mirror of
https://github.com/github/codeql.git
synced 2025-12-23 12:16:33 +01:00
Packaging: Refactor the cpp libraries
This PR separates the core cpp packs into `codeql/cpp-queries` and `codeql/cpp-all`. There are very few lines of code changed. Almost all changes are moving files around.
This commit is contained in:
469
cpp/ql/lib/semmle/code/cpp/exprs/Access.qll
Normal file
469
cpp/ql/lib/semmle/code/cpp/exprs/Access.qll
Normal file
@@ -0,0 +1,469 @@
|
||||
/**
|
||||
* Provides classes for modeling accesses including variable accesses, enum
|
||||
* constant accesses and function accesses.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Variable
|
||||
import semmle.code.cpp.Enum
|
||||
private import semmle.code.cpp.dataflow.EscapesTree
|
||||
|
||||
/**
|
||||
* A C/C++ access expression. This refers to a function, variable, or enum constant.
|
||||
*/
|
||||
class Access extends Expr, NameQualifiableElement, @access {
|
||||
// As `@access` is a union type containing `@routineexpr` (which describes function accesses
|
||||
// that are called), we need to exclude function calls.
|
||||
Access() { this instanceof @routineexpr implies not iscall(underlyingElement(this), _) }
|
||||
|
||||
/** Gets the accessed function, variable, or enum constant. */
|
||||
Declaration getTarget() { none() } // overridden in subclasses
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `enum` constant access expression. For example the access to
|
||||
* `MYENUMCONST1` in `myFunction` in the following code:
|
||||
* ```
|
||||
* enum MyEnum {
|
||||
* MYENUMCONST1,
|
||||
* MYENUMCONST2
|
||||
* };
|
||||
*
|
||||
* void myFunction() {
|
||||
* MyEnum v = MYENUMCONST1;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class EnumConstantAccess extends Access, @varaccess {
|
||||
override string getAPrimaryQlClass() { result = "EnumConstantAccess" }
|
||||
|
||||
EnumConstantAccess() {
|
||||
exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
|
||||
}
|
||||
|
||||
/** Gets the accessed `enum` constant. */
|
||||
override EnumConstant getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/** Gets a textual representation of this `enum` constant access. */
|
||||
override string toString() { result = this.getTarget().getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ variable access expression. For example the accesses to
|
||||
* `x` and `y` in `myFunction` in the following code:
|
||||
* ```
|
||||
* int x;
|
||||
*
|
||||
* void myFunction(int y) {
|
||||
* x = y;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class VariableAccess extends Access, @varaccess {
|
||||
override string getAPrimaryQlClass() { result = "VariableAccess" }
|
||||
|
||||
VariableAccess() {
|
||||
not exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
|
||||
}
|
||||
|
||||
/** Gets the accessed variable. */
|
||||
override Variable getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Holds if this variable access is providing an LValue in a meaningful way.
|
||||
* For example, this includes accesses on the left-hand side of an assignment.
|
||||
* It does not include accesses on the right-hand side of an assignment, even if they could appear on the left-hand side of some assignment.
|
||||
*/
|
||||
predicate isUsedAsLValue() {
|
||||
exists(Assignment a | a.getLValue() = this) or
|
||||
exists(CrementOperation c | c.getOperand() = this) or
|
||||
exists(AddressOfExpr addof | addof.getOperand() = this) or
|
||||
exists(ReferenceToExpr rte | this.getConversion() = rte) or
|
||||
exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this variable access is in a position where it is (directly) modified,
|
||||
* for instance by an assignment or increment/decrement operator.
|
||||
*/
|
||||
predicate isModified() {
|
||||
exists(Assignment a | a.getLValue() = this)
|
||||
or
|
||||
exists(CrementOperation c | c.getOperand() = this)
|
||||
or
|
||||
exists(FunctionCall c | c.getQualifier() = this and c.getTarget().hasName("operator="))
|
||||
}
|
||||
|
||||
/** Holds if this variable access is an rvalue. */
|
||||
predicate isRValue() {
|
||||
not exists(AssignExpr ae | ae.getLValue() = this) and
|
||||
not exists(AddressOfExpr addof | addof.getOperand() = this) and
|
||||
not exists(ReferenceToExpr rte | this.getConversion() = rte) and
|
||||
not exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression generating the variable being accessed.
|
||||
*
|
||||
* As a few examples:
|
||||
* For `ptr->x`, this gives `ptr`.
|
||||
* For `(*ptr).x`, this gives `(*ptr)`.
|
||||
* For `smart_ptr->x`, this gives the call to `operator->`.
|
||||
*
|
||||
* This applies mostly to FieldAccesses, but also to static member variables accessed
|
||||
* "through" a pointer. Note that it does NOT apply to static member variables accessed
|
||||
* through a type name, as in that case the type name is a qualifier on the variable
|
||||
* rather than a qualifier on the access.
|
||||
*/
|
||||
Expr getQualifier() { this.getChild(-1) = result }
|
||||
|
||||
/** Gets a textual representation of this variable access. */
|
||||
override string toString() {
|
||||
if exists(this.getTarget())
|
||||
then result = this.getTarget().getName()
|
||||
else result = "variable access"
|
||||
}
|
||||
|
||||
override predicate mayBeImpure() {
|
||||
this.getQualifier().mayBeImpure() or
|
||||
this.getTarget().getType().isVolatile()
|
||||
}
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
this.getQualifier().mayBeGloballyImpure() or
|
||||
this.getTarget().getType().isVolatile()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this access is used to get the address of the underlying variable
|
||||
* in such a way that the address might escape. This can be either explicit,
|
||||
* for example `&x`, or implicit, for example `T& y = x`.
|
||||
*/
|
||||
predicate isAddressOfAccess() { variableAddressEscapesTree(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if this access is used to get the address of the underlying variable
|
||||
* in such a way that the address might escape as a pointer or reference to
|
||||
* non-const data. This can be either explicit, for example `&x`, or
|
||||
* implicit, for example `T& y = x`.
|
||||
*/
|
||||
predicate isAddressOfAccessNonConst() { variableAddressEscapesTreeNonConst(this, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ field access expression. For example the accesses to
|
||||
* `x` and `y` in `myMethod` in the following code:
|
||||
* ```
|
||||
* class MyClass {
|
||||
* public:
|
||||
* void myMethod(MyClass &other) {
|
||||
* x = other.y;
|
||||
* }
|
||||
*
|
||||
* int x, y;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class FieldAccess extends VariableAccess {
|
||||
override string getAPrimaryQlClass() { result = "FieldAccess" }
|
||||
|
||||
FieldAccess() { exists(Field f | varbind(underlyingElement(this), unresolveElement(f))) }
|
||||
|
||||
/** Gets the accessed field. */
|
||||
override Field getTarget() { result = super.getTarget() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access whose qualifier is a pointer to a class, struct or union.
|
||||
* These typically take the form `obj->field`. Another case is a field access
|
||||
* with an implicit `this->` qualifier, which is often a `PointerFieldAccess`
|
||||
* (but see also `ImplicitThisFieldAccess`).
|
||||
*
|
||||
* For example the accesses to `x` and `y` in `myMethod` in the following code
|
||||
* are each a `PointerFieldAccess`:
|
||||
* ```
|
||||
* class MyClass {
|
||||
* public:
|
||||
* void myMethod(MyClass *other) {
|
||||
* other->x = y;
|
||||
* }
|
||||
*
|
||||
* int x, y;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class PointerFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "PointerFieldAccess" }
|
||||
|
||||
PointerFieldAccess() {
|
||||
exists(PointerType t |
|
||||
t = getQualifier().getFullyConverted().getUnspecifiedType() and
|
||||
t.getBaseType() instanceof Class
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access of the form `obj.field`. The type of `obj` is either a
|
||||
* class/struct/union or a reference to one. `DotFieldAccess` has two
|
||||
* sub-classes, `ValueFieldAccess` and `ReferenceFieldAccess`, to
|
||||
* distinguish whether or not the type of `obj` is a reference type.
|
||||
*/
|
||||
class DotFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "DotFieldAccess" }
|
||||
|
||||
DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access of the form `obj.field`, where the type of `obj` is a
|
||||
* reference to a class/struct/union. For example the accesses to `y` in
|
||||
* `myMethod` in the following code:
|
||||
* ```
|
||||
* class MyClass {
|
||||
* public:
|
||||
* void myMethod(MyClass a, MyClass &b) {
|
||||
* a.x = b.y;
|
||||
* }
|
||||
*
|
||||
* int x, y;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ReferenceFieldAccess extends DotFieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "ReferenceFieldAccess" }
|
||||
|
||||
ReferenceFieldAccess() { exprHasReferenceConversion(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access of the form `obj.field`, where the type of `obj` is a
|
||||
* class/struct/union (and not a reference). For example the accesses to `x`
|
||||
* in `myMethod` in the following code:
|
||||
* ```
|
||||
* class MyClass {
|
||||
* public:
|
||||
* void myMethod(MyClass a, MyClass &b) {
|
||||
* a.x = b.y;
|
||||
* }
|
||||
*
|
||||
* int x, y;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ValueFieldAccess extends DotFieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "ValueFieldAccess" }
|
||||
|
||||
ValueFieldAccess() { not exprHasReferenceConversion(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `c` is a conversion from type `T&` to `T` (or from `T&&` to
|
||||
* `T`).
|
||||
*/
|
||||
private predicate referenceConversion(Conversion c) {
|
||||
c.getType() = c.getExpr().getType().(ReferenceType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is a reference expression (that is, it has a type of the
|
||||
* form `T&`), which is converted to a value. For example:
|
||||
* ```
|
||||
* int myfcn(MyStruct &x) {
|
||||
* return x.field;
|
||||
* }
|
||||
* ```
|
||||
* In this example, the type of `x` is `MyStruct&`, but it gets implicitly
|
||||
* converted to `MyStruct` in the expression `x.field`.
|
||||
*/
|
||||
private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.getConversion+()) }
|
||||
|
||||
/**
|
||||
* A field access of a field of `this` which has no qualifier because
|
||||
* the use of `this` is implicit. For example, in the following code the
|
||||
* implicit call to the destructor of `A` has no qualifier because the
|
||||
* use of `this` is implicit:
|
||||
* ```
|
||||
* class A {
|
||||
* public:
|
||||
* ~A() {
|
||||
* // ...
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* class B {
|
||||
* public:
|
||||
* A a;
|
||||
*
|
||||
* ~B() {
|
||||
* // Implicit call to the destructor of `A`.
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
* Note: the C++ front-end often automatically desugars `field` to
|
||||
* `this->field`, so most accesses of `this->field` are instances
|
||||
* of `PointerFieldAccess` (with `ThisExpr` as the qualifier), not
|
||||
* `ImplicitThisFieldAccess`.
|
||||
*/
|
||||
class ImplicitThisFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "ImplicitThisFieldAccess" }
|
||||
|
||||
ImplicitThisFieldAccess() { not exists(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ _pointer to non-static data member_ literal. For example, `&C::x` is
|
||||
* an expression that refers to field `x` of class `C`. If the type of that
|
||||
* field is `int`, then `&C::x` ought to have type `int C::*`. It is currently
|
||||
* modeled in QL as having type `int`.
|
||||
*
|
||||
* See [dcl.mptr] in the C++17 standard or see
|
||||
* https://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members.
|
||||
*/
|
||||
class PointerToFieldLiteral extends ImplicitThisFieldAccess {
|
||||
PointerToFieldLiteral() {
|
||||
// The extractor currently emits a pointer-to-field literal as a field
|
||||
// access without a qualifier. The only other unqualified field accesses it
|
||||
// emits are for compiler-generated constructors and destructors. When we
|
||||
// filter those out, there are only pointer-to-field literals left.
|
||||
not this.isCompilerGenerated()
|
||||
}
|
||||
|
||||
override predicate isConstant() { any() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerToFieldLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ function access expression. For example the access to
|
||||
* `myFunctionTarget` in `myFunction` in the following code:
|
||||
* ```
|
||||
* int myFunctionTarget(int);
|
||||
*
|
||||
* void myFunction() {
|
||||
* int (*myFunctionPointer)(int) = &myFunctionTarget;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class FunctionAccess extends Access, @routineexpr {
|
||||
FunctionAccess() { not iscall(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionAccess" }
|
||||
|
||||
/** Gets the accessed function. */
|
||||
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/** Gets a textual representation of this function access. */
|
||||
override string toString() {
|
||||
if exists(this.getTarget())
|
||||
then result = this.getTarget().getName()
|
||||
else result = "function access"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to a parameter of a function signature for the purposes of a `decltype`.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```
|
||||
* template <typename L, typename R>
|
||||
* auto add(L lhs, R rhs) -> decltype(lhs + rhs) {
|
||||
* return lhs + rhs;
|
||||
* }
|
||||
* ```
|
||||
* The return type of the function is a decltype, the expression of which contains
|
||||
* an add expression, which in turn has two `ParamAccessForType` children.
|
||||
*/
|
||||
class ParamAccessForType extends Expr, @param_ref {
|
||||
override string toString() { result = "param access" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to a type. This occurs in certain contexts where a built-in
|
||||
* works on types directly rather than variables, expressions etc. For
|
||||
* example the reference to `MyClass` in `__is_pod` in the following code:
|
||||
* ```
|
||||
* class MyClass {
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* void myFunction() {
|
||||
* if (__is_pod(MyClass))
|
||||
* {
|
||||
* ...
|
||||
* } else {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class TypeName extends Expr, @type_operand {
|
||||
override string getAPrimaryQlClass() { result = "TypeName" }
|
||||
|
||||
override string toString() { result = this.getType().getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ array access expression. For example, the access to `as` in
|
||||
* `myFunction` in the following code:
|
||||
* ```
|
||||
* int as[10];
|
||||
*
|
||||
* void myFunction() {
|
||||
* as[0]++;
|
||||
* }
|
||||
* ```
|
||||
* For calls to `operator[]`, which look syntactically identical, see
|
||||
* `OverloadedArrayExpr`.
|
||||
*/
|
||||
class ArrayExpr extends Expr, @subscriptexpr {
|
||||
override string getAPrimaryQlClass() { result = "ArrayExpr" }
|
||||
|
||||
/**
|
||||
* Gets the array or pointer expression being subscripted.
|
||||
*
|
||||
* This is `arr` in both `arr[0]` and `0[arr]`.
|
||||
*/
|
||||
Expr getArrayBase() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the expression giving the index into the array.
|
||||
*
|
||||
* This is `0` in both `arr[0]` and `0[arr]`.
|
||||
*/
|
||||
Expr getArrayOffset() { result = this.getChild(1) }
|
||||
|
||||
/**
|
||||
* Holds if this array access is in a position where it is (directly) modified,
|
||||
* for instance by an assignment or an increment/decrement operation.
|
||||
*/
|
||||
predicate isModified() {
|
||||
exists(Assignment a | a.getLValue() = this)
|
||||
or
|
||||
exists(CrementOperation c | c.getOperand() = this)
|
||||
or
|
||||
exists(FunctionCall c | c.getQualifier() = this and c.getTarget().hasName("operator="))
|
||||
}
|
||||
|
||||
override string toString() { result = "access to array" }
|
||||
|
||||
override predicate mayBeImpure() {
|
||||
this.getArrayBase().mayBeImpure() or
|
||||
this.getArrayOffset().mayBeImpure() or
|
||||
this.getArrayBase().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile() or
|
||||
this.getArrayOffset().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile()
|
||||
}
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
this.getArrayBase().mayBeGloballyImpure() or
|
||||
this.getArrayOffset().mayBeGloballyImpure() or
|
||||
this.getArrayBase().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile() or
|
||||
this.getArrayOffset().getFullyConverted().getType().(DerivedType).getBaseType().isVolatile()
|
||||
}
|
||||
}
|
||||
455
cpp/ql/lib/semmle/code/cpp/exprs/ArithmeticOperation.qll
Normal file
455
cpp/ql/lib/semmle/code/cpp/exprs/ArithmeticOperation.qll
Normal file
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* Provides classes for modeling arithmetic operations such as `+`, `-`, `*`
|
||||
* and `++`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ unary arithmetic operation.
|
||||
*/
|
||||
class UnaryArithmeticOperation extends UnaryOperation, @un_arith_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ unary minus expression.
|
||||
* ```
|
||||
* b = - a;
|
||||
* ```
|
||||
*/
|
||||
class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnaryMinusExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ unary plus expression.
|
||||
* ```
|
||||
* b = + a;
|
||||
* ```
|
||||
*/
|
||||
class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnaryPlusExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ GNU conjugation expression. It operates on `_Complex` or
|
||||
* `__complex__ `numbers, and is similar to the C99 `conj`, `conjf` and `conjl`
|
||||
* functions.
|
||||
* ```
|
||||
* _Complex double a = ( 1.0, 2.0 );
|
||||
* _Complex double b = ~ a; // ( 1.0, - 2.0 )
|
||||
* ```
|
||||
*/
|
||||
class ConjugationExpr extends UnaryArithmeticOperation, @conjugation {
|
||||
override string getOperator() { result = "~" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConjugationExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `++` or `--` expression (either prefix or postfix).
|
||||
*
|
||||
* This is the base QL class for increment and decrement operations.
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator++`
|
||||
* or `operator--`.
|
||||
*/
|
||||
class CrementOperation extends UnaryArithmeticOperation, @crement_expr {
|
||||
override predicate mayBeImpure() { any() }
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
not exists(VariableAccess va, StackVariable v |
|
||||
va = this.getOperand() and
|
||||
v = va.getTarget() and
|
||||
not va.getConversion+() instanceof ReferenceDereferenceExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `++` expression (either prefix or postfix).
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator++`.
|
||||
*/
|
||||
class IncrementOperation extends CrementOperation, @increment_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ `--` expression (either prefix or postfix).
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator--`.
|
||||
*/
|
||||
class DecrementOperation extends CrementOperation, @decrement_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ `++` or `--` prefix expression.
|
||||
*
|
||||
* Note that this does not include calls to user-defined operators.
|
||||
*/
|
||||
class PrefixCrementOperation extends CrementOperation, @prefix_crement_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ `++` or `--` postfix expression.
|
||||
*
|
||||
* Note that this does not include calls to user-defined operators.
|
||||
*/
|
||||
class PostfixCrementOperation extends CrementOperation, @postfix_crement_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ prefix increment expression, as in `++x`.
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator++`.
|
||||
* ```
|
||||
* b = ++a;
|
||||
* ```
|
||||
*/
|
||||
class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preincrexpr {
|
||||
override string getOperator() { result = "++" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PrefixIncrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ prefix decrement expression, as in `--x`.
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator--`.
|
||||
* ```
|
||||
* b = --a;
|
||||
* ```
|
||||
*/
|
||||
class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predecrexpr {
|
||||
override string getOperator() { result = "--" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PrefixDecrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ postfix increment expression, as in `x++`.
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator++`.
|
||||
* ```
|
||||
* b = a++;
|
||||
* ```
|
||||
*/
|
||||
class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @postincrexpr {
|
||||
override string getOperator() { result = "++" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PostfixIncrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
override string toString() { result = "... " + getOperator() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ postfix decrement expression, as in `x--`.
|
||||
*
|
||||
* Note that this does not include calls to user-defined `operator--`.
|
||||
* ```
|
||||
* b = a--;
|
||||
* ```
|
||||
*/
|
||||
class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @postdecrexpr {
|
||||
override string getOperator() { result = "--" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PostfixDecrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
override string toString() { result = "... " + getOperator() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ GNU real part expression. It operates on `_Complex` or
|
||||
* `__complex__` numbers.
|
||||
* ```
|
||||
* _Complex double f = { 2.0, 3.0 };
|
||||
* double d = __real(f); // 2.0
|
||||
* ```
|
||||
*/
|
||||
class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr {
|
||||
override string getOperator() { result = "__real" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RealPartExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ GNU imaginary part expression. It operates on `_Complex` or
|
||||
* `__complex__` numbers.
|
||||
* ```
|
||||
* _Complex double f = { 2.0, 3.0 };
|
||||
* double d = __imag(f); // 3.0
|
||||
* ```
|
||||
*/
|
||||
class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr {
|
||||
override string getOperator() { result = "__imag" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryPartExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ binary arithmetic operation.
|
||||
*
|
||||
* This is an abstract base QL class for all binary arithmetic operations.
|
||||
*/
|
||||
class BinaryArithmeticOperation extends BinaryOperation, @bin_arith_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ add expression.
|
||||
* ```
|
||||
* c = a + b;
|
||||
* ```
|
||||
*/
|
||||
class AddExpr extends BinaryArithmeticOperation, @addexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ subtract expression.
|
||||
* ```
|
||||
* c = a - b;
|
||||
* ```
|
||||
*/
|
||||
class SubExpr extends BinaryArithmeticOperation, @subexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ multiply expression.
|
||||
* ```
|
||||
* c = a * b;
|
||||
* ```
|
||||
*/
|
||||
class MulExpr extends BinaryArithmeticOperation, @mulexpr {
|
||||
override string getOperator() { result = "*" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MulExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ divide expression.
|
||||
* ```
|
||||
* c = a / b;
|
||||
* ```
|
||||
*/
|
||||
class DivExpr extends BinaryArithmeticOperation, @divexpr {
|
||||
override string getOperator() { result = "/" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DivExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ remainder expression.
|
||||
* ```
|
||||
* c = a % b;
|
||||
* ```
|
||||
*/
|
||||
class RemExpr extends BinaryArithmeticOperation, @remexpr {
|
||||
override string getOperator() { result = "%" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RemExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ multiply expression with an imaginary number. This is specific to
|
||||
* C99 and later.
|
||||
* ```
|
||||
* double z;
|
||||
* _Imaginary double x, y;
|
||||
* z = x * y;
|
||||
* ```
|
||||
*/
|
||||
class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
|
||||
override string getOperator() { result = "*" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryMulExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ divide expression with an imaginary number. This is specific to
|
||||
* C99 and later.
|
||||
* ```
|
||||
* double z;
|
||||
* _Imaginary double y;
|
||||
* z = z / y;
|
||||
* ```
|
||||
*/
|
||||
class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
|
||||
override string getOperator() { result = "/" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryDivExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ add expression with a real term and an imaginary term. This is
|
||||
* specific to C99 and later.
|
||||
* ```
|
||||
* double z;
|
||||
* _Imaginary double x;
|
||||
* _Complex double w;
|
||||
* w = z + x;
|
||||
* ```
|
||||
*/
|
||||
class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RealImaginaryAddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ add expression with an imaginary term and a real term. This is
|
||||
* specific to C99 and later.
|
||||
* ```
|
||||
* double z;
|
||||
* _Imaginary double x;
|
||||
* _Complex double w;
|
||||
* w = x + z;
|
||||
* ```
|
||||
*/
|
||||
class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryRealAddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ subtract expression with a real term and an imaginary term. This is
|
||||
* specific to C99 and later.
|
||||
* ```
|
||||
* double z;
|
||||
* _Imaginary double x;
|
||||
* _Complex double w;
|
||||
* w = z - x;
|
||||
* ```
|
||||
*/
|
||||
class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RealImaginarySubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ subtract expression with an imaginary term and a real term. This is
|
||||
* specific to C99 and later.
|
||||
* ```
|
||||
* double z;
|
||||
* _Imaginary double x;
|
||||
* _Complex double w;
|
||||
* w = x - z;
|
||||
* ```
|
||||
*/
|
||||
class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryRealSubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ GNU min expression.
|
||||
* ```
|
||||
* c = a <? b;
|
||||
* ```
|
||||
*/
|
||||
class MinExpr extends BinaryArithmeticOperation, @minexpr {
|
||||
override string getOperator() { result = "<?" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MinExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ GNU max expression.
|
||||
* ```
|
||||
* c = a >? b;
|
||||
* ```
|
||||
*/
|
||||
class MaxExpr extends BinaryArithmeticOperation, @maxexpr {
|
||||
override string getOperator() { result = ">?" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MaxExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ pointer arithmetic operation.
|
||||
*/
|
||||
class PointerArithmeticOperation extends BinaryArithmeticOperation, @p_arith_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ pointer add expression.
|
||||
* ```
|
||||
* foo *ptr = &f[0];
|
||||
* ptr = ptr + 2;
|
||||
* ```
|
||||
*/
|
||||
class PointerAddExpr extends PointerArithmeticOperation, @paddexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerAddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ pointer subtract expression.
|
||||
* ```
|
||||
* foo *ptr = &f[3];
|
||||
* ptr = ptr - 2;
|
||||
* ```
|
||||
*/
|
||||
class PointerSubExpr extends PointerArithmeticOperation, @psubexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerSubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ pointer difference expression.
|
||||
* ```
|
||||
* foo *start = &f[0], *end = &f[4];
|
||||
* int size = end - size;
|
||||
* ```
|
||||
*/
|
||||
class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerDiffExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
248
cpp/ql/lib/semmle/code/cpp/exprs/Assignment.qll
Normal file
248
cpp/ql/lib/semmle/code/cpp/exprs/Assignment.qll
Normal file
@@ -0,0 +1,248 @@
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.exprs.ArithmeticOperation
|
||||
import semmle.code.cpp.exprs.BitwiseOperation
|
||||
|
||||
/**
|
||||
* A non-overloaded binary assignment operation, including `=`, `+=`, `&=`,
|
||||
* etc. A C++ overloaded assignment operation looks syntactically identical but is instead
|
||||
* a `FunctionCall`.
|
||||
*
|
||||
* This is a QL base class for all (non-overloaded) assignments.
|
||||
*/
|
||||
class Assignment extends Operation, @assign_expr {
|
||||
/** Gets the _lvalue_ of this assignment. */
|
||||
Expr getLValue() { this.hasChild(result, 0) }
|
||||
|
||||
/** Gets the rvalue of this assignment. */
|
||||
Expr getRValue() { this.hasChild(result, 1) }
|
||||
|
||||
override int getPrecedence() { result = 2 }
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
this.getRValue().mayBeGloballyImpure()
|
||||
or
|
||||
not exists(VariableAccess va, StackVariable v |
|
||||
va = this.getLValue() and
|
||||
v = va.getTarget() and
|
||||
not va.getConversion+() instanceof ReferenceDereferenceExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded assignment operation with the operator `=`.
|
||||
* ```
|
||||
* a = b;
|
||||
* ```
|
||||
*/
|
||||
class AssignExpr extends Assignment, @assignexpr {
|
||||
override string getOperator() { result = "=" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AssignExpr" }
|
||||
|
||||
/** Gets a textual representation of this assignment. */
|
||||
override string toString() { result = "... = ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded binary assignment operation other than `=`.
|
||||
*/
|
||||
class AssignOperation extends Assignment, @assign_op_expr {
|
||||
override string toString() { result = "... " + this.getOperator() + " ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded arithmetic assignment operation on a non-pointer _lvalue_:
|
||||
* `+=`, `-=`, `*=`, `/=` and `%=`.
|
||||
*/
|
||||
class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { }
|
||||
|
||||
/**
|
||||
* A non-overloaded `+=` assignment expression on a non-pointer _lvalue_.
|
||||
* ```
|
||||
* a += b;
|
||||
* ```
|
||||
*/
|
||||
class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignAddExpr" }
|
||||
|
||||
override string getOperator() { result = "+=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `-=` assignment expression on a non-pointer _lvalue_.
|
||||
* ```
|
||||
* a -= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignSubExpr" }
|
||||
|
||||
override string getOperator() { result = "-=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `*=` assignment expression.
|
||||
* ```
|
||||
* a *= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignMulExpr" }
|
||||
|
||||
override string getOperator() { result = "*=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `/=` assignment expression.
|
||||
* ```
|
||||
* a /= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignDivExpr" }
|
||||
|
||||
override string getOperator() { result = "/=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `%=` assignment expression.
|
||||
* ```
|
||||
* a %= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignRemExpr extends AssignArithmeticOperation, @assignremexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignRemExpr" }
|
||||
|
||||
override string getOperator() { result = "%=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded bitwise assignment operation:
|
||||
* `&=`, `|=`, `^=`, `<<=`, and `>>=`.
|
||||
*/
|
||||
class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { }
|
||||
|
||||
/**
|
||||
* A non-overloaded AND (`&=`) assignment expression.
|
||||
* ```
|
||||
* a &= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignAndExpr" }
|
||||
|
||||
override string getOperator() { result = "&=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded OR (`|=`) assignment expression.
|
||||
* ```
|
||||
* a |= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignOrExpr" }
|
||||
|
||||
override string getOperator() { result = "|=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded XOR (`^=`) assignment expression.
|
||||
* ```
|
||||
* a ^= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignXorExpr" }
|
||||
|
||||
override string getOperator() { result = "^=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `<<=` assignment expression.
|
||||
* ```
|
||||
* a <<= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
|
||||
|
||||
override string getOperator() { result = "<<=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `>>=` assignment expression.
|
||||
* ```
|
||||
* a >>= b;
|
||||
* ```
|
||||
*/
|
||||
class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
|
||||
|
||||
override string getOperator() { result = ">>=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `+=` pointer assignment expression.
|
||||
* ```
|
||||
* ptr += index;
|
||||
* ```
|
||||
*/
|
||||
class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignPointerAddExpr" }
|
||||
|
||||
override string getOperator() { result = "+=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded `-=` pointer assignment expression.
|
||||
* ```
|
||||
* ptr -= index;
|
||||
* ```
|
||||
*/
|
||||
class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignPointerSubExpr" }
|
||||
|
||||
override string getOperator() { result = "-=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ variable declaration inside the conditional expression of a `while`, `if` or
|
||||
* `for` compound statement. Declaring a variable this way narrows its lifetime and
|
||||
* scope to be strictly the compound statement itself. For example:
|
||||
* ```
|
||||
* extern int x, y;
|
||||
* if (bool c = x < y) { do_something_with(c); }
|
||||
* // c is no longer in scope
|
||||
* while (int d = x - y) { do_something_else_with(d); }
|
||||
* // d is no longer is scope
|
||||
* ```
|
||||
*/
|
||||
class ConditionDeclExpr extends Expr, @condition_decl {
|
||||
/**
|
||||
* DEPRECATED: Use `getVariableAccess()` or `getInitializingExpr()` instead.
|
||||
*
|
||||
* Gets the access using the condition for this declaration.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConditionDeclExpr" }
|
||||
|
||||
/**
|
||||
* Gets the compiler-generated variable access that conceptually occurs after
|
||||
* the initialization of the declared variable.
|
||||
*/
|
||||
VariableAccess getVariableAccess() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the expression that initializes the declared variable. This predicate
|
||||
* always has a result.
|
||||
*/
|
||||
Expr getInitializingExpr() { result = this.getVariable().getInitializer().getExpr() }
|
||||
|
||||
/** Gets the variable that is declared. */
|
||||
Variable getVariable() { condition_decl_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string toString() { result = "(condition decl)" }
|
||||
}
|
||||
100
cpp/ql/lib/semmle/code/cpp/exprs/BitwiseOperation.qll
Normal file
100
cpp/ql/lib/semmle/code/cpp/exprs/BitwiseOperation.qll
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Provides classes for modeling bitwise operations such as `~`, `<<`, `&` and
|
||||
* `|`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ unary bitwise operation.
|
||||
*/
|
||||
class UnaryBitwiseOperation extends UnaryOperation, @un_bitwise_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ complement expression.
|
||||
* ```
|
||||
* unsigned c = ~a;
|
||||
* ```
|
||||
*/
|
||||
class ComplementExpr extends UnaryBitwiseOperation, @complementexpr {
|
||||
override string getOperator() { result = "~" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ComplementExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ binary bitwise operation.
|
||||
*/
|
||||
class BinaryBitwiseOperation extends BinaryOperation, @bin_bitwise_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ left shift expression.
|
||||
* ```
|
||||
* unsigned c = a << b;
|
||||
* ```
|
||||
*/
|
||||
class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr {
|
||||
override string getOperator() { result = "<<" }
|
||||
|
||||
override int getPrecedence() { result = 12 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LShiftExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ right shift expression.
|
||||
* ```
|
||||
* unsigned c = a >> b;
|
||||
* ```
|
||||
*/
|
||||
class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr {
|
||||
override string getOperator() { result = ">>" }
|
||||
|
||||
override int getPrecedence() { result = 12 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RShiftExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ bitwise AND expression.
|
||||
* ```
|
||||
* unsigned c = a & b;
|
||||
* ```
|
||||
*/
|
||||
class BitwiseAndExpr extends BinaryBitwiseOperation, @andexpr {
|
||||
override string getOperator() { result = "&" }
|
||||
|
||||
override int getPrecedence() { result = 8 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ bitwise OR expression.
|
||||
* ```
|
||||
* unsigned c = a | b;
|
||||
* ```
|
||||
*/
|
||||
class BitwiseOrExpr extends BinaryBitwiseOperation, @orexpr {
|
||||
override string getOperator() { result = "|" }
|
||||
|
||||
override int getPrecedence() { result = 6 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ bitwise XOR expression.
|
||||
* ```
|
||||
* unsigned c = a ^ b;
|
||||
* ```
|
||||
*/
|
||||
class BitwiseXorExpr extends BinaryBitwiseOperation, @xorexpr {
|
||||
override string getOperator() { result = "^" }
|
||||
|
||||
override int getPrecedence() { result = 7 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
|
||||
}
|
||||
990
cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll
Normal file
990
cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll
Normal file
@@ -0,0 +1,990 @@
|
||||
/**
|
||||
* Provides classes for modeling built-in operations. Built-in operations are
|
||||
* typically compiler specific and are used by libraries and generated code.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ built-in operation. This is the root QL class encompassing
|
||||
* built-in functionality.
|
||||
*/
|
||||
class BuiltInOperation extends Expr, @builtin_op {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperation" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ built-in operation that is used to support functions with variable numbers of arguments.
|
||||
* This includes `va_start`, `va_end`, `va_copy`, and `va_arg`.
|
||||
*/
|
||||
class VarArgsExpr extends BuiltInOperation, @var_args_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_va_start` built-in operation (used by some
|
||||
* implementations of `va_start`).
|
||||
* ```
|
||||
* __builtin_va_list ap;
|
||||
* __builtin_va_start(ap, last_named_param);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInVarArgsStart extends VarArgsExpr, @vastartexpr {
|
||||
override string toString() { result = "__builtin_va_start" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
*/
|
||||
final Expr getVAList() { result = getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the argument that specifies the last named parameter before the ellipsis.
|
||||
*/
|
||||
final VariableAccess getLastNamedParameter() { result = getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_va_end` built-in operation (used by some implementations
|
||||
* of `va_end`).
|
||||
* ```
|
||||
* __builtin_va_start(ap, last_named_param);
|
||||
* ap = __builtin_va_arg(ap, long);
|
||||
* __builtin_va_end(ap);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInVarArgsEnd extends VarArgsExpr, @vaendexpr {
|
||||
override string toString() { result = "__builtin_va_end" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
*/
|
||||
final Expr getVAList() { result = getChild(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_va_arg` built-in operation (used by some implementations
|
||||
* of `va_arg`).
|
||||
* ```
|
||||
* ap = __builtin_va_arg(ap, long);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInVarArg extends VarArgsExpr, @vaargexpr {
|
||||
override string toString() { result = "__builtin_va_arg" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArg" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
*/
|
||||
final Expr getVAList() { result = getChild(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_va_copy` built-in operation (used by some implementations
|
||||
* of `va_copy`).
|
||||
* ```
|
||||
* va_list ap, aq;
|
||||
* __builtin_va_start(ap, last_named_param);
|
||||
* va_copy(aq, ap);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInVarArgCopy extends VarArgsExpr, @vacopyexpr {
|
||||
override string toString() { result = "__builtin_va_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" }
|
||||
|
||||
/**
|
||||
* Gets the destination `va_list` argument.
|
||||
*/
|
||||
final Expr getDestinationVAList() { result = getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the the source `va_list` argument.
|
||||
*/
|
||||
final Expr getSourceVAList() { result = getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Microsoft C/C++ `__noop` expression, which does nothing.
|
||||
* ```
|
||||
* __noop;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInNoOp extends BuiltInOperation, @noopexpr {
|
||||
override string toString() { result = "__noop" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInNoOp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BuiltInOperationBuiltInOffsetOf` instead.
|
||||
*/
|
||||
deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf;
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_offsetof` built-in operation (used by some implementations
|
||||
* of `offsetof`). The operation retains its semantics even in the presence
|
||||
* of an overloaded `operator &`). This is a GNU/Clang extension.
|
||||
* ```
|
||||
* struct S {
|
||||
* int a, b;
|
||||
* };
|
||||
* int d = __builtin_offsetof(struct S, b); // usually 4
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr {
|
||||
override string toString() { result = "__builtin_offsetof" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInOffsetOf" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `__INTADDR__` built-in operation (used by some implementations
|
||||
* of `offsetof`). The operation retains its semantics even in the presence
|
||||
* of an overloaded `operator &`). This is an EDG extension.
|
||||
* ```
|
||||
* struct S {
|
||||
* int a, b;
|
||||
* };
|
||||
* int d = __INTADDR__(struct S, b); // usually 4
|
||||
* ```
|
||||
*/
|
||||
class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr {
|
||||
override string toString() { result = "__INTADDR__" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInIntAddr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_assign` built-in operation (used by some implementations of
|
||||
* the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a copy assignment operator.
|
||||
* ```
|
||||
* bool v = __has_assign(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr {
|
||||
override string toString() { result = "__has_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_copy` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a copy constructor.
|
||||
* ```
|
||||
* std::integral_constant< bool, __has_copy(_Tp)> hc;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr {
|
||||
override string toString() { result = "__has_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasCopy" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_nothrow_assign` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a copy assignment operator has an empty exception
|
||||
* specification.
|
||||
* ```
|
||||
* std::integral_constant< bool, __has_nothrow_assign(_Tp)> hnta;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign {
|
||||
override string toString() { result = "__has_nothrow_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_nothrow_constructor` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the default constructor has an empty exception
|
||||
* specification.
|
||||
* ```
|
||||
* bool v = __has_nothrow_constructor(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothrowconstr {
|
||||
override string toString() { result = "__has_nothrow_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowConstructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_nothrow_copy` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the copy constructor has an empty exception specification.
|
||||
* ```
|
||||
* std::integral_constant< bool, __has_nothrow_copy(MyType) >;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy {
|
||||
override string toString() { result = "__has_nothrow_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowCopy" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_trivial_assign` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a trivial assignment
|
||||
* operator (`operator =`).
|
||||
* ```
|
||||
* bool v = __has_trivial_assign(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassign {
|
||||
override string toString() { result = "__has_trivial_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_trivial_constructor` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a trivial constructor.
|
||||
* ```
|
||||
* bool v = __has_trivial_constructor(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivialconstr {
|
||||
override string toString() { result = "__has_trivial_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialConstructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_trivial_copy` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if the type has a trivial copy constructor.
|
||||
* ```
|
||||
* std::integral_constant< bool, __has_trivial_copy(MyType) > htc;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy {
|
||||
override string toString() { result = "__has_trivial_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialCopy" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_trivial_destructor` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a trivial destructor.
|
||||
* ```
|
||||
* bool v = __has_trivial_destructor(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivialdestructor {
|
||||
override string toString() { result = "__has_trivial_destructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialDestructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_user_destructor` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if the type has a user-declared destructor.
|
||||
* ```
|
||||
* bool v = __has_user_destructor(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr {
|
||||
override string toString() { result = "__has_user_destructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasUserDestructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__has_virtual_destructor` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a virtual destructor.
|
||||
* ```
|
||||
* template<typename _Tp>
|
||||
* struct has_virtual_destructor
|
||||
* : public integral_constant<bool, __has_virtual_destructor(_Tp)>
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtualdestr {
|
||||
override string toString() { result = "__has_virtual_destructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasVirtualDestructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_abstract` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the class has at least one pure virtual function.
|
||||
* ```
|
||||
* bool v = __is_abstract(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr {
|
||||
override string toString() { result = "__is_abstract" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAbstract" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_base_of` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the first type is a base class of the second type, of if both types are the same.
|
||||
* ```
|
||||
* bool v = __is_base_of(MyType, OtherType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr {
|
||||
override string toString() { result = "__is_base_of" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsBaseOf" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_class` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is a `class` or a `struct`.
|
||||
* ```
|
||||
* bool v = __is_class(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr {
|
||||
override string toString() { result = "__is_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_convertible_to` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the first type can be converted to the second type.
|
||||
* ```
|
||||
* bool v = __is_convertible_to(MyType, OtherType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr {
|
||||
override string toString() { result = "__is_convertible_to" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_empty` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has no instance data members.
|
||||
* ```
|
||||
* bool v = __is_empty(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr {
|
||||
override string toString() { result = "__is_empty" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsEmpty" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_enum` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns true if the type is an `enum`.
|
||||
* ```
|
||||
* bool v = __is_enum(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr {
|
||||
override string toString() { result = "__is_enum" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsEnum" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_pod` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is a `class`, `struct` or `union`, WITHOUT
|
||||
* (1) constructors, (2) private or protected non-static members, (3) base
|
||||
* classes, or (4) virtual functions.
|
||||
* ```
|
||||
* bool v = __is_pod(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr {
|
||||
override string toString() { result = "__is_pod" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsPod" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_polymorphic` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has at least one virtual function.
|
||||
* ```
|
||||
* bool v = __is_polymorphic(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr {
|
||||
override string toString() { result = "__is_polymorphic" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsPolymorphic" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_union` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is a `union`.
|
||||
* ```
|
||||
* bool v = __is_union(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr {
|
||||
override string toString() { result = "__is_union" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BuiltInOperationBuiltInTypesCompatibleP` instead.
|
||||
*/
|
||||
deprecated class BuiltInOperationBuiltInTypes = BuiltInOperationBuiltInTypesCompatibleP;
|
||||
|
||||
/**
|
||||
* A C++ `__builtin_types_compatible_p` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the two types are the same (modulo qualifiers).
|
||||
* ```
|
||||
* template<typename _Tp1, typename _Tp2>
|
||||
* struct types_compatible
|
||||
* : public integral_constant<bool, __builtin_types_compatible_p(_Tp1, _Tp2) >
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typescompexpr {
|
||||
override string toString() { result = "__builtin_types_compatible_p" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A clang `__builtin_shufflevector` expression.
|
||||
*
|
||||
* It outputs a permutation of elements from one or two input vectors.
|
||||
* Please see
|
||||
* https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#langext-builtin-shufflevector
|
||||
* for more information.
|
||||
* ```
|
||||
* // Concatenate every other element of 4-element vectors V1 and V2.
|
||||
* V3 = __builtin_shufflevector(V1, V2, 0, 2, 4, 6);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshufflevector {
|
||||
override string toString() { result = "__builtin_shufflevector" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A clang `__builtin_convertvector` expression.
|
||||
*
|
||||
* Allows for conversion of vectors of equal element count and compatible
|
||||
* element types. Please see
|
||||
* https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#builtin-convertvector
|
||||
* for more information.
|
||||
* ```
|
||||
* float vf __attribute__((__vector_size__(16)));
|
||||
* typedef double vector4double __attribute__((__vector_size__(32)));
|
||||
* // convert from a vector of 4 floats to a vector of 4 doubles.
|
||||
* vector4double vd = __builtin_convertvector(vf, vector4double);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInConvertVector extends BuiltInOperation, @builtinconvertvector {
|
||||
override string toString() { result = "__builtin_convertvector" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInConvertVector" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A clang `__builtin_addressof` function (can be used to implement C++'s
|
||||
* `std::addressof`).
|
||||
*
|
||||
* This function disregards any overloads created for `operator &`.
|
||||
* ```
|
||||
* int a = 1;
|
||||
* int *b = __builtin_addressof(a);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation, @builtinaddressof {
|
||||
/** Gets the function or variable whose address is taken. */
|
||||
Declaration getAddressable() {
|
||||
result = this.getOperand().(Access).getTarget()
|
||||
or
|
||||
// this handles the case where we are taking the address of a reference variable
|
||||
result = this.getOperand().(ReferenceDereferenceExpr).getChild(0).(Access).getTarget()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInAddressOf" }
|
||||
|
||||
override string getOperator() { result = "__builtin_addressof" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_trivially_constructible` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a trivial default
|
||||
* constructor, copy constructor or move constructor.
|
||||
* ```
|
||||
* template<typename T, typename... Args>
|
||||
* struct is_trivially_constructible
|
||||
* : public integral_constant<bool, __is_trivially_constructible(T, Args...) >
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation,
|
||||
@istriviallyconstructibleexpr {
|
||||
override string toString() { result = "__is_trivially_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_destructible` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type's destructor is not `delete`d and is accessible
|
||||
* in derived `class`es, and whose base `class` and all non-static data members
|
||||
* are also destructible.
|
||||
* ```
|
||||
* bool v = __is_destructible(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleexpr {
|
||||
override string toString() { result = "__is_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsDestructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_nothrow_destructible` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is destructible and whose destructor, and those
|
||||
* of member data and any super`class`es all have an empty exception
|
||||
* specification.
|
||||
* ```
|
||||
* bool v = __is_nothrow_destructible(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrowdestructibleexpr {
|
||||
override string toString() { result = "__is_nothrow_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowDestructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_trivially_destructible` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is destructible and whose destructor, and those
|
||||
* of member data and any superclasses are all trivial.
|
||||
* ```
|
||||
* bool v = __is_trivially_destructible(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr {
|
||||
override string toString() { result = "__is_trivially_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_trivially_assignable` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the assignment operator `C::operator =(const C& c)` is
|
||||
* trivial.
|
||||
* ```
|
||||
* template<typename T>
|
||||
* struct is_trivially_assignable
|
||||
* : public integral_constant<bool, __is_trivially_assignable(T) >
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr {
|
||||
override string toString() { result = "__is_trivially_assignable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyAssignable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_nothrow_assignable` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if there exists a `C::operator =(const C& c) nothrow`
|
||||
* assignment operator (i.e, with an empty exception specification).
|
||||
* ```
|
||||
* bool v = __is_nothrow_assignable(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr {
|
||||
override string toString() { result = "__is_nothrow_assignable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_standard_layout` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is a primitive type, or a `class`, `struct` or
|
||||
* `union` WITHOUT (1) virtual functions or base classes, (2) reference member
|
||||
* variable or (3) multiple occurrences of base `class` objects, among other
|
||||
* restrictions. Please see
|
||||
* https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
|
||||
* for more information.
|
||||
* ```
|
||||
* bool v = __is_standard_layout(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayoutexpr {
|
||||
override string toString() { result = "__is_standard_layout" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsStandardLayout" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_trivially_copyable` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if instances of this type can be copied by trivial
|
||||
* means. The copying is done in a manner similar to the `memcpy`
|
||||
* function.
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr {
|
||||
override string toString() { result = "__is_trivially_copyable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_literal_type` built-in operation (used by some implementations of
|
||||
* the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is a scalar type, a reference type or an array of
|
||||
* literal types, among others. Please see
|
||||
* https://en.cppreference.com/w/cpp/named_req/LiteralType
|
||||
* for more information.
|
||||
*
|
||||
* ```
|
||||
* template <typename _Tp>
|
||||
* std::integral_constant< bool, __is_literal_type(_Tp)> ilt;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr {
|
||||
override string toString() { result = "__is_literal_type" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsLiteralType" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__has_trivial_move_constructor` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if the move (`&&`) constructor can be generated by the
|
||||
* compiler, with semantics of the `memcpy` operation.
|
||||
* ```
|
||||
* template <typename _Tp>
|
||||
* std::integral_constant< bool, __has_trivial_move_constructor(_Tp)> htmc;
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
|
||||
@hastrivialmoveconstructorexpr {
|
||||
override string toString() { result = "__has_trivial_move_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__has_trivial_move_assign` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns if the move-assign operator `C::operator =(C &&c)` is trivial.
|
||||
* ```
|
||||
* template<typename T>
|
||||
* struct has_trivial_move_assign
|
||||
* : public integral_constant<bool, __has_trivial_move_assign(T) >
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivialmoveassignexpr {
|
||||
override string toString() { result = "__has_trivial_move_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__has_nothrow_move_assign` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type has a `C::operator=(C&& c) nothrow`, that is,
|
||||
* an assignment operator with an empty exception specification.
|
||||
* ```
|
||||
* bool v = __has_nothrow_move_assign(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrowmoveassignexpr {
|
||||
override string toString() { result = "__has_nothrow_move_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNothrowMoveAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_constructible` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type can be constructed using specified arguments
|
||||
* (or none).
|
||||
* ```
|
||||
* template<typename T, typename... Args>
|
||||
* struct is_constructible
|
||||
* : public integral_constant<bool, __is_constructible(T, Args...) >
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructibleexpr {
|
||||
override string toString() { result = "__is_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConstructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_nothrow_constructible` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the type is constructable and all its constructors have an
|
||||
* empty exception specification (i.e., are declared with `nothrow`);
|
||||
* ```
|
||||
* bool v = __is_nothrow_constructible(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothrowconstructibleexpr {
|
||||
override string toString() { result = "__is_nothrow_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConstructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__has_finalizer` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the type defines a _finalizer_ `C::!C(void)`, to be called
|
||||
* from either the regular destructor or the garbage collector.
|
||||
* ```
|
||||
* bool v = __has_finalizer(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr {
|
||||
override string toString() { result = "__has_finalizer" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasFinalizer" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_delegate` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the function has been declared as a `delegate`, used in
|
||||
* message forwarding. Please see
|
||||
* https://docs.microsoft.com/en-us/cpp/extensions/delegate-cpp-component-extensions
|
||||
* for more information.
|
||||
*/
|
||||
class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr {
|
||||
override string toString() { result = "__is_delegate" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsDelegate" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_interface_class` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the type has been declared as an `interface`. Please see
|
||||
* https://docs.microsoft.com/en-us/cpp/extensions/interface-class-cpp-component-extensions
|
||||
* for more information.
|
||||
*/
|
||||
class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfaceclassexpr {
|
||||
override string toString() { result = "__is_interface_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsInterfaceClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_ref_array` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the object passed in is a _platform array_. Please see
|
||||
* https://docs.microsoft.com/en-us/cpp/extensions/arrays-cpp-component-extensions
|
||||
* for more information.
|
||||
* ```
|
||||
* array<int>^ x = gcnew array<int>(10);
|
||||
* bool b = __is_ref_array(array<int>);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr {
|
||||
override string toString() { result = "__is_ref_array" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefArray" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_ref_class` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the type is a _reference class_. Please see
|
||||
* https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions
|
||||
* for more information.
|
||||
* ```
|
||||
* ref class R {};
|
||||
* bool b = __is_ref_class(R);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr {
|
||||
override string toString() { result = "__is_ref_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_sealed` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if a given class or virtual function is marked as `sealed`,
|
||||
* meaning that it cannot be extended or overridden. The `sealed` keyword
|
||||
* is similar to the C++11 `final` keyword.
|
||||
* ```
|
||||
* ref class X sealed {
|
||||
* virtual void f() sealed { }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr {
|
||||
override string toString() { result = "__is_sealed" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSealed" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_simple_value_class` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if passed a value type that contains no references to the
|
||||
* garbage-collected heap.
|
||||
* ```
|
||||
* ref class R {}; // __is_simple_value_class(R) == false
|
||||
* value struct V {}; // __is_simple_value_class(V) == true
|
||||
* value struct V2 { // __is_simple_value_class(V2) == false
|
||||
* R ^ r; // not a simple value type
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalueclassexpr {
|
||||
override string toString() { result = "__is_simple_value_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSimpleValueClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_value_class` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if passed a value type. Please see
|
||||
* https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions
|
||||
* For more information.
|
||||
* ```
|
||||
* value struct V {};
|
||||
* bool v = __is_value_class(V);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr {
|
||||
override string toString() { result = "__is_value_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsValueClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_final` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the `class` has been marked with the `final` specifier.
|
||||
* ```
|
||||
* template<typename T>
|
||||
* struct is_final
|
||||
* : public integral_constant<bool, __is_final(T) >
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr {
|
||||
override string toString() { result = "__is_final" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsFinal" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__builtin_choose_expr` expression. This is a GNU/Clang extension.
|
||||
*
|
||||
* The expression functions similarly to the ternary `?:` operator, except
|
||||
* that it is evaluated at compile-time.
|
||||
* ```
|
||||
* int sz = __builtin_choose_expr(__builtin_types_compatible_p(int, long), 4, 8);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr {
|
||||
override string toString() { result = "__builtin_choose_expr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInChooseExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill operation on a vector. This is a GNU extension.
|
||||
*
|
||||
* A single scalar value is used to populate all the elements in a vector.
|
||||
* In the example below, the scalar value is `25`:
|
||||
* ```
|
||||
* typedef int v16i __attribute__((vector_size(16)));
|
||||
* v16i src, dst;
|
||||
* dst = src << 25;
|
||||
* ```
|
||||
*/
|
||||
class VectorFillOperation extends UnaryOperation, @vec_fill {
|
||||
override string getOperator() { result = "(vector fill)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VectorFillOperation" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The GNU `__builtin_complex` operation.
|
||||
*/
|
||||
class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex {
|
||||
override string toString() { result = "__builtin_complex" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInComplexOperation" }
|
||||
|
||||
/** Gets the operand corresponding to the real part of the complex number. */
|
||||
Expr getRealOperand() { this.hasChild(result, 0) }
|
||||
|
||||
/** Gets the operand corresponding to the imaginary part of the complex number. */
|
||||
Expr getImaginaryOperand() { this.hasChild(result, 1) }
|
||||
}
|
||||
665
cpp/ql/lib/semmle/code/cpp/exprs/Call.qll
Normal file
665
cpp/ql/lib/semmle/code/cpp/exprs/Call.qll
Normal file
@@ -0,0 +1,665 @@
|
||||
/**
|
||||
* Provides classes for modeling call expressions including direct calls to
|
||||
* functions, constructor and destructor calls, and calls made through function
|
||||
* pointers.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Function
|
||||
private import semmle.code.cpp.dataflow.EscapesTree
|
||||
|
||||
private class TCall = @funbindexpr or @callexpr;
|
||||
|
||||
/**
|
||||
* A C/C++ call.
|
||||
*/
|
||||
class Call extends Expr, NameQualifiableElement, TCall {
|
||||
// `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes
|
||||
// `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to
|
||||
// that function. That's why the charpred for `FunctionCall` requires:
|
||||
// ```
|
||||
// iscall(underlyingElement(this), _)
|
||||
// ```
|
||||
// So for the charpred for `Call` we include the requirement that if this is an instance of
|
||||
// `@funbindexpr` it must be a _call_ to the function.
|
||||
Call() { this instanceof @callexpr or iscall(underlyingElement(this), _) }
|
||||
|
||||
/**
|
||||
* Gets the number of arguments (actual parameters) of this call. The count
|
||||
* does _not_ include the qualifier of the call, if any.
|
||||
*/
|
||||
int getNumberOfArguments() { result = count(this.getAnArgument()) }
|
||||
|
||||
/**
|
||||
* Holds if this call has a qualifier.
|
||||
*
|
||||
* For example, `ptr->f()` has a qualifier, whereas plain `f()` does not.
|
||||
*/
|
||||
predicate hasQualifier() { exists(Expr e | this.getChild(-1) = e) }
|
||||
|
||||
/**
|
||||
* Gets the expression to the left of the function name or function pointer variable name.
|
||||
*
|
||||
* As a few examples:
|
||||
* For the call to `f` in `ptr->f()`, this gives `ptr`.
|
||||
* For the call to `f` in `(*ptr).f()`, this gives `(*ptr)`.
|
||||
*/
|
||||
Expr getQualifier() { result = this.getChild(-1) }
|
||||
|
||||
/**
|
||||
* Gets an argument for this call. To get the qualifier of this call, if
|
||||
* any, use `getQualifier()`.
|
||||
*/
|
||||
Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 0) }
|
||||
|
||||
/**
|
||||
* Gets the nth argument for this call.
|
||||
*
|
||||
* The range of `n` is from `0` to `getNumberOfArguments() - 1`. To get the
|
||||
* qualifier of this call, if any, use `getQualifier()`.
|
||||
*/
|
||||
Expr getArgument(int n) { result = this.getChild(n) and n >= 0 }
|
||||
|
||||
/**
|
||||
* Gets a subexpression of the argument at position `index`. If the
|
||||
* argument itself contains calls, such calls will be considered
|
||||
* leaves in the expression tree. The qualifier of the call, if any, is not
|
||||
* considered to be an argument.
|
||||
*
|
||||
* Example: the call `f(2, 3 + 4, g(4 + 5))` has sub expression(s)
|
||||
* `2` at index 0; `3`, `4`, and `3 + 4` at index 1; and `g(4 + 5)`
|
||||
* at index 2, respectively.
|
||||
*/
|
||||
Expr getAnArgumentSubExpr(int index) {
|
||||
result = getArgument(index)
|
||||
or
|
||||
exists(Expr mid |
|
||||
mid = getAnArgumentSubExpr(index) and
|
||||
not mid instanceof Call and
|
||||
not mid instanceof SizeofOperator and
|
||||
result = mid.getAChild()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the call, as best as makes sense for this kind of call.
|
||||
* The precise meaning depends on the kind of call it is:
|
||||
* - For a call to a function, it's the function being called.
|
||||
* - For a C++ method call, it's the statically resolved method.
|
||||
* - For an Objective C message expression, it's the statically resolved
|
||||
* method, and it might not exist.
|
||||
* - For a variable call, it never exists.
|
||||
*/
|
||||
Function getTarget() { none() } // overridden in subclasses
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this call passes the variable accessed by `va` by
|
||||
* reference as the `i`th argument. The qualifier of a call to a member
|
||||
* function is `i = -1`.
|
||||
*
|
||||
* A variable is passed by reference if the `i`th parameter of the function
|
||||
* receives an address that points within the object denoted by `va`. For a
|
||||
* variable named `x`, passing by reference includes both explicit pointers
|
||||
* (`&x`) and implicit conversion to a C++ reference (`x`), but it also
|
||||
* includes deeper expressions such as `&x[0] + length` or `&*&*&x`.
|
||||
*
|
||||
* When `Field`s are involved, an argument `i` may pass more than one
|
||||
* variable by reference simultaneously. For example, the call `f(&x.m1.m2)`
|
||||
* counts as passing both `x`, `m1` and `m2` to argument 0 of `f`.
|
||||
*
|
||||
* This predicate holds for variables passed by reference even if they are
|
||||
* passed as references to `const` and thus cannot be changed through that
|
||||
* reference. See `passesByNonConstReference` for a predicate that only holds
|
||||
* for variables passed by reference to non-const.
|
||||
*/
|
||||
predicate passesByReference(int i, VariableAccess va) {
|
||||
variableAddressEscapesTree(va, this.getArgument(i).getFullyConverted())
|
||||
or
|
||||
variableAddressEscapesTree(va, this.getQualifier().getFullyConverted()) and
|
||||
i = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this call passes the variable accessed by `va` by
|
||||
* reference to non-const data as the `i`th argument. The qualifier of a
|
||||
* call to a member function is `i = -1`.
|
||||
*
|
||||
* A variable is passed by reference if the `i`th parameter of the function
|
||||
* receives an address that points within the object denoted by `va`. For a
|
||||
* variable named `x`, passing by reference includes both explicit pointers
|
||||
* (`&x`) and implicit conversion to a C++ reference (`x`), but it also
|
||||
* includes deeper expressions such as `&x[0] + length` or `&*&*&x`.
|
||||
*
|
||||
* When `Field`s are involved, an argument `i` may pass more than one
|
||||
* variable by reference simultaneously. For example, the call `f(&x.m1.m2)`
|
||||
* counts as passing both `x`, `m1` and `m2` to argument 0 of `f`.
|
||||
*
|
||||
* This predicate only holds for variables passed by reference to non-const
|
||||
* data and thus can be changed through that reference. See
|
||||
* `passesByReference` for a predicate that also holds for variables passed
|
||||
* by reference to const.
|
||||
*/
|
||||
predicate passesByReferenceNonConst(int i, VariableAccess va) {
|
||||
variableAddressEscapesTreeNonConst(va, this.getArgument(i).getFullyConverted())
|
||||
or
|
||||
variableAddressEscapesTreeNonConst(va, this.getQualifier().getFullyConverted()) and
|
||||
i = -1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ function call where the name of the target function is known at compile-time.
|
||||
*
|
||||
* This includes various kinds of call:
|
||||
* 1. Calls such as `f(x)` where `f` is the name of a function.
|
||||
* 2. Calls such as `ptr->f()` where `f` is the name of a (possibly virtual) member function.
|
||||
* 3. Constructor calls for stack-allocated objects.
|
||||
* 4. Implicit and explicit calls to user-defined operators.
|
||||
* 5. Base class initializers in constructors.
|
||||
*/
|
||||
class FunctionCall extends Call, @funbindexpr {
|
||||
FunctionCall() { iscall(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionCall" }
|
||||
|
||||
/** Gets an explicit template argument for this call. */
|
||||
Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
|
||||
|
||||
/** Gets an explicit template argument value for this call. */
|
||||
Locatable getAnExplicitTemplateArgumentKind() { result = getExplicitTemplateArgumentKind(_) }
|
||||
|
||||
/** Gets a template argument for this call. */
|
||||
Locatable getATemplateArgument() { result = getTarget().getATemplateArgument() }
|
||||
|
||||
/** Gets a template argument value for this call. */
|
||||
Locatable getATemplateArgumentKind() { result = getTarget().getATemplateArgumentKind() }
|
||||
|
||||
/** Gets the nth explicit template argument for this call. */
|
||||
Locatable getExplicitTemplateArgument(int n) {
|
||||
n < getNumberOfExplicitTemplateArguments() and
|
||||
result = getTemplateArgument(n)
|
||||
}
|
||||
|
||||
/** Gets the nth explicit template argument value for this call. */
|
||||
Locatable getExplicitTemplateArgumentKind(int n) {
|
||||
n < getNumberOfExplicitTemplateArguments() and
|
||||
result = getTemplateArgumentKind(n)
|
||||
}
|
||||
|
||||
/** Gets the number of explicit template arguments for this call. */
|
||||
int getNumberOfExplicitTemplateArguments() {
|
||||
if numtemplatearguments(underlyingElement(this), _)
|
||||
then numtemplatearguments(underlyingElement(this), result)
|
||||
else result = 0
|
||||
}
|
||||
|
||||
/** Gets the number of template arguments for this call. */
|
||||
int getNumberOfTemplateArguments() { result = count(int i | exists(getTemplateArgument(i))) }
|
||||
|
||||
/** Gets the nth template argument for this call (indexed from 0). */
|
||||
Locatable getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
|
||||
|
||||
/** Gets the nth template argument value for this call (indexed from 0). */
|
||||
Locatable getTemplateArgumentKind(int n) { result = getTarget().getTemplateArgumentKind(n) }
|
||||
|
||||
/** Holds if any template arguments for this call are implicit / deduced. */
|
||||
predicate hasImplicitTemplateArguments() {
|
||||
exists(int i |
|
||||
exists(getTemplateArgument(i)) and
|
||||
not exists(getExplicitTemplateArgument(i))
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a template argument list was provided for this call. */
|
||||
predicate hasTemplateArgumentList() { numtemplatearguments(underlyingElement(this), _) }
|
||||
|
||||
/**
|
||||
* Gets the `RoutineType` of the call target as visible at the call site. For
|
||||
* constructor calls, this predicate instead gets the `Class` of the constructor
|
||||
* being called.
|
||||
*/
|
||||
Type getTargetType() { result = Call.super.getType().stripType() }
|
||||
|
||||
/**
|
||||
* Gets the expected return type of the function called by this call.
|
||||
*
|
||||
* In most cases, the expected return type will be the return type of the function being called.
|
||||
* It is only different when the function being called is ambiguously declared, at which point
|
||||
* the expected return type is the return type of the (unambiguous) function declaration that was
|
||||
* visible at the call site.
|
||||
*/
|
||||
Type getExpectedReturnType() {
|
||||
if getTargetType() instanceof RoutineType
|
||||
then result = getTargetType().(RoutineType).getReturnType()
|
||||
else result = getTarget().getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expected type of the nth parameter of the function called by this call.
|
||||
*
|
||||
* In most cases, the expected parameter types match the parameter types of the function being called.
|
||||
* They are only different when the function being called is ambiguously declared, at which point
|
||||
* the expected parameter types are the parameter types of the (unambiguous) function declaration that
|
||||
* was visible at the call site.
|
||||
*/
|
||||
Type getExpectedParameterType(int n) {
|
||||
if getTargetType() instanceof RoutineType
|
||||
then result = getTargetType().(RoutineType).getParameterType(n)
|
||||
else result = getTarget().getParameter(n).getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function called by this call.
|
||||
*
|
||||
* In the case of virtual function calls, the result is the most-specific function in the override tree (as
|
||||
* determined by the compiler) such that the target at runtime will be one of `result.getAnOverridingFunction*()`.
|
||||
*/
|
||||
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Gets the type of this expression, that is, the return type of the function being called.
|
||||
*/
|
||||
override Type getType() { result = getExpectedReturnType() }
|
||||
|
||||
/**
|
||||
* Holds if this is a call to a virtual function.
|
||||
*
|
||||
* Note that this holds even in cases where a sufficiently clever compiler could perform static dispatch.
|
||||
*/
|
||||
predicate isVirtual() { iscall(underlyingElement(this), 1) }
|
||||
|
||||
/**
|
||||
* Holds if the target of this function call was found by argument-dependent lookup and wouldn't have been
|
||||
* found by any other means.
|
||||
*/
|
||||
predicate isOnlyFoundByADL() { iscall(underlyingElement(this), 2) }
|
||||
|
||||
/** Gets a textual representation of this function call. */
|
||||
override string toString() {
|
||||
if exists(getTarget())
|
||||
then result = "call to " + this.getTarget().getName()
|
||||
else result = "call to unknown function"
|
||||
}
|
||||
|
||||
override predicate mayBeImpure() {
|
||||
this.getChild(_).mayBeImpure() or
|
||||
this.getTarget().mayHaveSideEffects() or
|
||||
isVirtual() or
|
||||
getTarget().getAnAttribute().getName() = "weak"
|
||||
}
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
this.getChild(_).mayBeGloballyImpure() or
|
||||
this.getTarget().mayHaveSideEffects() or
|
||||
isVirtual() or
|
||||
getTarget().getAnAttribute().getName() = "weak"
|
||||
}
|
||||
}
|
||||
|
||||
/** A _user-defined_ unary `operator*` function. */
|
||||
class OverloadedPointerDereferenceFunction extends Function {
|
||||
OverloadedPointerDereferenceFunction() {
|
||||
this.hasName("operator*") and
|
||||
this.getEffectiveNumberOfParameters() = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of a _user-defined_ unary `operator*` applied to its argument.
|
||||
* ```
|
||||
* T1 operator*(const T2 &);
|
||||
* T1 a; T2 b;
|
||||
* a = *b;
|
||||
* ```
|
||||
*/
|
||||
class OverloadedPointerDereferenceExpr extends FunctionCall {
|
||||
OverloadedPointerDereferenceExpr() {
|
||||
this.getTarget() instanceof OverloadedPointerDereferenceFunction
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" }
|
||||
|
||||
/**
|
||||
* Gets the expression this operator * applies to.
|
||||
*/
|
||||
Expr getExpr() {
|
||||
result = this.getChild(0) or
|
||||
result = this.getQualifier()
|
||||
}
|
||||
|
||||
override predicate mayBeImpure() {
|
||||
FunctionCall.super.mayBeImpure() and
|
||||
(
|
||||
this.getExpr().mayBeImpure()
|
||||
or
|
||||
not exists(Class declaring |
|
||||
this.getTarget().getDeclaringType().isConstructedFrom*(declaring)
|
||||
|
|
||||
declaring.getNamespace() instanceof StdNamespace
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
FunctionCall.super.mayBeGloballyImpure() and
|
||||
(
|
||||
this.getExpr().mayBeGloballyImpure()
|
||||
or
|
||||
not exists(Class declaring |
|
||||
this.getTarget().getDeclaringType().isConstructedFrom*(declaring)
|
||||
|
|
||||
declaring.getNamespace() instanceof StdNamespace
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of a _user-defined_ binary `operator[]` applied to its arguments.
|
||||
* ```
|
||||
* struct T2 { T1 operator[](const T3 &); };
|
||||
* T1 a; T2 b; T3 c;
|
||||
* a = b[c];
|
||||
* ```
|
||||
*/
|
||||
class OverloadedArrayExpr extends FunctionCall {
|
||||
OverloadedArrayExpr() { getTarget().hasName("operator[]") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" }
|
||||
|
||||
/**
|
||||
* Gets the expression being subscripted.
|
||||
*/
|
||||
Expr getArrayBase() {
|
||||
if exists(this.getQualifier()) then result = this.getQualifier() else result = this.getChild(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression giving the index.
|
||||
*/
|
||||
Expr getArrayOffset() {
|
||||
if exists(this.getQualifier()) then result = this.getChild(0) else result = this.getChild(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ call which is performed through a function pointer.
|
||||
*
|
||||
* In the call below, `(*funcptr)` may be simplified to just `funcptr`.
|
||||
* ```
|
||||
* extern int (*funcptr)(int a, int b);
|
||||
* int c = (*funcptr)(1, 2);
|
||||
* ```
|
||||
*/
|
||||
class ExprCall extends Call, @callexpr {
|
||||
/**
|
||||
* Gets the expression which yields the function pointer to call.
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExprCall" }
|
||||
|
||||
override Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 1) }
|
||||
|
||||
override Expr getArgument(int index) {
|
||||
result = this.getChild(index + 1) and index in [0 .. this.getNumChild() - 2]
|
||||
}
|
||||
|
||||
override string toString() { result = "call to expression" }
|
||||
|
||||
override Function getTarget() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ call which is performed through a variable of function pointer type.
|
||||
* ```
|
||||
* int call_via_ptr(int (*pfn)(int)) {
|
||||
* return pfn(5);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class VariableCall extends ExprCall {
|
||||
VariableCall() { this.getExpr() instanceof VariableAccess }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VariableCall" }
|
||||
|
||||
/**
|
||||
* Gets the variable which yields the function pointer to call.
|
||||
*/
|
||||
Variable getVariable() { this.getExpr().(VariableAccess).getTarget() = result }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a constructor.
|
||||
* ```
|
||||
* struct S { S(void) {} };
|
||||
* S s;
|
||||
* ```
|
||||
*/
|
||||
class ConstructorCall extends FunctionCall {
|
||||
ConstructorCall() { super.getTarget() instanceof Constructor }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorCall" }
|
||||
|
||||
/** Gets the constructor being called. */
|
||||
override Constructor getTarget() { result = super.getTarget() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor.
|
||||
* ```
|
||||
* struct S { ~S(void) {} } *s;
|
||||
* s->~S();
|
||||
* ```
|
||||
*/
|
||||
class DestructorCall extends FunctionCall {
|
||||
DestructorCall() { super.getTarget() instanceof Destructor }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DestructorCall" }
|
||||
|
||||
/** Gets the destructor being called. */
|
||||
override Destructor getTarget() { result = super.getTarget() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that looks like a destructor call, but has no effect.
|
||||
*
|
||||
* For example, given a plain old data type `pod_t`, the syntax `ptr->~pod_t()` is
|
||||
* a vacuous destructor call, as `~pod_t` isn't actually a function. This can also
|
||||
* occur in instantiated templates, as `ptr->~T()` becomes vacuous when `T` is `int`.
|
||||
* ```
|
||||
* typedef int pod_t;
|
||||
* pod_t *s;
|
||||
* s->~pod_t();
|
||||
* ```
|
||||
*/
|
||||
class VacuousDestructorCall extends Expr, @vacuous_destructor_call {
|
||||
/**
|
||||
* Gets the expression for the object whose destructor would be called.
|
||||
*/
|
||||
Expr getQualifier() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VacuousDestructorCall" }
|
||||
|
||||
override string toString() { result = "(vacuous destructor call)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An initialization of a base class or member variable performed as part
|
||||
* of a constructor's explicit initializer list or implicit actions.
|
||||
*
|
||||
* This is a QL root class for reprenting various types of constructor
|
||||
* initializations.
|
||||
*/
|
||||
class ConstructorInit extends Expr, @ctorinit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a constructor of a base class as part of a constructor's
|
||||
* initializer list or compiler-generated actions.
|
||||
*/
|
||||
class ConstructorBaseInit extends ConstructorInit, ConstructorCall {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorBaseInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a constructor of a direct non-virtual base class as part of a
|
||||
* constructor's initializer list or compiler-generated actions.
|
||||
* ```
|
||||
* struct S {
|
||||
* int a;
|
||||
* S(int b): a(b) {}
|
||||
* };
|
||||
* struct T: S {
|
||||
* T(): S(33) {} // S(33) is a constructor call
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDirectInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a constructor of a virtual base class as part of a
|
||||
* constructor's initializer list or compiler-generated actions.
|
||||
*
|
||||
* If the virtual base class has already been initialized, then this
|
||||
* call won't be performed.
|
||||
* ```
|
||||
* struct S {
|
||||
* int a;
|
||||
* S(int b): a(b) {}
|
||||
* };
|
||||
* struct T: virtual S {
|
||||
* T(): S(33) {} // S(33) is a call to a virtual base constructor
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorVirtualInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a constructor of the same class as part of a constructor's
|
||||
* initializer list, which delegates object construction (C++11 only).
|
||||
* ```
|
||||
* struct S {
|
||||
* int a;
|
||||
* S(int b): a(b) { }
|
||||
* S(): S(0) { } // delegation to another constructor
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDelegationInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed as part of a
|
||||
* constructor's explicit initializer list or implicit actions.
|
||||
* In the example below, member variable `b` is being initialized by
|
||||
* constructor parameter `a`:
|
||||
* ```
|
||||
* struct S {
|
||||
* int b;
|
||||
* S(int a): b(a) {}
|
||||
* } s(2);
|
||||
* ```
|
||||
*/
|
||||
class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
|
||||
/** Gets the field being initialized. */
|
||||
Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorFieldInit" }
|
||||
|
||||
/**
|
||||
* Gets the expression to which the field is initialized.
|
||||
*
|
||||
* This is typically either a Literal or a FunctionCall to a
|
||||
* constructor, but more complex expressions can also occur.
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string toString() { result = "constructor init of field " + getTarget().getName() }
|
||||
|
||||
override predicate mayBeImpure() { this.getExpr().mayBeImpure() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor of a base class or field as part of a destructor's
|
||||
* compiler-generated actions.
|
||||
*/
|
||||
class DestructorDestruction extends Expr, @dtordestruct {
|
||||
override string getAPrimaryQlClass() { result = "DestructorDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor of a base class as part of a destructor's
|
||||
* compiler-generated actions.
|
||||
*/
|
||||
class DestructorBaseDestruction extends DestructorCall, DestructorDestruction {
|
||||
override string getAPrimaryQlClass() { result = "DestructorBaseDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor of a direct non-virtual base class as part of a
|
||||
* destructor's compiler-generated actions.
|
||||
* ```
|
||||
* struct S { ~S(void) {} };
|
||||
* struct T: S {
|
||||
* ~T(void) {} // will call ~S()
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirectdestruct {
|
||||
override string getAPrimaryQlClass() { result = "DestructorDirectDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor of a direct virtual base class as part of a
|
||||
* destructor's compiler-generated actions.
|
||||
*
|
||||
* If the virtual base class wasn't initialized by the ConstructorVirtualInit
|
||||
* in the corresponding constructor, then this call won't be performed.
|
||||
* ```
|
||||
* struct S { ~S(void) {} };
|
||||
* struct T: virtual S {
|
||||
* ~T(void) {} // will call ~S()
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class DestructorVirtualDestruction extends DestructorBaseDestruction, @dtorvirtualdestruct {
|
||||
override string getAPrimaryQlClass() { result = "DestructorVirtualDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A destruction of a member variable performed as part of a
|
||||
* destructor's compiler-generated actions.
|
||||
* ```
|
||||
* struct S { ~S(void) {} };
|
||||
* struct T {
|
||||
* S s;
|
||||
* ~T(void) {} // will call s.~S()
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class DestructorFieldDestruction extends DestructorDestruction, @dtorfielddestruct {
|
||||
/** Gets the field being destructed. */
|
||||
Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DestructorFieldDestruction" }
|
||||
|
||||
/** Gets the compiler-generated call to the variable's destructor. */
|
||||
DestructorCall getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string toString() {
|
||||
result = "destructor field destruction of " + this.getTarget().getName()
|
||||
}
|
||||
}
|
||||
922
cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll
Normal file
922
cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll
Normal file
@@ -0,0 +1,922 @@
|
||||
/**
|
||||
* Provides classes for modeling C/C++ casts and conversions, as well as some
|
||||
* type-related operators such as `sizeof` and `alignof`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* A C/C++ cast expression or similar unary expression that doesn't affect the logical value of its operand.
|
||||
*
|
||||
* Instances of this class are not present in the main AST which is navigated by parent/child links. Instead,
|
||||
* instances of this class are attached to nodes in the main AST via special conversion links.
|
||||
*/
|
||||
class Conversion extends Expr, @conversion {
|
||||
/** Gets the expression being converted. */
|
||||
Expr getExpr() { result.getConversion() = this }
|
||||
|
||||
/** Holds if this conversion is an implicit conversion. */
|
||||
predicate isImplicit() { this.isCompilerGenerated() }
|
||||
|
||||
override predicate mayBeImpure() { this.getExpr().mayBeImpure() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ cast expression.
|
||||
*
|
||||
* To get the type which the expression is being cast to, use `Cast::getType()`.
|
||||
*
|
||||
* There are two groups of subtypes of `Cast`. The first group differentiates
|
||||
* between the different cast syntax forms, e.g. `CStyleCast`, `StaticCast`,
|
||||
* etc. The second group differentiates between the semantic operation being
|
||||
* performed by the cast, e.g. `IntegralConversion`, `PointerBaseClassConversion`,
|
||||
* etc.
|
||||
* The two groups are largely orthogonal to one another. For example, a
|
||||
* cast that is syntactically as `CStyleCast` may also be an `IntegralConversion`,
|
||||
* a `PointerBaseClassConversion`, or some other semantic conversion. Similarly,
|
||||
* a `PointerDerivedClassConversion` may also be a `CStyleCast` or a `StaticCast`.
|
||||
*
|
||||
* This is a root QL class representing the different casts. For
|
||||
* specific examples, consult the documentation for any of QL classes mentioned above.
|
||||
*/
|
||||
class Cast extends Conversion, @cast {
|
||||
/**
|
||||
* Gets a string describing the semantic conversion operation being performed by
|
||||
* this cast.
|
||||
*/
|
||||
string getSemanticConversionString() { result = "unknown conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Query predicates used to check invariants that should hold for all `Cast`
|
||||
* nodes. To run all consistency queries for the ASTs, including the ones below,
|
||||
* run "semmle/code/cpp/ASTConsistency.ql".
|
||||
*/
|
||||
module CastConsistency {
|
||||
/**
|
||||
* Holds if the cast has more than one result for `Cast.getSemanticConversionString()`.
|
||||
*/
|
||||
query predicate multipleSemanticConversionStrings(Cast cast, Type fromType, string kind) {
|
||||
// Every cast should have exactly one semantic conversion kind
|
||||
count(cast.getSemanticConversionString()) > 1 and
|
||||
kind = cast.getSemanticConversionString() and
|
||||
fromType = cast.getExpr().getUnspecifiedType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the cast has no result for `Cast.getSemanticConversionString()`.
|
||||
*/
|
||||
query predicate missingSemanticConversionString(Cast cast, Type fromType) {
|
||||
// Every cast should have exactly one semantic conversion kind
|
||||
not exists(cast.getSemanticConversionString()) and
|
||||
fromType = cast.getExpr().getUnspecifiedType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the cast has a result for `Cast.getSemanticConversionString()` that indicates that the
|
||||
* kind of its semantic conversion is not known.
|
||||
*/
|
||||
query predicate unknownSemanticConversionString(Cast cast, Type fromType) {
|
||||
// Every cast should have a known semantic conversion kind
|
||||
cast.getSemanticConversionString() = "unknown conversion" and
|
||||
fromType = cast.getExpr().getUnspecifiedType()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cast expression in C, or a C-style cast expression in C++.
|
||||
* ```
|
||||
* float f = 3.0f;
|
||||
* int i = (int)f;
|
||||
* ```
|
||||
*/
|
||||
class CStyleCast extends Cast, @c_style_cast {
|
||||
override string toString() { result = "(" + this.getType().getName() + ")..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CStyleCast" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `static_cast` expression.
|
||||
*
|
||||
* Please see https://en.cppreference.com/w/cpp/language/static_cast for
|
||||
* more information.
|
||||
* ```
|
||||
* struct T: S {};
|
||||
* struct S *s = get_S();
|
||||
* struct T *t = static_cast<struct T *>(s); // downcast
|
||||
* ```
|
||||
*/
|
||||
class StaticCast extends Cast, @static_cast {
|
||||
override string toString() { result = "static_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StaticCast" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `const_cast` expression.
|
||||
*
|
||||
* Please see https://en.cppreference.com/w/cpp/language/const_cast for
|
||||
* more information.
|
||||
* ```
|
||||
* const struct S *s = get_S();
|
||||
* struct S *t = const_cast<struct S *>(s);
|
||||
* ```
|
||||
*/
|
||||
class ConstCast extends Cast, @const_cast {
|
||||
override string toString() { result = "const_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstCast" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `reinterpret_cast` expression.
|
||||
*
|
||||
* Please see https://en.cppreference.com/w/cpp/language/reinterpret_cast for
|
||||
* more information.
|
||||
* ```
|
||||
* struct S *s = get_S();
|
||||
* std::uintptr_t p = reinterpret_cast<std::uintptr_t>(s);
|
||||
* ```
|
||||
*/
|
||||
class ReinterpretCast extends Cast, @reinterpret_cast {
|
||||
override string toString() { result = "reinterpret_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ReinterpretCast" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
}
|
||||
|
||||
private predicate isArithmeticOrEnum(Type type) {
|
||||
type instanceof ArithmeticType or
|
||||
type instanceof Enum
|
||||
}
|
||||
|
||||
private predicate isIntegralOrEnum(Type type) {
|
||||
type instanceof IntegralType or
|
||||
type instanceof Enum
|
||||
}
|
||||
|
||||
private predicate isPointerOrNullPointer(Type type) {
|
||||
type instanceof PointerType or
|
||||
type instanceof FunctionPointerType or
|
||||
type instanceof NullPointerType
|
||||
}
|
||||
|
||||
private predicate isPointerToMemberOrNullPointer(Type type) {
|
||||
type instanceof PointerToMemberType or
|
||||
type instanceof NullPointerType
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from one arithmetic or `enum` type to another.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class ArithmeticConversion extends Cast {
|
||||
ArithmeticConversion() {
|
||||
conversionkinds(underlyingElement(this), 0) and
|
||||
isArithmeticOrEnum(getUnspecifiedType()) and
|
||||
isArithmeticOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "arithmetic conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from one integral or enum type to another.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class IntegralConversion extends ArithmeticConversion {
|
||||
IntegralConversion() {
|
||||
isIntegralOrEnum(getUnspecifiedType()) and
|
||||
isIntegralOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "IntegralConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "integral conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from one floating point type.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class FloatingPointConversion extends ArithmeticConversion {
|
||||
FloatingPointConversion() {
|
||||
getUnspecifiedType() instanceof FloatingPointType and
|
||||
getExpr().getUnspecifiedType() instanceof FloatingPointType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "FloatingPointConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "floating point conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from a floating point type to an integral or enum type.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class FloatingPointToIntegralConversion extends ArithmeticConversion {
|
||||
FloatingPointToIntegralConversion() {
|
||||
isIntegralOrEnum(getUnspecifiedType()) and
|
||||
getExpr().getUnspecifiedType() instanceof FloatingPointType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "FloatingPointToIntegralConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "floating point to integral conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from an integral or enum type to a floating point type.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class IntegralToFloatingPointConversion extends ArithmeticConversion {
|
||||
IntegralToFloatingPointConversion() {
|
||||
getUnspecifiedType() instanceof FloatingPointType and
|
||||
isIntegralOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "IntegralToFloatingPointConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "integral to floating point conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from one pointer type to another.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*
|
||||
* The conversion does
|
||||
* not modify the value of the pointer. For pointer conversions involving
|
||||
* casts between base and derived classes, please see see `BaseClassConversion` or
|
||||
* `DerivedClassConversion`.
|
||||
*/
|
||||
class PointerConversion extends Cast {
|
||||
PointerConversion() {
|
||||
conversionkinds(underlyingElement(this), 0) and
|
||||
isPointerOrNullPointer(getUnspecifiedType()) and
|
||||
isPointerOrNullPointer(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" }
|
||||
|
||||
override string getSemanticConversionString() { result = "pointer conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from one pointer-to-member type to another.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*
|
||||
* The conversion does not modify the value of the pointer-to-member.
|
||||
* For pointer-to-member conversions involving casts between base and
|
||||
* derived classes, please see `PointerToMemberBaseClassConversion`
|
||||
* or `PointerToMemberDerivedClassConversion`.
|
||||
*/
|
||||
class PointerToMemberConversion extends Cast {
|
||||
PointerToMemberConversion() {
|
||||
conversionkinds(underlyingElement(this), 0) and
|
||||
exists(Type fromType, Type toType |
|
||||
fromType = getExpr().getUnspecifiedType() and
|
||||
toType = getUnspecifiedType() and
|
||||
isPointerToMemberOrNullPointer(fromType) and
|
||||
isPointerToMemberOrNullPointer(toType) and
|
||||
// A conversion from nullptr to nullptr is a `PointerConversion`, not a
|
||||
// `PointerToMemberConversion`.
|
||||
not (
|
||||
fromType instanceof NullPointerType and
|
||||
toType instanceof NullPointerType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToMemberConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "pointer-to-member conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from a pointer type to an integral or enum type.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class PointerToIntegralConversion extends Cast {
|
||||
PointerToIntegralConversion() {
|
||||
conversionkinds(underlyingElement(this), 0) and
|
||||
isIntegralOrEnum(getUnspecifiedType()) and
|
||||
isPointerOrNullPointer(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToIntegralConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "pointer to integral conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from an integral or enum type to a pointer type.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class IntegralToPointerConversion extends Cast {
|
||||
IntegralToPointerConversion() {
|
||||
conversionkinds(underlyingElement(this), 0) and
|
||||
isPointerOrNullPointer(getUnspecifiedType()) and
|
||||
isIntegralOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "IntegralToPointerConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "integral to pointer conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion to `bool`. Returns `false` if the source value is zero,
|
||||
* `false`, or `nullptr`. Returns `true` otherwise.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class BoolConversion extends Cast {
|
||||
BoolConversion() { conversionkinds(underlyingElement(this), 1) }
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BoolConversion" }
|
||||
|
||||
override string getSemanticConversionString() { result = "conversion to bool" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion to `void`.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class VoidConversion extends Cast {
|
||||
VoidConversion() {
|
||||
conversionkinds(underlyingElement(this), 0) and
|
||||
getUnspecifiedType() instanceof VoidType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" }
|
||||
|
||||
override string getSemanticConversionString() { result = "conversion to void" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion between two pointers or _glvalue_s related by inheritance.
|
||||
*
|
||||
* The base class will always be either a direct base class of the derived class,
|
||||
* or a virtual base class of the derived class. A conversion to an indirect
|
||||
* non-virtual base class will be represented as a sequence of conversions to
|
||||
* direct base classes.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class InheritanceConversion extends Cast {
|
||||
InheritanceConversion() {
|
||||
conversionkinds(underlyingElement(this), 2) or conversionkinds(underlyingElement(this), 3)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ClassDerivation` for the inheritance relationship between
|
||||
* the base and derived classes. This predicate does not hold if the
|
||||
* conversion is to an indirect virtual base class.
|
||||
*/
|
||||
final ClassDerivation getDerivation() {
|
||||
result.getBaseClass() = getBaseClass() and
|
||||
result.getDerivedClass() = getDerivedClass()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base class of the conversion. This will be either a direct
|
||||
* base class of the derived class, or a virtual base class of the
|
||||
* derived class.
|
||||
*/
|
||||
Class getBaseClass() {
|
||||
none() // Overridden by subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the derived class of the conversion.
|
||||
*/
|
||||
Class getDerivedClass() {
|
||||
none() // Overridden by subclasses
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the source operand or result of an `InheritanceConversion`, returns the
|
||||
* class being converted from or to. If the type of the expression is a pointer,
|
||||
* this returns the pointed-to class. Otherwise, the type of the expression must
|
||||
* be a class, in which case the result is that class.
|
||||
*/
|
||||
private Class getConversionClass(Expr expr) {
|
||||
exists(Type operandType |
|
||||
operandType = expr.getUnspecifiedType() and
|
||||
(
|
||||
result = operandType or
|
||||
result = operandType.(PointerType).getBaseType()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from a pointer or _glvalue_ of a derived class to a pointer or
|
||||
* _glvalue_ of a direct or virtual base class.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class BaseClassConversion extends InheritanceConversion {
|
||||
BaseClassConversion() { conversionkinds(underlyingElement(this), 2) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "BaseClassConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "base class conversion" }
|
||||
|
||||
override Class getBaseClass() { result = getConversionClass(this) }
|
||||
|
||||
override Class getDerivedClass() { result = getConversionClass(getExpr()) }
|
||||
|
||||
/**
|
||||
* Holds if this conversion is to a virtual base class.
|
||||
*/
|
||||
predicate isVirtual() { getDerivation().isVirtual() or not exists(getDerivation()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from a pointer or _glvalue_ to a base class to a pointer or _glvalue_
|
||||
* to a direct derived class.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class DerivedClassConversion extends InheritanceConversion {
|
||||
DerivedClassConversion() { conversionkinds(underlyingElement(this), 3) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "DerivedClassConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "derived class conversion" }
|
||||
|
||||
override Class getBaseClass() { result = getConversionClass(getExpr()) }
|
||||
|
||||
override Class getDerivedClass() { result = getConversionClass(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from a pointer-to-member of a derived class to a pointer-to-member
|
||||
* of an immediate base class.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class PointerToMemberBaseClassConversion extends Cast {
|
||||
PointerToMemberBaseClassConversion() { conversionkinds(underlyingElement(this), 4) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToMemberBaseClassConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() {
|
||||
result = "pointer-to-member base class conversion"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion from a pointer-to-member of a base class to a pointer-to-member
|
||||
* of an immediate derived class.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class PointerToMemberDerivedClassConversion extends Cast {
|
||||
PointerToMemberDerivedClassConversion() { conversionkinds(underlyingElement(this), 5) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToMemberDerivedClassConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() {
|
||||
result = "pointer-to-member derived class conversion"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A conversion of a _glvalue_ from one type to another. The conversion does not
|
||||
* modify the address of the _glvalue_. For _glvalue_ conversions involving base and
|
||||
* derived classes, see `BaseClassConversion` and `DerivedClassConversion`.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class GlvalueConversion extends Cast {
|
||||
GlvalueConversion() { conversionkinds(underlyingElement(this), 6) }
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" }
|
||||
|
||||
override string getSemanticConversionString() { result = "glvalue conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The adjustment of the type of a class _prvalue_. Most commonly seen in code
|
||||
* similar to:
|
||||
* ```
|
||||
* class String { ... };
|
||||
* String func();
|
||||
* void caller() {
|
||||
* const String& r = func();
|
||||
* }
|
||||
* ```
|
||||
* In the above example, the result of the call to `func` is a _prvalue_ of type
|
||||
* `String`, which will be adjusted to type `const String` before being bound
|
||||
* to the reference.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class PrvalueAdjustmentConversion extends Cast {
|
||||
PrvalueAdjustmentConversion() { conversionkinds(underlyingElement(this), 7) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not exists(qlCast(this)) and result = "PrvalueAdjustmentConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "prvalue adjustment conversion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `dynamic_cast` expression.
|
||||
*
|
||||
* Please see https://en.cppreference.com/w/cpp/language/dynamic_cast for
|
||||
* more information.
|
||||
* ```
|
||||
* struct T: S {};
|
||||
* struct S *s = get_S();
|
||||
* struct T *t = dynamic_cast<struct T *>(s); // downcast
|
||||
* ```
|
||||
*/
|
||||
class DynamicCast extends Cast, @dynamic_cast {
|
||||
override string toString() { result = "dynamic_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DynamicCast" }
|
||||
|
||||
override string getSemanticConversionString() { result = "dynamic_cast" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Microsoft C/C++ `__uuidof` expression that returns the UUID of a type, as
|
||||
* specified by the `__declspec(uuid)` attribute.
|
||||
* ```
|
||||
* struct UUID { char a[16]; };
|
||||
* struct __declspec(uuid("{01234567-89ab-cdef-0123-456789ABCDEF}")) S {};
|
||||
* UUID uuid = __uuidof(S);
|
||||
* ```
|
||||
*/
|
||||
class UuidofOperator extends Expr, @uuidof {
|
||||
override string toString() {
|
||||
if exists(getTypeOperand())
|
||||
then result = "__uuidof(" + getTypeOperand().getName() + ")"
|
||||
else result = "__uuidof(0)"
|
||||
}
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { uuidof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `typeid` expression which provides run-time type information (RTTI)
|
||||
* about its argument.
|
||||
*
|
||||
* Please see https://en.cppreference.com/w/cpp/language/typeid for more
|
||||
* information.
|
||||
* ```
|
||||
* Base *ptr = new Derived;
|
||||
* const std::type_info &info1 = typeid(ptr);
|
||||
* printf("the type of ptr is: %s\n", typeid(ptr).name());
|
||||
* ```
|
||||
*/
|
||||
class TypeidOperator extends Expr, @type_id {
|
||||
/**
|
||||
* Gets the type that is returned by this typeid expression.
|
||||
*/
|
||||
Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getResultType()` instead.
|
||||
*
|
||||
* Gets the type that is returned by this typeid expression.
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getResultType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeidOperator" }
|
||||
|
||||
/**
|
||||
* Gets the contained expression, if any (if this typeid contains
|
||||
* a type rather than an expression, there is no result).
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string toString() { result = "typeid ..." }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
override predicate mayBeImpure() { this.getExpr().mayBeImpure() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++11 `sizeof...` expression which determines the size of a template parameter pack.
|
||||
*
|
||||
* This expression only appears in templates themselves - in any actual
|
||||
* instantiations, "sizeof...(x)" will be replaced by its integer value.
|
||||
* ```
|
||||
* template < typename... T >
|
||||
* int count ( T &&... t ) { return sizeof... ( t ); }
|
||||
* ```
|
||||
*/
|
||||
class SizeofPackOperator extends Expr, @sizeof_pack {
|
||||
override string toString() { result = "sizeof...(...)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofPackOperator" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ sizeof expression.
|
||||
*/
|
||||
class SizeofOperator extends Expr, @runtime_sizeof {
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ sizeof expression whose operand is an expression.
|
||||
* ```
|
||||
* if (sizeof(a) == sizeof(b)) { c = (b)a; }
|
||||
* ```
|
||||
*/
|
||||
class SizeofExprOperator extends SizeofOperator {
|
||||
SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofExprOperator" }
|
||||
|
||||
/** Gets the contained expression. */
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getExprOperand()` instead
|
||||
*
|
||||
* Gets the contained expression.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getExprOperand() }
|
||||
|
||||
override string toString() { result = "sizeof(<expr>)" }
|
||||
|
||||
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { this.getExprOperand().mayBeGloballyImpure() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ sizeof expression whose operand is a type name.
|
||||
* ```
|
||||
* int szlong = sizeof(int) == sizeof(long)? 4 : 8;
|
||||
* ```
|
||||
*/
|
||||
class SizeofTypeOperator extends SizeofOperator {
|
||||
SizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofTypeOperator" }
|
||||
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getTypeOperand()` instead
|
||||
*
|
||||
* Gets the contained type.
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
|
||||
|
||||
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++11 `alignof` expression.
|
||||
*/
|
||||
class AlignofOperator extends Expr, @runtime_alignof {
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++11 `alignof` expression whose operand is an expression.
|
||||
* ```
|
||||
* int addrMask = ~(alignof(expr) - 1);
|
||||
* ```
|
||||
*/
|
||||
class AlignofExprOperator extends AlignofOperator {
|
||||
AlignofExprOperator() { exists(Expr e | this.getChild(0) = e) }
|
||||
|
||||
/**
|
||||
* Gets the contained expression.
|
||||
*/
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getExprOperand()` instead.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getExprOperand() }
|
||||
|
||||
override string toString() { result = "alignof(<expr>)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++11 `alignof` expression whose operand is a type name.
|
||||
* ```
|
||||
* bool proper_alignment = (alingof(T) == alignof(T[0]);
|
||||
* ```
|
||||
*/
|
||||
class AlignofTypeOperator extends AlignofOperator {
|
||||
AlignofTypeOperator() { sizeof_bind(underlyingElement(this), _) }
|
||||
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getTypeOperand()` instead.
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
|
||||
|
||||
override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ array to pointer conversion.
|
||||
*
|
||||
* The conversion is either implicit or underlies a particular cast.
|
||||
* Please see `CStyleCast`, `StaticCast`, `ConstCast`
|
||||
* or `ReinterpretCast` for more information.
|
||||
*/
|
||||
class ArrayToPointerConversion extends Conversion, @array_to_pointer {
|
||||
/** Gets a textual representation of this conversion. */
|
||||
override string toString() { result = "array to pointer conversion" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayToPointerConversion" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a temporary object created as part of an expression.
|
||||
*
|
||||
* This is most commonly seen in the following cases:
|
||||
* ```c++
|
||||
* // when binding a reference to a prvalue
|
||||
* const std::string& r = std::string("text");
|
||||
*
|
||||
* // when performing member access on a class prvalue
|
||||
* strlen(std::string("text").c_str());
|
||||
*
|
||||
* // when a prvalue of a type with a destructor is discarded
|
||||
* s.substr(0, 5); // Return value is discarded but requires destruction
|
||||
* ```
|
||||
*/
|
||||
class TemporaryObjectExpr extends Conversion, @temp_init {
|
||||
/** Gets a textual representation of this conversion. */
|
||||
override string toString() { result = "temporary object" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TemporaryObjectExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the Cast sub-class of entity `cast`.
|
||||
*/
|
||||
string qlCast(Cast cast) {
|
||||
// NB: Take care and include only leaf QL classes
|
||||
cast instanceof CStyleCast and result = "CStyleCast"
|
||||
or
|
||||
cast instanceof StaticCast and result = "StaticCast"
|
||||
or
|
||||
cast instanceof DynamicCast and result = "DynamicCast"
|
||||
or
|
||||
cast instanceof ConstCast and result = "ConstCast"
|
||||
or
|
||||
cast instanceof ReinterpretCast and result = "ReinterpretCast"
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the Conversion sub-class of entity `cast`.
|
||||
*/
|
||||
string qlConversion(Cast cast) {
|
||||
// NB: Take care and include only leaf QL classes
|
||||
cast instanceof IntegralConversion and result = "IntegralConversion"
|
||||
or
|
||||
cast instanceof FloatingPointConversion and result = "FloatingPointConversion"
|
||||
or
|
||||
cast instanceof FloatingPointToIntegralConversion and result = "FloatingPointToIntegralConversion"
|
||||
or
|
||||
cast instanceof IntegralToFloatingPointConversion and result = "IntegralToFloatingPointConversion"
|
||||
or
|
||||
cast instanceof PointerConversion and result = "PointerConversion"
|
||||
or
|
||||
cast instanceof PointerToMemberConversion and result = "PointerToMemberConversion"
|
||||
or
|
||||
cast instanceof PointerToIntegralConversion and result = "PointerToIntegralConversion"
|
||||
or
|
||||
cast instanceof IntegralToPointerConversion and result = "IntegralToPointerConversion"
|
||||
or
|
||||
cast instanceof BoolConversion and result = "BoolConversion"
|
||||
or
|
||||
cast instanceof VoidConversion and result = "VoidConversion"
|
||||
or
|
||||
cast instanceof BaseClassConversion and result = "BaseClassConversion"
|
||||
or
|
||||
cast instanceof DerivedClassConversion and result = "DerivedClassConversion"
|
||||
or
|
||||
cast instanceof PointerToMemberBaseClassConversion and
|
||||
result = "PointerToMemberBaseClassConversion"
|
||||
or
|
||||
cast instanceof PointerToMemberDerivedClassConversion and
|
||||
result = "PointerToMemberDerivedClassConversion"
|
||||
or
|
||||
cast instanceof GlvalueConversion and result = "GlvalueConversion"
|
||||
or
|
||||
cast instanceof PrvalueAdjustmentConversion and result = "PrvalueAdjustmentConversion"
|
||||
or
|
||||
// treat dynamic_cast<...>(...) as a conversion
|
||||
cast instanceof DynamicCast and result = "DynamicCast"
|
||||
}
|
||||
140
cpp/ql/lib/semmle/code/cpp/exprs/ComparisonOperation.qll
Normal file
140
cpp/ql/lib/semmle/code/cpp/exprs/ComparisonOperation.qll
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Provides classes for modeling comparisons such as `==`, `!=` and `<`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ comparison operation, that is, either an equality operation or a relational operation.
|
||||
*
|
||||
* This is a QL base class for all comparisons.
|
||||
*/
|
||||
class ComparisonOperation extends BinaryOperation, @cmp_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ equality operation, that is, either "==" or "!=".
|
||||
*/
|
||||
class EqualityOperation extends ComparisonOperation, @eq_op_expr {
|
||||
override int getPrecedence() { result = 9 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ equal expression.
|
||||
* ```
|
||||
* bool c = (a == b);
|
||||
* ```
|
||||
*/
|
||||
class EQExpr extends EqualityOperation, @eqexpr {
|
||||
override string getAPrimaryQlClass() { result = "EQExpr" }
|
||||
|
||||
override string getOperator() { result = "==" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ not equal expression.
|
||||
* ```
|
||||
* bool c = (a != b);
|
||||
* ```
|
||||
*/
|
||||
class NEExpr extends EqualityOperation, @neexpr {
|
||||
override string getAPrimaryQlClass() { result = "NEExpr" }
|
||||
|
||||
override string getOperator() { result = "!=" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ relational operation, that is, one of `<=`, `<`, `>`, or `>=`.
|
||||
*/
|
||||
class RelationalOperation extends ComparisonOperation, @rel_op_expr {
|
||||
override int getPrecedence() { result = 10 }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getGreaterOperand()` instead.
|
||||
*/
|
||||
deprecated Expr getLarge() { result = getGreaterOperand() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLesserOperand()` instead.
|
||||
*/
|
||||
deprecated Expr getSmall() { result = getLesserOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational expression, that is, the side that is larger
|
||||
* if the overall expression evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Expr getGreaterOperand() { none() } // overridden in subclasses
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational expression, that is, the side that is smaller
|
||||
* if the overall expression evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Expr getLesserOperand() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ greater than expression.
|
||||
* ```
|
||||
* bool c = (a > b);
|
||||
* ```
|
||||
*/
|
||||
class GTExpr extends RelationalOperation, @gtexpr {
|
||||
override string getAPrimaryQlClass() { result = "GTExpr" }
|
||||
|
||||
override string getOperator() { result = ">" }
|
||||
|
||||
override Expr getGreaterOperand() { result = getLeftOperand() }
|
||||
|
||||
override Expr getLesserOperand() { result = getRightOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ less than expression.
|
||||
* ```
|
||||
* bool c = (a < b);
|
||||
* ```
|
||||
*/
|
||||
class LTExpr extends RelationalOperation, @ltexpr {
|
||||
override string getAPrimaryQlClass() { result = "LTExpr" }
|
||||
|
||||
override string getOperator() { result = "<" }
|
||||
|
||||
override Expr getGreaterOperand() { result = getRightOperand() }
|
||||
|
||||
override Expr getLesserOperand() { result = getLeftOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ greater than or equal expression.
|
||||
* ```
|
||||
* bool c = (a >= b);
|
||||
* ```
|
||||
*/
|
||||
class GEExpr extends RelationalOperation, @geexpr {
|
||||
override string getAPrimaryQlClass() { result = "GEExpr" }
|
||||
|
||||
override string getOperator() { result = ">=" }
|
||||
|
||||
override Expr getGreaterOperand() { result = getLeftOperand() }
|
||||
|
||||
override Expr getLesserOperand() { result = getRightOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ less than or equal expression.
|
||||
* ```
|
||||
* bool c = (a <= b);
|
||||
* ```
|
||||
*/
|
||||
class LEExpr extends RelationalOperation, @leexpr {
|
||||
override string getAPrimaryQlClass() { result = "LEExpr" }
|
||||
|
||||
override string getOperator() { result = "<=" }
|
||||
|
||||
override Expr getGreaterOperand() { result = getRightOperand() }
|
||||
|
||||
override Expr getLesserOperand() { result = getLeftOperand() }
|
||||
}
|
||||
1331
cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll
Normal file
1331
cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll
Normal file
File diff suppressed because it is too large
Load Diff
153
cpp/ql/lib/semmle/code/cpp/exprs/Lambda.qll
Normal file
153
cpp/ql/lib/semmle/code/cpp/exprs/Lambda.qll
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Provides classes for modeling lambda expressions and their captures.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Class
|
||||
|
||||
/**
|
||||
* A C++11 lambda expression, for example the expression initializing `a` in
|
||||
* the following code:
|
||||
* ```
|
||||
* auto a = [x, y](int z) -> int {
|
||||
* return x + y + z;
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* The type given by `getType()` will be an instance of `Closure`.
|
||||
*/
|
||||
class LambdaExpression extends Expr, @lambdaexpr {
|
||||
override string toString() { result = "[...](...){...}" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LambdaExpression" }
|
||||
|
||||
/**
|
||||
* Gets an implicitly or explicitly captured value of this lambda expression.
|
||||
*/
|
||||
LambdaCapture getACapture() { result = getCapture(_) }
|
||||
|
||||
/**
|
||||
* Gets the nth implicitly or explicitly captured value of this lambda expression.
|
||||
*/
|
||||
LambdaCapture getCapture(int index) {
|
||||
lambda_capture(result, underlyingElement(this), index, _, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default variable capture mode for the lambda expression.
|
||||
*
|
||||
* Will be one of:
|
||||
* - "" if no default was specified, meaning that all captures must be explicit.
|
||||
* - "&" if capture-by-reference is the default for implicit captures.
|
||||
* - "=" if capture-by-value is the default for implicit captures.
|
||||
*/
|
||||
string getDefaultCaptureMode() { lambdas(underlyingElement(this), result, _) }
|
||||
|
||||
/**
|
||||
* Holds if the return type (of the call operator of the resulting object) was explicitly specified.
|
||||
*/
|
||||
predicate returnTypeIsExplicit() { lambdas(underlyingElement(this), _, true) }
|
||||
|
||||
/**
|
||||
* Gets the function which will be invoked when the resulting object is called.
|
||||
*
|
||||
* Various components of the lambda expression can be obtained from components of this
|
||||
* function, such as:
|
||||
* - The number and type of parameters.
|
||||
* - Whether the mutable keyword was used (iff this function is not const).
|
||||
* - The return type.
|
||||
* - The statements comprising the lambda body.
|
||||
*/
|
||||
Operator getLambdaFunction() { result = getType().(Closure).getLambdaFunction() }
|
||||
|
||||
/**
|
||||
* Gets the initializer that initializes the captured variables in the closure, if any.
|
||||
* A lambda that does not capture any variables will not have an initializer.
|
||||
*/
|
||||
ClassAggregateLiteral getInitializer() { result = getChild(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class written by the compiler to be the type of a C++11 lambda expression.
|
||||
* For example the variable `a` in the following code has a closure type:
|
||||
* ```
|
||||
* auto a = [x, y](int z) -> int {
|
||||
* return x + y + z;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class Closure extends Class {
|
||||
Closure() { exists(LambdaExpression e | this = e.getType()) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Closure" }
|
||||
|
||||
/** Gets the lambda expression of which this is the type. */
|
||||
LambdaExpression getLambdaExpression() { result.getType() = this }
|
||||
|
||||
/** Gets the compiler-generated operator() of this closure type. */
|
||||
Operator getLambdaFunction() {
|
||||
result = this.getAMember() and
|
||||
result.getName() = "operator()"
|
||||
}
|
||||
|
||||
override string getDescription() { result = "decltype([...](...){...})" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a value captured as part of a lambda expression. For
|
||||
* example in the following code, information about `x` and `y` is captured:
|
||||
* ```
|
||||
* auto a = [x, y](int z) -> int {
|
||||
* return x + y + z;
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class LambdaCapture extends Locatable, @lambdacapture {
|
||||
override string toString() { result = getField().getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LambdaCapture" }
|
||||
|
||||
/**
|
||||
* Holds if this capture was made implicitly.
|
||||
*/
|
||||
predicate isImplicit() { lambda_capture(this, _, _, _, _, true, _) }
|
||||
|
||||
/**
|
||||
* Holds if the variable was captured by reference.
|
||||
*
|
||||
* An identifier is captured by reference if:
|
||||
* - It is explicitly captured by reference.
|
||||
* - It is implicitly captured, and the lambda's default capture mode is by-reference.
|
||||
* - The identifier is "this". [Said behaviour is dictated by the C++11 standard, but it
|
||||
* is actually "*this" being captured rather than "this".]
|
||||
*/
|
||||
predicate isCapturedByReference() { lambda_capture(this, _, _, _, true, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the location of the declaration of this capture.
|
||||
*
|
||||
* For explicit captures, this is a location within the "[...]" part of the lambda expression.
|
||||
*
|
||||
* For implicit captures, this is the first location within the "{...}" part of the lambda
|
||||
* expression which accesses the captured variable.
|
||||
*/
|
||||
override Location getLocation() { lambda_capture(this, _, _, _, _, _, result) }
|
||||
|
||||
/**
|
||||
* Gets the field of the lambda expression's closure type which is used to store this capture.
|
||||
*/
|
||||
MemberVariable getField() { lambda_capture(this, _, _, result, _, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the expression which yields the final captured value.
|
||||
*
|
||||
* In many cases, this will be an instance of VariableAccess.
|
||||
* If a this-pointer is being captured, this will be an instance of ThisExpr.
|
||||
* For by-value captures of non-primitive types, this will be a call to a copy constructor.
|
||||
*/
|
||||
Expr getInitializer() {
|
||||
exists(LambdaExpression lambda | this = lambda.getCapture(_) |
|
||||
result = lambda.getInitializer().getFieldExpr(this.getField())
|
||||
)
|
||||
}
|
||||
}
|
||||
346
cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll
Normal file
346
cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll
Normal file
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Provides classes for modeling literals in the source code such as `0`, `'c'`
|
||||
* or `"string"`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ literal.
|
||||
*
|
||||
* The is the QL root class for all literals.
|
||||
*/
|
||||
class Literal extends Expr, @literal {
|
||||
/** Gets a textual representation of this literal. */
|
||||
override string toString() {
|
||||
result = this.getValue()
|
||||
or
|
||||
not exists(this.getValue()) and
|
||||
result = "Unknown literal"
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Literal" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A label literal, that is, a use of the '&&' operator to take the address of a
|
||||
* label for use in a computed goto statement. This is a non-standard C/C++ extension.
|
||||
*
|
||||
* For example:
|
||||
* ```
|
||||
* void *label_ptr = &&myLabel; // &&myLabel is a LabelLiteral
|
||||
* goto *label_ptr; // this is a ComputedGotoStmt
|
||||
* myLabel: // this is a LabelStmt
|
||||
* ```
|
||||
*/
|
||||
class LabelLiteral extends Literal {
|
||||
LabelLiteral() { jumpinfo(underlyingElement(this), _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LabelLiteral" }
|
||||
|
||||
/** Gets the corresponding label statement. */
|
||||
LabelStmt getLabel() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) }
|
||||
}
|
||||
|
||||
/** A character literal or a string literal. */
|
||||
class TextLiteral extends Literal {
|
||||
TextLiteral() {
|
||||
// String Literal
|
||||
// Note that `AggregateLiteral`s can also have an array type, but they derive from
|
||||
// @aggregateliteral rather than @literal.
|
||||
this.getType() instanceof ArrayType
|
||||
or
|
||||
// Char literal
|
||||
this.getValueText().regexpMatch("(?s)\\s*L?'.*")
|
||||
}
|
||||
|
||||
/** Gets a hex escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */
|
||||
string getAHexEscapeSequence(int occurrence, int offset) {
|
||||
result = getValueText().regexpFind("(?<!\\\\)\\\\x[0-9a-fA-F]+", occurrence, offset)
|
||||
}
|
||||
|
||||
/** Gets an octal escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */
|
||||
string getAnOctalEscapeSequence(int occurrence, int offset) {
|
||||
result = getValueText().regexpFind("(?<!\\\\)\\\\[0-7]{1,3}", occurrence, offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-standard escape sequence that appears in the character or string literal. This is one that has the
|
||||
* form of an escape sequence but is not one of the valid types of escape sequence in the C++ Standard.
|
||||
*/
|
||||
string getANonStandardEscapeSequence(int occurrence, int offset) {
|
||||
// Find all single character escape sequences (ignoring the start of octal escape sequences),
|
||||
// together with anything starting like a hex escape sequence but not followed by a hex digit.
|
||||
result = getValueText().regexpFind("\\\\[^x0-7\\s]|\\\\x[^0-9a-fA-F]", occurrence, offset) and
|
||||
// From these, exclude all standard escape sequences.
|
||||
not result = getAStandardEscapeSequence(_, _)
|
||||
}
|
||||
|
||||
/** Gets a simple escape sequence that appears in the char or string literal (see [lex.ccon] in the C++ Standard). */
|
||||
string getASimpleEscapeSequence(int occurrence, int offset) {
|
||||
result = getValueText().regexpFind("\\\\['\"?\\\\abfnrtv]", occurrence, offset)
|
||||
}
|
||||
|
||||
/** Gets a standard escape sequence that appears in the char or string literal (see [lex.ccon] in the C++ Standard). */
|
||||
string getAStandardEscapeSequence(int occurrence, int offset) {
|
||||
result = getASimpleEscapeSequence(occurrence, offset) or
|
||||
result = getAnOctalEscapeSequence(occurrence, offset) or
|
||||
result = getAHexEscapeSequence(occurrence, offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of the string literal (including null) before escape sequences added by the extractor.
|
||||
*/
|
||||
int getOriginalLength() { result = getValue().length() + 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A character literal. For example:
|
||||
* ```
|
||||
* char c1 = 'a';
|
||||
* wchar_t c2 = L'b';
|
||||
* ```
|
||||
*/
|
||||
class CharLiteral extends TextLiteral {
|
||||
CharLiteral() { this.getValueText().regexpMatch("(?s)\\s*L?'.*") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CharLiteral" }
|
||||
|
||||
/**
|
||||
* Gets the character of this literal. For example `L'a'` has character `"a"`.
|
||||
*/
|
||||
string getCharacter() { result = this.getValueText().regexpCapture("(?s)\\s*L?'(.*)'", 1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A string literal. For example:
|
||||
* ```
|
||||
* const char *s1 = "abcdef";
|
||||
* const wchar_t *s2 = L"123456";
|
||||
* ```
|
||||
*/
|
||||
class StringLiteral extends TextLiteral {
|
||||
StringLiteral() {
|
||||
this.getType() instanceof ArrayType
|
||||
// Note that `AggregateLiteral`s can also have an array type, but they derive from
|
||||
// @aggregateliteral rather than @literal.
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StringLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An octal literal. For example:
|
||||
* ```
|
||||
* char esc = 033;
|
||||
* ```
|
||||
* Octal literals must always start with the digit `0`.
|
||||
*/
|
||||
class OctalLiteral extends Literal {
|
||||
OctalLiteral() { super.getValueText().regexpMatch("\\s*0[0-7]+[uUlL]*\\s*") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OctalLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A hexadecimal literal.
|
||||
* ```
|
||||
* unsigned int32_t minus2 = 0xfffffffe;
|
||||
* ```
|
||||
*/
|
||||
class HexLiteral extends Literal {
|
||||
HexLiteral() { super.getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F]+[uUlL]*\\s*") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "HexLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ aggregate literal.
|
||||
*/
|
||||
class AggregateLiteral extends Expr, @aggregateliteral {
|
||||
override string getAPrimaryQlClass() { result = "AggregateLiteral" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead.
|
||||
*
|
||||
* Gets the expression within the aggregate literal that is used to initialise field `f`,
|
||||
* if this literal is being used to initialise a class/struct instance.
|
||||
*/
|
||||
deprecated Expr getCorrespondingExpr(Field f) {
|
||||
result = this.(ClassAggregateLiteral).getFieldExpr(f)
|
||||
}
|
||||
|
||||
override predicate mayBeImpure() { this.getAChild().mayBeImpure() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { this.getAChild().mayBeGloballyImpure() }
|
||||
|
||||
/** Gets a textual representation of this aggregate literal. */
|
||||
override string toString() { result = "{...}" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ aggregate literal that initializes a `class`, `struct`, or `union`.
|
||||
* For example:
|
||||
* ```
|
||||
* S s = { arg1, arg2, { arg3, arg4 }, arg5 };
|
||||
* ```
|
||||
*/
|
||||
class ClassAggregateLiteral extends AggregateLiteral {
|
||||
Class classType;
|
||||
|
||||
ClassAggregateLiteral() { classType = this.getUnspecifiedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" }
|
||||
|
||||
/**
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
* field `field`, if present.
|
||||
*/
|
||||
Expr getFieldExpr(Field field) {
|
||||
field = classType.getAField() and
|
||||
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the field `field` is initialized by this initializer list, either
|
||||
* explicitly with an expression, or implicitly value initialized.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isInitialized(Field field) {
|
||||
field = classType.getAField() and
|
||||
field.isInitializable() and
|
||||
(
|
||||
// If the field has an explicit initializer expression, then the field is
|
||||
// initialized.
|
||||
exists(getFieldExpr(field))
|
||||
or
|
||||
// If the type is not a union, all fields without initializers are value
|
||||
// initialized.
|
||||
not classType instanceof Union
|
||||
or
|
||||
// If the type is a union, and there are no explicit initializers, then
|
||||
// the first declared field is value initialized.
|
||||
not exists(getAChild()) and
|
||||
field.getInitializationOrder() = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the field `field` is value initialized because it is not
|
||||
* explicitly initialized by this initializer list.
|
||||
*
|
||||
* Value initialization (see [dcl.init]/8) recursively initializes all fields
|
||||
* of an object to `false`, `0`, `nullptr`, or by calling the default
|
||||
* constructor, as appropriate to the type.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isValueInitialized(Field field) {
|
||||
isInitialized(field) and
|
||||
not exists(getFieldExpr(field))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ aggregate literal that initializes an array or a GNU vector type.
|
||||
*/
|
||||
class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
|
||||
ArrayOrVectorAggregateLiteral() {
|
||||
exists(DerivedType type |
|
||||
type = this.getUnspecifiedType() and
|
||||
(
|
||||
type instanceof ArrayType or
|
||||
type instanceof GNUVectorType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of elements initialized by this initializer list, either explicitly with an
|
||||
* expression, or by implicit value initialization.
|
||||
*/
|
||||
int getArraySize() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the elements in the initializer list.
|
||||
*/
|
||||
Type getElementType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
* element `elementIndex`, if present.
|
||||
*/
|
||||
Expr getElementExpr(int elementIndex) {
|
||||
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the element `elementIndex` is initialized by this initializer
|
||||
* list, either explicitly with an expression, or implicitly value
|
||||
* initialized.
|
||||
*/
|
||||
bindingset[elementIndex]
|
||||
predicate isInitialized(int elementIndex) {
|
||||
elementIndex >= 0 and
|
||||
elementIndex < getArraySize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the element `elementIndex` is value initialized because it is not
|
||||
* explicitly initialized by this initializer list.
|
||||
*
|
||||
* Value initialization (see [dcl.init]/8) recursively initializes all fields
|
||||
* of an object to `false`, `0`, `nullptr`, or by calling the default
|
||||
* constructor, as appropriate to the type.
|
||||
*/
|
||||
bindingset[elementIndex]
|
||||
predicate isValueInitialized(int elementIndex) {
|
||||
isInitialized(elementIndex) and
|
||||
not exists(getElementExpr(elementIndex))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ aggregate literal that initializes an array
|
||||
* ```
|
||||
* S s[4] = { s_1, s_2, s_3, s_n };
|
||||
* ```
|
||||
*/
|
||||
class ArrayAggregateLiteral extends ArrayOrVectorAggregateLiteral {
|
||||
ArrayType arrayType;
|
||||
|
||||
ArrayAggregateLiteral() { arrayType = this.getUnspecifiedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayAggregateLiteral" }
|
||||
|
||||
override int getArraySize() { result = arrayType.getArraySize() }
|
||||
|
||||
override Type getElementType() { result = arrayType.getBaseType() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ aggregate literal that initializes a GNU vector type.
|
||||
*
|
||||
* Braced initializer lists are used, similarly to what is done
|
||||
* for arrays.
|
||||
* ```
|
||||
* typedef int v4si __attribute__ (( vector_size(4*sizeof(int)) ));
|
||||
* v4si v = (v4si){ 1, 2, 3, 4 };
|
||||
* typedef float float4 __attribute__((ext_vector_type(4)));
|
||||
* float4 vf = {1.0f, 2.0f, 3.0f, 4.0f};
|
||||
* ```
|
||||
*/
|
||||
class VectorAggregateLiteral extends ArrayOrVectorAggregateLiteral {
|
||||
GNUVectorType vectorType;
|
||||
|
||||
VectorAggregateLiteral() { vectorType = this.getUnspecifiedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VectorAggregateLiteral" }
|
||||
|
||||
override int getArraySize() { result = vectorType.getNumElements() }
|
||||
|
||||
override Type getElementType() { result = vectorType.getBaseType() }
|
||||
}
|
||||
131
cpp/ql/lib/semmle/code/cpp/exprs/LogicalOperation.qll
Normal file
131
cpp/ql/lib/semmle/code/cpp/exprs/LogicalOperation.qll
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Provides classes for modeling logical operations such as `!`, `&&`, `||`, and
|
||||
* the ternary `? :` expression.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ unary logical operation.
|
||||
*/
|
||||
class UnaryLogicalOperation extends UnaryOperation, @un_log_op_expr { }
|
||||
|
||||
/**
|
||||
* A C/C++ logical not expression.
|
||||
* ```
|
||||
* c = !a;
|
||||
* ```
|
||||
*/
|
||||
class NotExpr extends UnaryLogicalOperation, @notexpr {
|
||||
override string getOperator() { result = "!" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NotExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ binary logical operation.
|
||||
*/
|
||||
class BinaryLogicalOperation extends BinaryOperation, @bin_log_op_expr {
|
||||
/**
|
||||
* Holds if the truth of this binary logical expression having value `wholeIsTrue`
|
||||
* implies that the truth of the child expression `part` has truth value `partIsTrue`.
|
||||
*
|
||||
* For example if the binary operation:
|
||||
* ```
|
||||
* x && y
|
||||
* ```
|
||||
* is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and
|
||||
* `impliesValue(y, true, true)` hold.
|
||||
*/
|
||||
predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ logical AND expression.
|
||||
* ```
|
||||
* if (a && b) { }
|
||||
* ```
|
||||
*/
|
||||
class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr {
|
||||
override string getOperator() { result = "&&" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
|
||||
|
||||
override int getPrecedence() { result = 5 }
|
||||
|
||||
override predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) {
|
||||
wholeIsTrue = true and partIsTrue = true and part = this.getAnOperand()
|
||||
or
|
||||
wholeIsTrue = true and
|
||||
this.getAnOperand().(BinaryLogicalOperation).impliesValue(part, partIsTrue, true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ logical OR expression.
|
||||
* ```
|
||||
* if (a || b) { }
|
||||
* ```
|
||||
*/
|
||||
class LogicalOrExpr extends BinaryLogicalOperation, @orlogicalexpr {
|
||||
override string getOperator() { result = "||" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 4 }
|
||||
|
||||
override predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) {
|
||||
wholeIsTrue = false and partIsTrue = false and part = this.getAnOperand()
|
||||
or
|
||||
wholeIsTrue = false and
|
||||
this.getAnOperand().(BinaryLogicalOperation).impliesValue(part, partIsTrue, false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ conditional ternary expression.
|
||||
* ```
|
||||
* a = (b > c ? d : e);
|
||||
* ```
|
||||
*/
|
||||
class ConditionalExpr extends Operation, @conditionalexpr {
|
||||
/** Gets the condition of this conditional expression. */
|
||||
Expr getCondition() { expr_cond_guard(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConditionalExpr" }
|
||||
|
||||
/** Gets the 'then' expression of this conditional expression. */
|
||||
Expr getThen() {
|
||||
if this.isTwoOperand()
|
||||
then result = this.getCondition()
|
||||
else expr_cond_true(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
|
||||
/** Gets the 'else' expression of this conditional expression. */
|
||||
Expr getElse() { expr_cond_false(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Holds if this expression used the two operand form `guard ? : false`.
|
||||
*/
|
||||
predicate isTwoOperand() { expr_cond_two_operand(underlyingElement(this)) }
|
||||
|
||||
override string getOperator() { result = "?" }
|
||||
|
||||
override string toString() { result = "... ? ... : ..." }
|
||||
|
||||
override int getPrecedence() { result = 3 }
|
||||
|
||||
override predicate mayBeImpure() {
|
||||
this.getCondition().mayBeImpure() or
|
||||
this.getThen().mayBeImpure() or
|
||||
this.getElse().mayBeImpure()
|
||||
}
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
this.getCondition().mayBeGloballyImpure() or
|
||||
this.getThen().mayBeGloballyImpure() or
|
||||
this.getElse().mayBeGloballyImpure()
|
||||
}
|
||||
}
|
||||
297
cpp/ql/lib/semmle/code/cpp/exprs/ObjectiveC.qll
Normal file
297
cpp/ql/lib/semmle/code/cpp/exprs/ObjectiveC.qll
Normal file
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Class
|
||||
import semmle.code.cpp.ObjectiveC
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C message expression, for example `[myColor changeColorToRed:5.0 green:2.0 blue:6.0]`.
|
||||
*/
|
||||
deprecated class MessageExpr extends Expr, Call {
|
||||
MessageExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets the selector of this message expression, for example `-changeColorToRed:green:blue:`.
|
||||
*/
|
||||
string getSelector() { none() }
|
||||
|
||||
/**
|
||||
* Gets the function invoked by this message expression, as inferred by the compiler.
|
||||
*
|
||||
* If the compiler could infer the type of the receiver, and that type had a method
|
||||
* whose name matched the selector, then the result of this predicate is said method.
|
||||
* Otherwise this predicate has no result.
|
||||
*
|
||||
* In all cases, actual function dispatch isn't performed until runtime, but the
|
||||
* lack of a static target is often cause for concern.
|
||||
*/
|
||||
MemberFunction getStaticTarget() { none() }
|
||||
|
||||
/**
|
||||
* Provided for compatibility with Call. It is the same as the static target.
|
||||
*/
|
||||
override MemberFunction getTarget() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the compiler could infer a function as the target of this message.
|
||||
*
|
||||
* In all cases, actual function dispatch isn't performed until runtime, but the
|
||||
* lack of a static target is often cause for concern.
|
||||
*/
|
||||
predicate hasStaticTarget() { none() }
|
||||
|
||||
/**
|
||||
* Gets the number of arguments passed by this message expression.
|
||||
*
|
||||
* In most cases, this equals the number of colons in the selector, but this needn't be the
|
||||
* case for variadic methods like "-initWithFormat:", which can have more than one argument.
|
||||
*/
|
||||
override int getNumberOfArguments() { none() }
|
||||
|
||||
/**
|
||||
* Gets an argument passed by this message expression.
|
||||
*/
|
||||
override Expr getAnArgument() { none() }
|
||||
|
||||
/**
|
||||
* Gets the nth argument passed by this message expression.
|
||||
*
|
||||
* The range of `n` is [`0` .. `getNumberOfArguments()`].
|
||||
*/
|
||||
override Expr getArgument(int n) { none() }
|
||||
|
||||
override int getPrecedence() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C message expression whose receiver is `super`, for example `[super init]`.
|
||||
*/
|
||||
deprecated class SuperMessageExpr extends MessageExpr {
|
||||
SuperMessageExpr() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C message expression whose receiver is the name of a class, and
|
||||
* is therefore calling a class method rather than an instance method. This occurs
|
||||
* most commonly for the "+alloc", "+new", and "+class" selectors.
|
||||
*/
|
||||
deprecated class ClassMessageExpr extends MessageExpr {
|
||||
ClassMessageExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets the class which is the receiver of this message.
|
||||
*/
|
||||
Type getReceiver() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C message expression whose receiver is an expression (which includes the
|
||||
* common case of the receiver being "self").
|
||||
*/
|
||||
deprecated class ExprMessageExpr extends MessageExpr {
|
||||
ExprMessageExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression which gives the receiver of this message.
|
||||
*/
|
||||
Expr getReceiver() { none() }
|
||||
|
||||
/**
|
||||
* Gets the Objective C class of which the receiving expression is an instance.
|
||||
*
|
||||
* If the receiving expression has type `id` or type `id<P>` for some protocol `P`,
|
||||
* then there will be no result. If the receiving expression has type `C*` or type
|
||||
* `C<P>*` for some protocol `P`, then the result will be the type `C`.
|
||||
*/
|
||||
ObjectiveClass getReceiverClass() { none() }
|
||||
|
||||
/**
|
||||
* Gets the Objective C classes and/or protocols which are statically implemented
|
||||
* by the receiving expression.
|
||||
*
|
||||
* If the receiving expression has type `id`, then there will be no result.
|
||||
* If the receiving expression has type `id<P>`, then `P` will be the sole result.
|
||||
* If the receiving expression has type `C*`, then `C` will be the sole result.
|
||||
* If the receiving expression has type `C<P>*`, then `C` and `P` will both be results.
|
||||
*/
|
||||
Class getAReceiverClassOrProtocol() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An access to an Objective C property using dot syntax.
|
||||
*
|
||||
* Such accesses are de-sugared into a message expression to the property's getter or setter.
|
||||
*/
|
||||
deprecated class PropertyAccess extends ExprMessageExpr {
|
||||
PropertyAccess() { none() }
|
||||
|
||||
/**
|
||||
* Gets the property being accessed by this expression.
|
||||
*/
|
||||
Property getProperty() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@selector` expression, for example `@selector(driveForDistance:)`.
|
||||
*/
|
||||
deprecated class AtSelectorExpr extends Expr {
|
||||
AtSelectorExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets the selector of this `@selector` expression, for example `driveForDistance:`.
|
||||
*/
|
||||
string getSelector() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@protocol` expression, for example `@protocol(SomeProtocol)`.
|
||||
*/
|
||||
deprecated class AtProtocolExpr extends Expr {
|
||||
AtProtocolExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets the protocol of this `@protocol` expression, for example `SomeProtocol`.
|
||||
*/
|
||||
Protocol getProtocol() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@encode` expression, for example `@encode(int *)`.
|
||||
*/
|
||||
deprecated class AtEncodeExpr extends Expr {
|
||||
AtEncodeExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type this `@encode` expression encodes, for example `int *`.
|
||||
*/
|
||||
Type getEncodedType() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C throw expression.
|
||||
*/
|
||||
deprecated class ObjcThrowExpr extends ThrowExpr {
|
||||
ObjcThrowExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C throw expression with no argument (which causes the
|
||||
* current exception to be re-thrown).
|
||||
*/
|
||||
deprecated class ObjcReThrowExpr extends ReThrowExpr, ObjcThrowExpr {
|
||||
ObjcReThrowExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C @ expression which boxes a single value, such as @(22).
|
||||
*/
|
||||
deprecated class AtExpr extends UnaryOperation {
|
||||
AtExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
override string getOperator() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C @[...] literal.
|
||||
*/
|
||||
deprecated class ArrayLiteral extends Expr {
|
||||
ArrayLiteral() { none() }
|
||||
|
||||
/** Gets a textual representation of this array literal. */
|
||||
override string toString() { none() }
|
||||
|
||||
/** An element of the array */
|
||||
Expr getElement(int i) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C @{...} literal.
|
||||
*/
|
||||
deprecated class DictionaryLiteral extends Expr {
|
||||
DictionaryLiteral() { none() }
|
||||
|
||||
/** Gets a textual representation of this dictionary literal. */
|
||||
override string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C @"..." string literal.
|
||||
*/
|
||||
deprecated class ObjCLiteralString extends TextLiteral {
|
||||
ObjCLiteralString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C/C++ overloaded subscripting access expression.
|
||||
*
|
||||
* Either
|
||||
* obj[idx]
|
||||
* or
|
||||
* obj[idx] = expr
|
||||
*/
|
||||
deprecated class SubscriptExpr extends Expr {
|
||||
SubscriptExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets the object expression being subscripted.
|
||||
*/
|
||||
Expr getSubscriptBase() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression giving the index into the object.
|
||||
*/
|
||||
Expr getSubscriptIndex() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression being assigned (if this is an assignment).
|
||||
*/
|
||||
Expr getAssignedExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C _cmd expression.
|
||||
*/
|
||||
deprecated class CmdExpr extends Expr {
|
||||
CmdExpr() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
}
|
||||
Reference in New Issue
Block a user