mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
C++: Declaration.getIdentityString and Type.getTypeIdentityString
This PR adds new predicates to `Declaration` and `Type` to get a fully-qualified canonical name for the element, suitable for debugging and dumps. It includes template parameters, cv qualifiers, function parameter and return types, and fully-qualified names for all symbols. These strings are too large to compute in productions queries, so they should be used only for dumps and debugging. Feel free to suggest better names for these predicates. I've updated PrintAST and PrintIR to use these instead of `Function.getFullSignature()`. The biggest advantage of the new predicates is that they handle lambdas and local classes, which `getQualifiedName` and `getFullSignature` do not. This makes IR and AST dumps much more usable for real-world snapshots. Along the way, I cleaned up some of our handling of `IntegralType` to use a single table for tracking the signed, unsigned, and canonical versions of each type. The canonical part is new, and was necessary for `getTypeIdentityString` so that `signed int` and `int` both appear as `int`.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Specifier
|
||||
import semmle.code.cpp.Namespace
|
||||
private import semmle.code.cpp.internal.IdentityString
|
||||
|
||||
/**
|
||||
* A C/C++ declaration: for example, a variable declaration, a type
|
||||
@@ -88,6 +89,17 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
/**
|
||||
* Gets a string that uniquely identifies this declaration, suitable for use when debugging queries. Only holds for
|
||||
* functions, user-defined types, global and namespace-scope variables, and member variables.
|
||||
*
|
||||
* This operation is very expensive, and should not be used in production queries. Consider using `hasName()` or
|
||||
* `hasQualifiedName()` for identifying known declarations in production queries.
|
||||
*/
|
||||
string getIdentityString() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this declaration.
|
||||
*
|
||||
|
||||
@@ -5,6 +5,7 @@ import semmle.code.cpp.Parameter
|
||||
import semmle.code.cpp.exprs.Call
|
||||
import semmle.code.cpp.metrics.MetricFunction
|
||||
import semmle.code.cpp.Linkage
|
||||
private import semmle.code.cpp.internal.IdentityString
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
@@ -55,6 +56,48 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
)
|
||||
}
|
||||
|
||||
override string getIdentityString() {
|
||||
result = getType().getTypeSpecifier() + getType().getDeclaratorPrefix() + " " + getScopePrefix(this) + getName() + getTemplateArgumentsString() + getDeclaratorSuffixBeforeQualifiers() + getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getTemplateArgumentsString() {
|
||||
if exists(getATemplateArgument()) then (
|
||||
result = "<" +
|
||||
concat(int i |
|
||||
exists(getTemplateArgument(i)) |
|
||||
getTemplateArgument(i).getTypeIdentityString(), ", " order by i
|
||||
) + ">"
|
||||
)
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getDeclaratorSuffixBeforeQualifiers() {
|
||||
result = "(" +
|
||||
concat(int i |
|
||||
exists(getParameter(i).getType()) |
|
||||
getParameterTypeString(getParameter(i).getType()), ", " order by i
|
||||
) + ")" + getQualifierString()
|
||||
}
|
||||
|
||||
private string getQualifierString() {
|
||||
if exists(getACVQualifier()) then
|
||||
result = " " + concat(string qualifier | qualifier = getACVQualifier() | qualifier, " ")
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getACVQualifier() {
|
||||
result = getASpecifier().getName() and
|
||||
(result = "const" or result = "volatile")
|
||||
}
|
||||
|
||||
private string getDeclaratorSuffix() {
|
||||
result = getType().getDeclaratorSuffixBeforeQualifiers() + getType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
/** Gets a specifier of this function. */
|
||||
override Specifier getASpecifier() {
|
||||
funspecifiers(underlyingElement(this),unresolveElement(result))
|
||||
@@ -1088,8 +1131,14 @@ class TemplateFunction extends Function {
|
||||
* A function that is an instantiation of a template.
|
||||
*/
|
||||
class FunctionTemplateInstantiation extends Function {
|
||||
TemplateFunction tf;
|
||||
|
||||
FunctionTemplateInstantiation() {
|
||||
exists(TemplateFunction tf | tf.getAnInstantiation() = this)
|
||||
tf.getAnInstantiation() = this
|
||||
}
|
||||
|
||||
TemplateFunction getTemplate() {
|
||||
result = tf
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -490,7 +490,7 @@ class FunctionNode extends ASTNode {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = func.getFullSignature()
|
||||
result = func.getIdentityString()
|
||||
}
|
||||
|
||||
override PrintASTNode getChild(int childIndex) {
|
||||
@@ -528,7 +528,7 @@ class FunctionNode extends ASTNode {
|
||||
file,
|
||||
line,
|
||||
column,
|
||||
function.getFullSignature()
|
||||
function.getIdentityString()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Member
|
||||
import semmle.code.cpp.Function
|
||||
private import semmle.code.cpp.internal.IdentityString
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
@@ -144,6 +145,66 @@ class Type extends Locatable, @type {
|
||||
*/
|
||||
string explain() { result = "type" } // Concrete base impl to allow filters on Type
|
||||
|
||||
/**
|
||||
* Gets a string that uniquely identifies this type, suitable for use when debugging queries. All typedefs and
|
||||
* decltypes are expanded, and all symbol names are fully qualified.
|
||||
*
|
||||
* This operation is very expensive, and should not be used in production queries.
|
||||
*/
|
||||
final string getTypeIdentityString() {
|
||||
/*
|
||||
The identity string of a type is just the concatenation of the four components below. To create the type
|
||||
identity for a derived type, insert the declarator of the derived type between the `getDeclaratorPrefix()` and
|
||||
`getDeclaratorSuffixBeforeQualifiers()`. To create the type identity for a `SpecifiedType`, insert the qualifiers
|
||||
after `getDeclaratorSuffixBeforeQualifiers()`.
|
||||
*/
|
||||
result = getTypeSpecifier() + getDeclaratorPrefix() + getDeclaratorSuffixBeforeQualifiers() + getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "type specifier" part of this type's name. This is generally the "leaf" type from which the type was
|
||||
* constructed.
|
||||
*
|
||||
* Examples:
|
||||
* - `int` -> `int`
|
||||
* - `int*` -> `int`
|
||||
* - `int (*&)(float, double) const` -> `int`
|
||||
*
|
||||
* This predicate is intended to be used only by the implementation of `getTypeIdentityString`.
|
||||
*/
|
||||
string getTypeSpecifier() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portion of this type's declarator that comes before the declarator for any derived type.
|
||||
*
|
||||
* This predicate is intended to be used only by the implementation of `getTypeIdentityString`.
|
||||
*/
|
||||
string getDeclaratorPrefix() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portion of this type's declarator that comes after the declarator for any derived type, but before any
|
||||
* qualifiers on the current type.
|
||||
*
|
||||
* This predicate is intended to be used only by the implementation of `getTypeIdentityString`.
|
||||
*/
|
||||
string getDeclaratorSuffixBeforeQualifiers() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portion of this type's declarator that comes after the declarator for any derived type and after any
|
||||
* qualifiers on the current type.
|
||||
*
|
||||
* This predicate is intended to be used only by the implementation of `getTypeIdentityString`.
|
||||
*/
|
||||
string getDeclaratorSuffix() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type is constant and only contains constant types.
|
||||
* For instance, a `char *const` is a constant type, but not deeply constant,
|
||||
@@ -312,6 +373,10 @@ class BuiltInType extends Type, @builtintype {
|
||||
|
||||
override string explain() { result = this.getName() }
|
||||
|
||||
override string getTypeSpecifier() {
|
||||
result = toString()
|
||||
}
|
||||
|
||||
override predicate isDeeplyConstBelow() { any() } // No subparts
|
||||
}
|
||||
|
||||
@@ -348,6 +413,12 @@ class ArithmeticType extends BuiltInType {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate isIntegralType(@builtintype type, int kind) {
|
||||
isArithmeticType(type, kind) and
|
||||
(kind < 24 or kind = 33 or (35 <= kind and kind <= 37) or
|
||||
kind = 43 or kind = 44)
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ integral or enum type.
|
||||
* The definition of "integral type" in the C++ Standard excludes enum types,
|
||||
@@ -358,11 +429,8 @@ class ArithmeticType extends BuiltInType {
|
||||
class IntegralOrEnumType extends Type {
|
||||
IntegralOrEnumType() {
|
||||
// Integral type
|
||||
exists(int kind |
|
||||
isArithmeticType(underlyingElement(this), kind) and
|
||||
(kind < 24 or kind = 33 or (35 <= kind and kind <= 37) or
|
||||
kind = 43 or kind = 44)
|
||||
) or
|
||||
isIntegralType(underlyingElement(this), _)
|
||||
or
|
||||
// Enum type
|
||||
(
|
||||
usertypes(underlyingElement(this), _, 4) or
|
||||
@@ -371,10 +439,52 @@ class IntegralOrEnumType extends Type {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps between different integral types of the same size.
|
||||
*
|
||||
* original: The original type. Can be any integral type kind.
|
||||
* canonical: The canonical form of the type
|
||||
* - plain T -> T
|
||||
* - signed T -> T (except signed char -> signed char)
|
||||
* - unsigned T -> unsigned T
|
||||
* unsigned: The explicitly unsigned form of the type.
|
||||
* signed: The explicitly signed form of the type.
|
||||
*/
|
||||
private predicate integralTypeMapping(int original, int canonical, int unsigned, int signed) {
|
||||
original = 4 and canonical = 4 and unsigned = -1 and signed = -1 // bool
|
||||
or original = 5 and canonical = 5 and unsigned = 6 and signed = 7 // char
|
||||
or original = 6 and canonical = 6 and unsigned = 6 and signed = 7 // unsigned char
|
||||
or original = 7 and canonical = 7 and unsigned = 6 and signed = 7 // signed char
|
||||
or original = 8 and canonical = 8 and unsigned = 9 and signed = 10 // short
|
||||
or original = 9 and canonical = 9 and unsigned = 9 and signed = 10 // unsigned short
|
||||
or original = 10 and canonical = 8 and unsigned = 9 and signed = 10 // signed short
|
||||
or original = 11 and canonical = 11 and unsigned = 12 and signed = 13 // int
|
||||
or original = 12 and canonical = 12 and unsigned = 12 and signed = 13 // unsigned int
|
||||
or original = 13 and canonical = 11 and unsigned = 12 and signed = 13 // signed int
|
||||
or original = 14 and canonical = 14 and unsigned = 15 and signed = 16 // long
|
||||
or original = 15 and canonical = 15 and unsigned = 15 and signed = 16 // unsigned long
|
||||
or original = 16 and canonical = 14 and unsigned = 15 and signed = 16 // signed long
|
||||
or original = 17 and canonical = 17 and unsigned = 18 and signed = 19 // long long
|
||||
or original = 18 and canonical = 18 and unsigned = 18 and signed = 19 // unsigned long long
|
||||
or original = 19 and canonical = 17 and unsigned = 18 and signed = 19 // signed long long
|
||||
or original = 33 and canonical = 33 and unsigned = -1 and signed = -1 // wchar_t
|
||||
or original = 35 and canonical = 35 and unsigned = 36 and signed = 37 // __int128
|
||||
or original = 36 and canonical = 36 and unsigned = 36 and signed = 37 // unsigned __int128
|
||||
or original = 37 and canonical = 35 and unsigned = 36 and signed = 37 // signed __int128
|
||||
or original = 43 and canonical = 43 and unsigned = -1 and signed = -1 // char16_t
|
||||
or original = 44 and canonical = 44 and unsigned = -1 and signed = -1 // char32_t
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ integral types. See 4.1.1.
|
||||
*/
|
||||
class IntegralType extends ArithmeticType, IntegralOrEnumType {
|
||||
int kind;
|
||||
|
||||
IntegralType() {
|
||||
isIntegralType(underlyingElement(this), kind)
|
||||
}
|
||||
|
||||
/** Holds if this integral type is signed. */
|
||||
predicate isSigned() {
|
||||
builtintypes(underlyingElement(this),_,_,_,-1,_)
|
||||
@@ -411,12 +521,29 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
|
||||
* example on a `short`, this would give the type `unsigned short`.
|
||||
*/
|
||||
IntegralType getUnsigned() {
|
||||
(builtintypes(underlyingElement(this),_, 5,_,_,_) or builtintypes(underlyingElement(this),_, 6,_,_,_) or builtintypes(underlyingElement(this),_, 7,_,_,_)) and builtintypes(unresolveElement(result),_, 6,_,_,_)
|
||||
or (builtintypes(underlyingElement(this),_, 8,_,_,_) or builtintypes(underlyingElement(this),_, 9,_,_,_) or builtintypes(underlyingElement(this),_,10,_,_,_)) and builtintypes(unresolveElement(result),_, 9,_,_,_)
|
||||
or (builtintypes(underlyingElement(this),_,11,_,_,_) or builtintypes(underlyingElement(this),_,12,_,_,_) or builtintypes(underlyingElement(this),_,13,_,_,_)) and builtintypes(unresolveElement(result),_,12,_,_,_)
|
||||
or (builtintypes(underlyingElement(this),_,14,_,_,_) or builtintypes(underlyingElement(this),_,15,_,_,_) or builtintypes(underlyingElement(this),_,16,_,_,_)) and builtintypes(unresolveElement(result),_,15,_,_,_)
|
||||
or (builtintypes(underlyingElement(this),_,17,_,_,_) or builtintypes(underlyingElement(this),_,18,_,_,_) or builtintypes(underlyingElement(this),_,19,_,_,_)) and builtintypes(unresolveElement(result),_,18,_,_,_)
|
||||
or (builtintypes(underlyingElement(this),_,35,_,_,_) or builtintypes(underlyingElement(this),_,36,_,_,_) or builtintypes(underlyingElement(this),_,37,_,_,_)) and builtintypes(unresolveElement(result),_,36,_,_,_)
|
||||
exists(int unsignedKind |
|
||||
integralTypeMapping(kind, _, unsignedKind, _) and
|
||||
builtintypes(unresolveElement(result), _, unsignedKind, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the canonical type corresponding to this integral type.
|
||||
*
|
||||
* For a plain type, this gives the same type (e.g. `short` -> `short`).
|
||||
* For an explicitly unsigned type, this gives the same type (e.g. `unsigned short` -> `unsigned short`).
|
||||
* For an explicitly signed type, this gives the plain version of that type (e.g. `signed short` -> `short`), except
|
||||
* that `signed char` -> `signed char`.
|
||||
*/
|
||||
IntegralType getCanonical() {
|
||||
exists(int canonicalKind |
|
||||
integralTypeMapping(kind, canonicalKind, _, _) and
|
||||
builtintypes(unresolveElement(result), _, canonicalKind, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
override string getTypeSpecifier() {
|
||||
result = getCanonical().toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,6 +781,18 @@ class DerivedType extends Type, @derivedtype {
|
||||
|
||||
override string getName() { derivedtypes(underlyingElement(this),result,_,_) }
|
||||
|
||||
override string getTypeSpecifier() {
|
||||
result = getBaseType().getTypeSpecifier()
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffixBeforeQualifiers() {
|
||||
result = getBaseType().getDeclaratorSuffixBeforeQualifiers()
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffix() {
|
||||
result = getBaseType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base type of this derived type.
|
||||
*
|
||||
@@ -754,6 +893,18 @@ class Decltype extends Type, @decltype {
|
||||
result = "decltype(...)"
|
||||
}
|
||||
|
||||
override string getTypeSpecifier() {
|
||||
result = getBaseType().getTypeSpecifier()
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
result = getBaseType().getDeclaratorPrefix()
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffix() {
|
||||
result = getBaseType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
none()
|
||||
}
|
||||
@@ -795,10 +946,38 @@ class Decltype extends Type, @decltype {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ pointer or reference type.
|
||||
*/
|
||||
class PointerIshType extends DerivedType {
|
||||
PointerIshType() {
|
||||
derivedtypes(underlyingElement(this), _, 1, _) or
|
||||
derivedtypes(underlyingElement(this), _, 2, _) or
|
||||
derivedtypes(underlyingElement(this), _, 8, _)
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
exists(string declarator |
|
||||
result = getBaseType().getDeclaratorPrefix() + declarator and
|
||||
if getBaseType().getUnspecifiedType() instanceof ArrayType then
|
||||
declarator = "(" + getDeclaratorToken() + ")"
|
||||
else
|
||||
declarator = getDeclaratorToken()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token used when declaring this kind of type (e.g. `*`, `&`, `&&`)/
|
||||
*/
|
||||
string getDeclaratorToken() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ pointer type. See 4.9.1.
|
||||
*/
|
||||
class PointerType extends DerivedType {
|
||||
class PointerType extends PointerIshType {
|
||||
|
||||
PointerType() { derivedtypes(underlyingElement(this),_,1,_) }
|
||||
|
||||
@@ -808,6 +987,10 @@ class PointerType extends DerivedType {
|
||||
|
||||
override string explain() { result = "pointer to {" + this.getBaseType().explain() + "}" }
|
||||
|
||||
override string getDeclaratorToken() {
|
||||
result = "*"
|
||||
}
|
||||
|
||||
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() }
|
||||
|
||||
override Type resolveTypedefs() {
|
||||
@@ -821,7 +1004,7 @@ class PointerType extends DerivedType {
|
||||
* For C++11 code bases, this includes both lvalue references (&) and rvalue references (&&).
|
||||
* To distinguish between them, use the LValueReferenceType and RValueReferenceType classes.
|
||||
*/
|
||||
class ReferenceType extends DerivedType {
|
||||
class ReferenceType extends PointerIshType {
|
||||
|
||||
ReferenceType() { derivedtypes(underlyingElement(this),_,2,_) or derivedtypes(underlyingElement(this),_,8,_) }
|
||||
|
||||
@@ -849,6 +1032,10 @@ class ReferenceType extends DerivedType {
|
||||
*/
|
||||
class LValueReferenceType extends ReferenceType {
|
||||
LValueReferenceType() { derivedtypes(underlyingElement(this),_,2,_) }
|
||||
|
||||
override string getDeclaratorToken() {
|
||||
result = "&"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -858,6 +1045,10 @@ class RValueReferenceType extends ReferenceType {
|
||||
RValueReferenceType() { derivedtypes(underlyingElement(this),_,8,_) }
|
||||
|
||||
override string explain() { result = "rvalue " + super.explain() }
|
||||
|
||||
override string getDeclaratorToken() {
|
||||
result = "&&"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -884,6 +1075,30 @@ class SpecifiedType extends DerivedType {
|
||||
|
||||
override string explain() { result = this.getSpecifierString() + "{" + this.getBaseType().explain() + "}" }
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
exists(string basePrefix |
|
||||
basePrefix = getBaseType().getDeclaratorPrefix() and
|
||||
if getBaseType().getUnspecifiedType() instanceof RoutineType then
|
||||
result = basePrefix
|
||||
else
|
||||
result = basePrefix + " " + getSpecifierString().trim()
|
||||
)
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffixBeforeQualifiers() {
|
||||
exists(string baseSuffix |
|
||||
baseSuffix = getBaseType().getDeclaratorSuffixBeforeQualifiers() and
|
||||
if getBaseType().getUnspecifiedType() instanceof RoutineType then
|
||||
result = baseSuffix + " " + getSpecifierString().trim()
|
||||
else
|
||||
result = baseSuffix
|
||||
)
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffix() {
|
||||
result = getBaseType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
override predicate isDeeplyConst() { this.getASpecifier().getName() = "const" and this.getBaseType().isDeeplyConstBelow() }
|
||||
|
||||
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() }
|
||||
@@ -941,6 +1156,17 @@ class ArrayType extends DerivedType {
|
||||
result = "array of {" + this.getBaseType().explain() + "}"
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
result = getBaseType().getDeclaratorPrefix()
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffixBeforeQualifiers() {
|
||||
if exists(getArraySize()) then
|
||||
result = "[" + getArraySize().toString() + "]" + getBaseType().getDeclaratorSuffixBeforeQualifiers()
|
||||
else
|
||||
result = "[]" + getBaseType().getDeclaratorSuffixBeforeQualifiers()
|
||||
}
|
||||
|
||||
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() } // No such thing as a const array type
|
||||
|
||||
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() }
|
||||
@@ -1002,6 +1228,10 @@ class FunctionPointerType extends FunctionPointerIshType {
|
||||
}
|
||||
|
||||
override string explain() { result = "pointer to {" + this.getBaseType().(RoutineType).explain() + "}" }
|
||||
|
||||
override string getDeclaratorToken() {
|
||||
result = "*"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1017,6 +1247,10 @@ class FunctionReferenceType extends FunctionPointerIshType {
|
||||
}
|
||||
|
||||
override string explain() { result = "reference to {" + this.getBaseType().(RoutineType).explain() + "}" }
|
||||
|
||||
override string getDeclaratorToken() {
|
||||
result = "&"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1035,6 +1269,10 @@ class BlockType extends FunctionPointerIshType {
|
||||
}
|
||||
|
||||
override string explain() { result = "block of {" + this.getBaseType().(RoutineType).explain() + "}" }
|
||||
|
||||
override string getDeclaratorToken() {
|
||||
result = "^"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1047,6 +1285,25 @@ class FunctionPointerIshType extends DerivedType {
|
||||
derivedtypes(underlyingElement(this),_,10,_)
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffixBeforeQualifiers() {
|
||||
result = ")" + getBaseType().getDeclaratorSuffixBeforeQualifiers()
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffix() {
|
||||
result = getBaseType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
result = getBaseType().getDeclaratorPrefix() + "(" + getDeclaratorToken()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token used when declaring this kind of type (e.g. `*`, `&`, `^`)/
|
||||
*/
|
||||
string getDeclaratorToken() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/** the return type of this function pointer type */
|
||||
Type getReturnType() {
|
||||
exists(RoutineType t | derivedtypes(underlyingElement(this),_,_,unresolveElement(t)) and result = t.getReturnType())
|
||||
@@ -1102,6 +1359,36 @@ class PointerToMemberType extends Type, @ptrtomember {
|
||||
|
||||
override string explain() { result = "pointer to member of " + this.getClass().toString() + " with type {" + this.getBaseType().explain() + "}" }
|
||||
|
||||
override string getTypeSpecifier() {
|
||||
result = getBaseType().getTypeSpecifier()
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
exists(string declarator, string parenDeclarator, Type baseType |
|
||||
declarator = getClass().getTypeIdentityString() + "::*" and
|
||||
result = getBaseType().getDeclaratorPrefix() + " " + parenDeclarator and
|
||||
baseType = getBaseType().getUnspecifiedType() and
|
||||
if (baseType instanceof ArrayType) or (baseType instanceof RoutineType) then
|
||||
parenDeclarator = "(" + declarator
|
||||
else
|
||||
parenDeclarator = declarator
|
||||
)
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffixBeforeQualifiers() {
|
||||
exists(Type baseType |
|
||||
baseType = getBaseType().getUnspecifiedType() and
|
||||
if (baseType instanceof ArrayType) or (baseType instanceof RoutineType) then
|
||||
result = ")" + getBaseType().getDeclaratorSuffixBeforeQualifiers()
|
||||
else
|
||||
result = getBaseType().getDeclaratorSuffixBeforeQualifiers()
|
||||
)
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffix() {
|
||||
result = getBaseType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
override predicate involvesTemplateParameter() {
|
||||
getBaseType().involvesTemplateParameter()
|
||||
}
|
||||
@@ -1129,6 +1416,27 @@ class RoutineType extends Type, @routinetype {
|
||||
"} with arguments (" + this.explainParameters(0) + ")"
|
||||
}
|
||||
|
||||
override string getTypeSpecifier() {
|
||||
result = getReturnType().getTypeSpecifier()
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
result = getReturnType().getDeclaratorPrefix()
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
override string getDeclaratorSuffixBeforeQualifiers() {
|
||||
result = "(" +
|
||||
concat(int i |
|
||||
exists(getParameterType(i)) |
|
||||
getParameterTypeString(getParameterType(i)), ", " order by i
|
||||
) + ")"
|
||||
}
|
||||
|
||||
override string getDeclaratorSuffix() {
|
||||
result = getReturnType().getDeclaratorSuffixBeforeQualifiers() + getReturnType().getDeclaratorSuffix()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string with the `explain()` values for the parameters of
|
||||
* this function, for instance "int,int".
|
||||
|
||||
@@ -2,6 +2,7 @@ import semmle.code.cpp.Declaration
|
||||
import semmle.code.cpp.Type
|
||||
import semmle.code.cpp.Member
|
||||
import semmle.code.cpp.Function
|
||||
private import semmle.code.cpp.internal.IdentityString
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
@@ -91,6 +92,35 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
|
||||
|
||||
override string explain() { result = this.getName() }
|
||||
|
||||
override string getIdentityString() {
|
||||
exists(string simpleName |
|
||||
(
|
||||
if this instanceof Closure then
|
||||
simpleName = "(" + getSimpleName() + ")"
|
||||
else
|
||||
simpleName = getSimpleName()
|
||||
) and
|
||||
result = getScopePrefix(this) + simpleName + getTemplateArgumentsString()
|
||||
)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getTemplateArgumentsString() {
|
||||
if exists(this.(Class).getATemplateArgument()) then (
|
||||
result = "<" +
|
||||
concat(int i |
|
||||
exists(this.(Class).getTemplateArgument(i)) |
|
||||
this.(Class).getTemplateArgument(i).getTypeIdentityString(), ", " order by i
|
||||
) + ">"
|
||||
)
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
override string getDeclaratorPrefix() {
|
||||
result = getIdentityString()
|
||||
}
|
||||
|
||||
// further overridden in LocalClass
|
||||
override AccessHolder getEnclosingAccessHolder() {
|
||||
result = this.getDeclaringType()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.exprs.Access
|
||||
import semmle.code.cpp.Initializer
|
||||
private import semmle.code.cpp.internal.IdentityString
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
@@ -75,6 +76,27 @@ class Variable extends Declaration, @variable {
|
||||
*/
|
||||
predicate declaredUsingAutoType() { autoderivation(underlyingElement(this), _) }
|
||||
|
||||
override string getIdentityString() {
|
||||
exists(Type type |
|
||||
(this instanceof MemberVariable or this instanceof GlobalOrNamespaceVariable) and
|
||||
type = this.getType() and
|
||||
result = type.getTypeSpecifier() + type.getDeclaratorPrefix() + " " + getScopePrefix(this) + this.getName() + this.getTemplateArgumentsString() + type.getDeclaratorSuffixBeforeQualifiers() + type.getDeclaratorSuffix()
|
||||
)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getTemplateArgumentsString() {
|
||||
if exists(getATemplateArgument()) then (
|
||||
result = "<" +
|
||||
concat(int i |
|
||||
exists(getTemplateArgument(i)) |
|
||||
getTemplateArgument(i).getTypeIdentityString(), ", " order by i
|
||||
) + ">"
|
||||
)
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
override VariableDeclarationEntry getADeclarationEntry() {
|
||||
result.getDeclaration() = this
|
||||
}
|
||||
|
||||
33
cpp/ql/src/semmle/code/cpp/internal/IdentityString.qll
Normal file
33
cpp/ql/src/semmle/code/cpp/internal/IdentityString.qll
Normal file
@@ -0,0 +1,33 @@
|
||||
import semmle.code.cpp.Declaration
|
||||
import semmle.code.cpp.Type
|
||||
|
||||
/**
|
||||
* Gets a string containing the scope in which this declaration is declared.
|
||||
*/
|
||||
string getScopePrefix(Declaration decl) {
|
||||
decl.isMember() and result = decl.getDeclaringType().getIdentityString() + "::" or
|
||||
(
|
||||
decl.isTopLevel() and
|
||||
exists (string parentName |
|
||||
parentName = decl.getNamespace().getQualifiedName() and
|
||||
(
|
||||
parentName != "" and result = parentName + "::" or
|
||||
parentName = "" and result = ""
|
||||
)
|
||||
)
|
||||
) or
|
||||
exists(UserType type |
|
||||
type = decl and type.isLocal() and result = "(" + type.getEnclosingFunction().getIdentityString() + ")::"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identity string of a type used as a parameter. Identical to `Type.getTypeIdentityString()`, except that
|
||||
* it returns `...` for `UnknownType`, which is used to represent variable arguments.
|
||||
*/
|
||||
string getParameterTypeString(Type parameterType) {
|
||||
if parameterType instanceof UnknownType then
|
||||
result = "..."
|
||||
else
|
||||
result = parameterType.getTypeIdentityString()
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = funcIR.getFunction().getFullSignature()
|
||||
result = funcIR.getFunction().getIdentityString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
|
||||
@@ -130,7 +130,7 @@ class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = funcIR.getFunction().getFullSignature()
|
||||
result = funcIR.getFunction().getIdentityString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
|
||||
@@ -130,7 +130,7 @@ class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = funcIR.getFunction().getFullSignature()
|
||||
result = funcIR.getFunction().getIdentityString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
|
||||
Reference in New Issue
Block a user