mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
C++: make unresolve a member of ElementBase
Also remove the charpred of ElementBase. This gets rid of many redundant charpred checks. It means that incomplete classes from the db are now `Element`s, which is maybe noisy but should not be harmful. Together, these changes give a great reduction in DIL and should help the optimiser. It brings the DIL of `UncontrolledFormatString.ql` down from 43,908 lines to 35,400 lines.
This commit is contained in:
@@ -12,7 +12,12 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
*/
|
||||
class Class extends UserType {
|
||||
Class() {
|
||||
isClass(underlyingElement(this))
|
||||
isClass(this.underlying()) and
|
||||
this = resolveClass(_)
|
||||
}
|
||||
|
||||
override @element unresolve() {
|
||||
resolveClass(result) = this
|
||||
}
|
||||
|
||||
/** Gets a child declaration of this class. */
|
||||
|
||||
@@ -2,63 +2,75 @@ import semmle.code.cpp.Location
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* Get the `@element` that represents this `@element`.
|
||||
* Normally this will simply be `e`, but sometimes it is not.
|
||||
* For example, for an incomplete struct `e` the result may be a
|
||||
* complete struct with the same name.
|
||||
*/
|
||||
private cached @element resolveElement(@element e) {
|
||||
if isClass(e)
|
||||
then result = resolveClass(e)
|
||||
else result = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `Element` that represents this `@element`.
|
||||
* Normally this will simply be a cast of `e`, but sometimes it is not.
|
||||
* For example, for an incomplete struct `e` the result may be a
|
||||
* complete struct with the same name.
|
||||
*/
|
||||
pragma[inline]
|
||||
Element mkElement(@element e) {
|
||||
result = resolveElement(e)
|
||||
result.unresolve() = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an `@element` that resolves to the `Element`. This should
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets an `@element` that resolves to the `Element`. This should
|
||||
* normally only be called from member predicates, where `e` is not
|
||||
* `this` and you need the result for an argument to a database
|
||||
* extensional.
|
||||
* See `underlyingElement` for when `e` is `this`.
|
||||
*/
|
||||
pragma[inline]
|
||||
@element unresolveElement(Element e) {
|
||||
resolveElement(result) = e
|
||||
result = e.unresolve()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `@element` that this `Element` extends. This should normally
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets the `@element` that this `Element` extends. This should normally
|
||||
* only be called from member predicates, where `e` is `this` and you
|
||||
* need the result for an argument to a database extensional.
|
||||
* See `unresolveElement` for when `e` is not `this`.
|
||||
*/
|
||||
pragma[inline]
|
||||
@element underlyingElement(Element e) {
|
||||
result = e
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ element with no member predicates other than `toString`. Not for
|
||||
* A C/C++ element with a minimal set of member predicates. Not for
|
||||
* general use. This class does not define a location, so classes wanting to
|
||||
* change their location without affecting other classes can extend
|
||||
* `ElementBase` instead of `Element` to create a new rootdef for `getURL`,
|
||||
* `getLocation`, or `hasLocationInfo`.
|
||||
*/
|
||||
class ElementBase extends @element {
|
||||
ElementBase() {
|
||||
this = resolveElement(_)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets the `@element` that this `Element` extends. This should normally only
|
||||
* be called from member predicates on `this` where you need the result for
|
||||
* an argument to a database extensional.
|
||||
* See `unresolve` for when the qualifier is not `this`.
|
||||
*/
|
||||
final @element underlying() { result = this }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets an `@element` that resolves to the `Element`. This should normally
|
||||
* only be called from member predicates, where the qualifier is not `this`
|
||||
* and you need the result for an argument to a database extensional.
|
||||
* See `underlying` for when the qualifier is `this`.
|
||||
*/
|
||||
pragma[inline]
|
||||
@element unresolve() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -294,13 +294,13 @@ class AttributeArgument extends Element, @attribute_arg {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
if exists (@attribute_arg_empty self | mkElement(self) = this)
|
||||
if exists (@attribute_arg_empty self | self = underlyingElement(this))
|
||||
then result = "empty argument"
|
||||
else exists (string prefix, string tail
|
||||
| (if exists(getName())
|
||||
then prefix = getName() + "="
|
||||
else prefix = "") and
|
||||
(if exists (@attribute_arg_type self | mkElement(self) = this)
|
||||
(if exists (@attribute_arg_type self | self = underlyingElement(this))
|
||||
then tail = getValueType().getName()
|
||||
else tail = getValueText()) and
|
||||
result = prefix + tail)
|
||||
|
||||
@@ -633,12 +633,26 @@ class PointsToExpr extends Expr
|
||||
pragma[noopt]
|
||||
Element pointsTo()
|
||||
{
|
||||
this.interesting() and exists(int set, @element thisEntity, @element resultEntity | thisEntity = underlyingElement(this) and pointstosets(set, thisEntity) and setlocations(set, resultEntity) and resultEntity = unresolveElement(result))
|
||||
this.interesting() and
|
||||
exists(int set, @element thisEntity, @element resultEntity |
|
||||
thisEntity = this.underlying() and
|
||||
pointstosets(set, thisEntity) and
|
||||
setlocations(set, resultEntity) and
|
||||
resultEntity = localUnresolveElement(result)
|
||||
)
|
||||
}
|
||||
|
||||
float confidence() { result = 1.0 / count(this.pointsTo()) }
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used above in a `pragma[noopt]` context, which prevents its
|
||||
* customary inlining. We materialise it explicitly here.
|
||||
*/
|
||||
private @element localUnresolveElement(Element e) {
|
||||
result = unresolveElement(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if anything points to an element, that is, is equivalent to:
|
||||
* ```
|
||||
|
||||
Reference in New Issue
Block a user