mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
[CPP-418] Expressions.
This commit is contained in:
committed by
Geoffrey White
parent
1f337e943f
commit
e2d5a82735
@@ -5,6 +5,8 @@ private import semmle.code.cpp.internal.AddressConstantExpression
|
||||
|
||||
/**
|
||||
* A C/C++ expression.
|
||||
*
|
||||
* This is the root QL class for all expressions.
|
||||
*/
|
||||
class Expr extends StmtParent, @expr {
|
||||
/** Gets the nth child of this expression. */
|
||||
@@ -163,36 +165,36 @@ class Expr extends StmtParent, @expr {
|
||||
predicate mayBeGloballyImpure() { any() }
|
||||
|
||||
/**
|
||||
* Holds if this expression is an lvalue. An lvalue is an expression that
|
||||
* Holds if this expression is an *lvalue*. An *lvalue* is an expression that
|
||||
* represents a location, rather than a value.
|
||||
* See [basic.lval] for more about lvalues.
|
||||
*/
|
||||
predicate isLValueCategory() { expr_types(underlyingElement(this), _, 3) }
|
||||
|
||||
/**
|
||||
* Holds if this expression is an xvalue. An xvalue is a location whose
|
||||
* lifetime is about to end (e.g. an rvalue reference returned from a function
|
||||
* Holds if this expression is an *xvalue*. An *xvalue* is a location whose
|
||||
* lifetime is about to end (e.g. an *rvalue* reference returned from a function
|
||||
* call).
|
||||
* See [basic.lval] for more about xvalues.
|
||||
*/
|
||||
predicate isXValueCategory() { expr_types(underlyingElement(this), _, 2) }
|
||||
|
||||
/**
|
||||
* Holds if this expression is a prvalue. A prvalue is an expression that
|
||||
* Holds if this expression is a *prvalue*. A *prvalue* is an expression that
|
||||
* represents a value, rather than a location.
|
||||
* See [basic.lval] for more about prvalues.
|
||||
*/
|
||||
predicate isPRValueCategory() { expr_types(underlyingElement(this), _, 1) }
|
||||
|
||||
/**
|
||||
* Holds if this expression is a glvalue. A glvalue is either an lvalue or an
|
||||
* xvalue.
|
||||
* Holds if this expression is a glvalue. A glvalue is either an *lvalue* or an
|
||||
* *xvalue*.
|
||||
*/
|
||||
predicate isGLValueCategory() { isLValueCategory() or isXValueCategory() }
|
||||
|
||||
/**
|
||||
* Holds if this expression is an rvalue. An rvalue is either a prvalue or an
|
||||
* xvalue.
|
||||
* Holds if this expression is an *rvalue*. An *rvalue* is either a *prvalue* or an
|
||||
* *xvalue*.
|
||||
*/
|
||||
predicate isRValueCategory() { isPRValueCategory() or isXValueCategory() }
|
||||
|
||||
@@ -200,24 +202,24 @@ class Expr extends StmtParent, @expr {
|
||||
* Gets a string representation of the value category of the expression.
|
||||
* This is intended only for debugging. The possible values are:
|
||||
*
|
||||
* - "lvalue"
|
||||
* - "xvalue"
|
||||
* - "prvalue"
|
||||
* - "prvalue(load)"
|
||||
* - "*lvalue*"
|
||||
* - "*xvalue*"
|
||||
* - "*prvalue*"
|
||||
* - "*prvalue*(load)"
|
||||
*
|
||||
* The "prvalue(load)" string is used when the expression is a prvalue, but
|
||||
* `hasLValueToRvalueConversion()` holds.
|
||||
* The "*prvalue*(load)" string is used when the expression is a **prvalue**, but
|
||||
* **hasLValueToRvalueConversion()** holds.
|
||||
*/
|
||||
string getValueCategoryString() {
|
||||
isLValueCategory() and
|
||||
result = "lvalue"
|
||||
result = "*lvalue*"
|
||||
or
|
||||
isXValueCategory() and
|
||||
result = "xvalue"
|
||||
result = "*xvalue*"
|
||||
or
|
||||
(
|
||||
isPRValueCategory() and
|
||||
if hasLValueToRValueConversion() then result = "prvalue(load)" else result = "prvalue"
|
||||
if hasLValueToRValueConversion() then result = "*prvalue*(load)" else result = "*prvalue*"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -252,32 +254,32 @@ class Expr extends StmtParent, @expr {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression has undergone an lvalue-to-rvalue conversion to
|
||||
* Holds if this expression has undergone an *lvalue*-to-**rvalue** conversion to
|
||||
* extract its value.
|
||||
* for example:
|
||||
* ```
|
||||
* y = x;
|
||||
* ```
|
||||
* The VariableAccess for `x` is a prvalue, and hasLValueToRValueConversion()
|
||||
* The **VariableAccess** for `x` is a **prvalue**, and **hasLValueToRValueConversion()**
|
||||
* holds because the value of `x` was loaded from the location of `x`.
|
||||
* The VariableAccess for `y` is an lvalue, and hasLValueToRValueConversion()
|
||||
* The **VariableAccess** for `y` is an *lvalue*, and **hasLValueToRValueConversion()**
|
||||
* does not hold because the value of `y` was not extracted.
|
||||
*
|
||||
* See [conv.lval] for more about the lvalue-to-rvalue conversion
|
||||
* See [conv.lval] for more about the *lvalue*-to-**rvalue** conversion
|
||||
*/
|
||||
predicate hasLValueToRValueConversion() { expr_isload(underlyingElement(this)) }
|
||||
|
||||
/**
|
||||
* Holds if this expression is an LValue, in the sense of having an address.
|
||||
* Holds if this expression is an *lvalue*, in the sense of having an address.
|
||||
*
|
||||
* Being an LValue is best approximated as having an address.
|
||||
* This is a strict superset of modifiable LValues, which are best approximated by things which could be on the left-hand side of an assignment.
|
||||
* This is also a strict superset of expressions which provide an LValue, which is best approximated by things whose address is important.
|
||||
* Being an *lvalue* is best approximated as having an address.
|
||||
* This is a strict superset of modifiable *lvalue*s, which are best approximated by things which could be on the left-hand side of an assignment.
|
||||
* This is also a strict superset of expressions which provide an *lvalue*, which is best approximated by things whose address is important.
|
||||
*
|
||||
* See [basic.lval] in the C++ language specification.
|
||||
* In C++03, every expression is either an LValue or an RValue.
|
||||
* In C++11, every expression is exactly one of an LValue, an XValue, or a PRValue (with RValues being the union of XValues and PRValues).
|
||||
* Using the C++11 terminology, this predicate selects expressions whose value category is lvalue.
|
||||
* In C++03, every expression is either an *lvalue* or an *rvalue*.
|
||||
* In C++11, every expression is exactly one of an *lvalue*, an *xvalue*, or a *prvalue* (with *rvalue*s being the union of *xvalues* and *prvalue*s).
|
||||
* Using the C++11 terminology, this predicate selects expressions whose value category is *lvalue*.
|
||||
*/
|
||||
predicate isLValue() {
|
||||
// C++ n3337 - 5.1.1 clause 1
|
||||
@@ -509,7 +511,14 @@ abstract class BinaryOperation extends Operation {
|
||||
*
|
||||
* This is used to represent particular syntax within templates where the final
|
||||
* form of the expression is not known. In actual instantiations, it will have
|
||||
* been turned into a constructor call or aggregate initializer or similar.
|
||||
* been turned into either a constructor call or an aggregate initializer or similar.
|
||||
* ```
|
||||
* template <typename T>
|
||||
* struct S {
|
||||
* T member;
|
||||
* S() { member = T({ arg1, arg2 }); }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ParenthesizedBracedInitializerList extends Expr, @braced_init_list {
|
||||
override string toString() { result = "({...})" }
|
||||
@@ -519,6 +528,12 @@ class ParenthesizedBracedInitializerList extends Expr, @braced_init_list {
|
||||
|
||||
/**
|
||||
* A C/C++ parenthesis expression.
|
||||
*
|
||||
* It is typically used to raise the syntactic precedence of the subexpression that
|
||||
* it contains. For example:
|
||||
* ```
|
||||
* int d = a & ( b | c )
|
||||
* ```
|
||||
*/
|
||||
class ParenthesisExpr extends Conversion, @parexpr {
|
||||
override string toString() { result = "(...)" }
|
||||
@@ -528,6 +543,8 @@ class ParenthesisExpr extends Conversion, @parexpr {
|
||||
|
||||
/**
|
||||
* A C/C++ expression that has not been resolved.
|
||||
*
|
||||
* It is assigned **ErroneousType** as its type.
|
||||
*/
|
||||
class ErrorExpr extends Expr, @errorexpr {
|
||||
override string toString() { result = "<error expr>" }
|
||||
@@ -537,6 +554,12 @@ class ErrorExpr extends Expr, @errorexpr {
|
||||
|
||||
/**
|
||||
* A Microsoft C/C++ __assume expression.
|
||||
*
|
||||
* Unlike `assert`, `__assume` is evaluated at compile-time and
|
||||
* is treated as a hint to the optimizer
|
||||
* ```
|
||||
* __assume(ptr < end_buf);
|
||||
* ```
|
||||
*/
|
||||
class AssumeExpr extends Expr, @assume {
|
||||
override string toString() { result = "__assume(...)" }
|
||||
@@ -551,6 +574,9 @@ class AssumeExpr extends Expr, @assume {
|
||||
|
||||
/**
|
||||
* A C/C++ comma expression.
|
||||
* ```
|
||||
* int c = compute1(), compute2(), resulting_value;
|
||||
* ```
|
||||
*/
|
||||
class CommaExpr extends Expr, @commaexpr {
|
||||
override string getCanonicalQLClass() { result = "CommaExpr" }
|
||||
@@ -583,6 +609,9 @@ class CommaExpr extends Expr, @commaexpr {
|
||||
|
||||
/**
|
||||
* A C/C++ address-of expression.
|
||||
* ```
|
||||
* int *ptr = &var;
|
||||
* ```
|
||||
*/
|
||||
class AddressOfExpr extends UnaryOperation, @address_of {
|
||||
override string getCanonicalQLClass() { result = "AddressOfExpr" }
|
||||
@@ -605,11 +634,14 @@ class AddressOfExpr extends UnaryOperation, @address_of {
|
||||
}
|
||||
|
||||
/**
|
||||
* An implicit conversion from type T to type T&.
|
||||
* An implicit conversion from type `T` to type `T &`.
|
||||
*
|
||||
* This typically occurs when an expression of type T is used to initialize a variable or parameter of
|
||||
* type T&, and is to reference types what AddressOfExpr is to pointer types - though this class is
|
||||
* This typically occurs when an expression of type `T` is used to initialize a variable or parameter of
|
||||
* type `T &`, and is to reference types what **AddressOfExpr** is to pointer types, though this class is
|
||||
* considered to be a conversion rather than an operation, and as such doesn't occur in the main AST.
|
||||
* ```
|
||||
* int &var_ref = var;
|
||||
* ```
|
||||
*/
|
||||
class ReferenceToExpr extends Conversion, @reference_to {
|
||||
override string toString() { result = "(reference to)" }
|
||||
@@ -620,9 +652,12 @@ class ReferenceToExpr extends Conversion, @reference_to {
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of unary operator * applied to a built-in type.
|
||||
* An instance of the built-in unary `operator *` applied to a type.
|
||||
*
|
||||
* For user-defined types, see OverloadedPointerDereferenceExpr.
|
||||
* For user-defined overloads of `operator *`, see **OverloadedPointerDereferenceExpr**.
|
||||
* ```
|
||||
* int var = *varptr;
|
||||
* ```
|
||||
*/
|
||||
class PointerDereferenceExpr extends UnaryOperation, @indirect {
|
||||
override string getCanonicalQLClass() { result = "PointerDereferenceExpr" }
|
||||
@@ -650,11 +685,15 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect {
|
||||
}
|
||||
|
||||
/**
|
||||
* An implicit conversion from type T& to type T.
|
||||
* An implicit conversion from type `T &` to type `T`.
|
||||
*
|
||||
* This typically occurs when an variable of type T& is used in a context which expects type T, and
|
||||
* is to reference types what PointerDereferenceExpr is to pointer types - though this class is
|
||||
* This typically occurs when an variable of type `T &` is used in a context which expects type `T`, and
|
||||
* is to reference types what **PointerDereferenceExpr** is to pointer types - though this class is
|
||||
* considered to be a conversion rather than an operation, and as such doesn't occur in the main AST.
|
||||
* ```
|
||||
* float &f_ref = get_ref();
|
||||
* float f = f_ref;
|
||||
* ```
|
||||
*/
|
||||
class ReferenceDereferenceExpr extends Conversion, @ref_indirect {
|
||||
override string toString() { result = "(reference dereference)" }
|
||||
@@ -756,6 +795,9 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
|
||||
/**
|
||||
* A C++ `new` (non-array) expression.
|
||||
* ```
|
||||
* Foo *ptr = new Foo(3);
|
||||
* ```
|
||||
*/
|
||||
class NewExpr extends NewOrNewArrayExpr, @new_expr {
|
||||
override string toString() { result = "new" }
|
||||
@@ -782,6 +824,10 @@ class NewExpr extends NewOrNewArrayExpr, @new_expr {
|
||||
|
||||
/**
|
||||
* A C++ `new[]` (array) expression.
|
||||
* ```
|
||||
* Foo *foo = new Foo[]{1, 3, 5};
|
||||
* Bar *bar = new Bar[5];
|
||||
* ```
|
||||
*/
|
||||
class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
||||
override string toString() { result = "new[]" }
|
||||
@@ -827,6 +873,9 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
||||
|
||||
/**
|
||||
* A C++ `delete` (non-array) expression.
|
||||
* ```
|
||||
* delete ptr;
|
||||
* ```
|
||||
*/
|
||||
class DeleteExpr extends Expr, @delete_expr {
|
||||
override string toString() { result = "delete" }
|
||||
@@ -902,6 +951,9 @@ class DeleteExpr extends Expr, @delete_expr {
|
||||
|
||||
/**
|
||||
* A C++ `delete[]` (array) expression.
|
||||
* ```
|
||||
* delete[] arr;
|
||||
* ```
|
||||
*/
|
||||
class DeleteArrayExpr extends Expr, @delete_array_expr {
|
||||
override string toString() { result = "delete[]" }
|
||||
@@ -977,6 +1029,10 @@ class DeleteArrayExpr extends Expr, @delete_array_expr {
|
||||
|
||||
/**
|
||||
* A compound statement enclosed in parentheses used as an expression (a GNU extension to C/C++).
|
||||
* In the example below, `b` is the return value from the compound statement.
|
||||
* ```
|
||||
* int a = ({ int b = c + d; b; });
|
||||
* ```
|
||||
*/
|
||||
class StmtExpr extends Expr, @expr_stmt {
|
||||
override string toString() { result = "(statement expression)" }
|
||||
@@ -1006,7 +1062,7 @@ private Expr getStmtResultExpr(Stmt stmt) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ this expression.
|
||||
* The C++ `this` pointer.
|
||||
*/
|
||||
class ThisExpr extends Expr, @thisaccess {
|
||||
override string toString() { result = "this" }
|
||||
@@ -1019,8 +1075,10 @@ class ThisExpr extends Expr, @thisaccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* A code block expression, for example `^ int (int x, int y) {return x + y;}`.
|
||||
*
|
||||
* A code block expression, for example:
|
||||
* ```
|
||||
* ^ int (int x, int y) {return x + y;}
|
||||
* ```
|
||||
* Blocks are a language extension supported by Clang, and by Apple's
|
||||
* branch of GCC.
|
||||
*/
|
||||
@@ -1036,7 +1094,11 @@ class BlockExpr extends Literal {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++11 `noexcept` expression, for example `noexcept(1 + 2)`.
|
||||
* A C++11 `noexcept` expression, returning `true` if its subexpression is guaranteed
|
||||
* not to `throw` exceptions. For example:
|
||||
* ```
|
||||
* if (noexcept(func_1() + func_2())) { }
|
||||
* ```
|
||||
*/
|
||||
class NoExceptExpr extends Expr, @noexceptexpr {
|
||||
override string toString() { result = "noexcept(...)" }
|
||||
@@ -1052,6 +1114,10 @@ class NoExceptExpr extends Expr, @noexceptexpr {
|
||||
/**
|
||||
* A C++17 fold expression. This will only appear in an uninstantiated template; any instantiations
|
||||
* of the template will instead contain the sequence of expressions given by expanding the fold.
|
||||
* ```
|
||||
* template < typename... T >
|
||||
* auto sum ( T <20> t ) { return ( t + ... + 0 ); }
|
||||
* ```
|
||||
*/
|
||||
class FoldExpr extends Expr, @foldexpr {
|
||||
override string toString() {
|
||||
|
||||
Reference in New Issue
Block a user