mirror of
https://github.com/github/codeql.git
synced 2025-12-17 09:13:20 +01:00
Merge pull request #1925 from geoffw0/qldoceg10
CPP: Add syntax examples to QLDoc in Access.qll, Declaration.qll
This commit is contained in:
@@ -14,8 +14,12 @@ private import semmle.code.cpp.internal.QualifiedName as Q
|
||||
* ```
|
||||
* extern int myglobal;
|
||||
* ```
|
||||
* Each of these declarations is given its own distinct `DeclarationEntry`,
|
||||
* but they all share the same `Declaration`.
|
||||
* and defined in one:
|
||||
* ```
|
||||
* int myglobal;
|
||||
* ```
|
||||
* Each of these declarations (including the definition) is given its own
|
||||
* distinct `DeclarationEntry`, but they all share the same `Declaration`.
|
||||
*
|
||||
* Some derived class of `Declaration` do not have a corresponding
|
||||
* `DeclarationEntry`, because they always have a unique source location.
|
||||
@@ -206,9 +210,19 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ declaration entry. See the comment above `Declaration` for an
|
||||
* explanation of the relationship between `Declaration` and
|
||||
* `DeclarationEntry`.
|
||||
* A C/C++ declaration entry. For example the following code contains five
|
||||
* declaration entries:
|
||||
* ```
|
||||
* extern int myGlobal;
|
||||
* int myVariable;
|
||||
* typedef char MyChar;
|
||||
* void myFunction();
|
||||
* void myFunction() {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
* See the comment above `Declaration` for an explanation of the relationship
|
||||
* between `Declaration` and `DeclarationEntry`.
|
||||
*/
|
||||
abstract class DeclarationEntry extends Locatable {
|
||||
/** Gets a specifier associated with this declaration entry. */
|
||||
@@ -281,8 +295,19 @@ abstract class DeclarationEntry extends Locatable {
|
||||
* A declaration that can potentially have more C++ access rights than its
|
||||
* enclosing element. This comprises `Class` (they have access to their own
|
||||
* private members) along with other `UserType`s and `Function` (they can be
|
||||
* the target of `friend` declarations).
|
||||
* the target of `friend` declarations). For example `MyClass` and
|
||||
* `myFunction` in the following code:
|
||||
* ```
|
||||
* class MyClass
|
||||
* {
|
||||
* public:
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* void myFunction() {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
* In the C++ standard (N4140 11.2), rules for access control revolve around
|
||||
* the informal phrase "_R_ occurs in a member or friend of class C", where
|
||||
* `AccessHolder` corresponds to this _R_.
|
||||
@@ -416,8 +441,19 @@ abstract class AccessHolder extends Declaration {
|
||||
/**
|
||||
* A declaration that very likely has more C++ access rights than its
|
||||
* enclosing element. This comprises `Class` (they have access to their own
|
||||
* private members) along with any target of a `friend` declaration.
|
||||
* private members) along with any target of a `friend` declaration. For
|
||||
* example `MyClass` and `friendFunction` in the following code:
|
||||
* ```
|
||||
* class MyClass
|
||||
* {
|
||||
* public:
|
||||
* friend void friendFunction();
|
||||
* };
|
||||
*
|
||||
* void friendFunction() {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
* Most access rights are computed for `DirectAccessHolder` instead of
|
||||
* `AccessHolder` -- that's more efficient because there are fewer
|
||||
* `DirectAccessHolder`s. If a `DirectAccessHolder` contains an `AccessHolder`,
|
||||
|
||||
@@ -18,7 +18,18 @@ abstract class Access extends Expr, NameQualifiableElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ enum constant access expression.
|
||||
* 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 getCanonicalQLClass() { result = "EnumConstantAccess" }
|
||||
@@ -27,15 +38,23 @@ class EnumConstantAccess extends Access, @varaccess {
|
||||
exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
|
||||
}
|
||||
|
||||
/** Gets the accessed enum constant. */
|
||||
/** Gets the accessed `enum` constant. */
|
||||
override EnumConstant getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/** Gets a textual representation of this enum constant access. */
|
||||
/** Gets a textual representation of this `enum` constant access. */
|
||||
override string toString() { result = this.getTarget().getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ variable access expression.
|
||||
* 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 getCanonicalQLClass() { result = "VariableAccess" }
|
||||
@@ -129,7 +148,18 @@ class VariableAccess extends Access, @varaccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ field access expression.
|
||||
* 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 getCanonicalQLClass() { result = "FieldAccess" }
|
||||
@@ -141,8 +171,23 @@ class FieldAccess extends VariableAccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access of the form `obj->field`. The type of `obj` is a pointer,
|
||||
* so this is equivalent to `(*obj).field`.
|
||||
* 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 getCanonicalQLClass() { result = "PointerFieldAccess" }
|
||||
@@ -169,7 +214,18 @@ class DotFieldAccess extends FieldAccess {
|
||||
|
||||
/**
|
||||
* A field access of the form `obj.field`, where the type of `obj` is a
|
||||
* reference to a class/struct/union.
|
||||
* 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 getCanonicalQLClass() { result = "ReferenceFieldAccess" }
|
||||
@@ -179,7 +235,18 @@ class ReferenceFieldAccess extends DotFieldAccess {
|
||||
|
||||
/**
|
||||
* A field access of the form `obj.field`, where the type of `obj` is a
|
||||
* class/struct/union (and not a reference).
|
||||
* 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 getCanonicalQLClass() { result = "ValueFieldAccess" }
|
||||
@@ -198,25 +265,40 @@ private predicate referenceConversion(Conversion c) {
|
||||
/**
|
||||
* 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`. The access has no qualifier because
|
||||
* the use of `this` is implicit. For example, `field` is equivalent to
|
||||
* `this->field` if `field` is a member of `this`.
|
||||
* 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 implicit accesses of `this->field` are instances
|
||||
* `this->field`, so most accesses of `this->field` are instances
|
||||
* of `PointerFieldAccess` (with `ThisExpr` as the qualifier), not
|
||||
* `ImplicitThisFieldAccess`.
|
||||
*/
|
||||
@@ -250,7 +332,15 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ function access expression.
|
||||
* 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) = &myTarget;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class FunctionAccess extends Access, @routineexpr {
|
||||
FunctionAccess() { not iscall(underlyingElement(this), _) }
|
||||
@@ -269,7 +359,7 @@ class FunctionAccess extends Access, @routineexpr {
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to a parameter of a function signature for the purposes of a decltype.
|
||||
* An access to a parameter of a function signature for the purposes of a `decltype`.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```
|
||||
@@ -279,7 +369,7 @@ class FunctionAccess extends Access, @routineexpr {
|
||||
* }
|
||||
* ```
|
||||
* The return type of the function is a decltype, the expression of which contains
|
||||
* an add expression, which in turn has two ParamAccessForType children.
|
||||
* an add expression, which in turn has two `ParamAccessForType` children.
|
||||
*/
|
||||
class ParamAccessForType extends Expr, @param_ref {
|
||||
override string toString() { result = "param access" }
|
||||
@@ -287,7 +377,22 @@ class ParamAccessForType extends Expr, @param_ref {
|
||||
|
||||
/**
|
||||
* An access to a type. This occurs in certain contexts where a built-in
|
||||
* works on types directly rather than variables, expressions etc.
|
||||
* 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 getCanonicalQLClass() { result = "TypeName" }
|
||||
@@ -296,9 +401,17 @@ class TypeName extends Expr, @type_operand {
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ array access expression.
|
||||
* A C/C++ array access expression. For example, the access to `as` in
|
||||
* `myFunction` in the following code:
|
||||
* ```
|
||||
* int as[10];
|
||||
*
|
||||
* For calls to operator[], which look syntactically identical, see OverloadedArrayExpr.
|
||||
* void myFunction() {
|
||||
* as[0]++;
|
||||
* }
|
||||
* ```
|
||||
* For calls to `operator[]`, which look syntactically identical, see
|
||||
* `OverloadedArrayExpr`.
|
||||
*/
|
||||
class ArrayExpr extends Expr, @subscriptexpr {
|
||||
override string getCanonicalQLClass() { result = "ArrayExpr" }
|
||||
@@ -306,14 +419,14 @@ class ArrayExpr extends Expr, @subscriptexpr {
|
||||
/**
|
||||
* Gets the array or pointer expression being subscripted.
|
||||
*
|
||||
* This is arr in both arr[0] and 0[arr].
|
||||
* 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].
|
||||
* This is `0` in both `arr[0]` and `0[arr]`.
|
||||
*/
|
||||
Expr getArrayOffset() { result = this.getChild(1) }
|
||||
|
||||
|
||||
@@ -1645,6 +1645,7 @@ class EnumSwitch extends SwitchStmt {
|
||||
* } catch (std::exception &e) {
|
||||
* g();
|
||||
* }
|
||||
* ```
|
||||
* there is a handler that's associated with the `catch` block and controls
|
||||
* entry to it.
|
||||
*/
|
||||
|
||||
@@ -84,3 +84,34 @@ int test_val00(S s) {
|
||||
int test_val01(U u) {
|
||||
return u.x;
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
public:
|
||||
void myMethod(MyClass a, MyClass &b, MyClass *c) {
|
||||
a.x = b.y; // val, ref
|
||||
c->x = y; // ptr, ptr
|
||||
c->x = this->y; // ptr, ptr
|
||||
(&b)->y = (*c).y; // ptr, val
|
||||
}
|
||||
|
||||
int x, y;
|
||||
};
|
||||
|
||||
class MyHasDestructor1 {
|
||||
public:
|
||||
~MyHasDestructor1() {
|
||||
// ...
|
||||
}
|
||||
};
|
||||
|
||||
class MyHasDestructor2 {
|
||||
public:
|
||||
int x;
|
||||
MyHasDestructor1 v;
|
||||
|
||||
~MyHasDestructor2() {
|
||||
x++; // PointerFieldAccess, the `this->` is generated rather than implicit.
|
||||
|
||||
// ImplicitThisFieldAccess on call `v`s destructor.
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,3 +16,13 @@
|
||||
| FieldAccess.cpp:77:12:77:13 | x1 | ref |
|
||||
| FieldAccess.cpp:81:12:81:13 | x1 | val |
|
||||
| FieldAccess.cpp:85:12:85:12 | x | val |
|
||||
| FieldAccess.cpp:91:7:91:7 | x | val |
|
||||
| FieldAccess.cpp:91:13:91:13 | y | ref |
|
||||
| FieldAccess.cpp:92:8:92:8 | x | ptr |
|
||||
| FieldAccess.cpp:92:12:92:12 | y | ptr |
|
||||
| FieldAccess.cpp:93:8:93:8 | x | ptr |
|
||||
| FieldAccess.cpp:93:18:93:18 | y | ptr |
|
||||
| FieldAccess.cpp:94:11:94:11 | y | ptr |
|
||||
| FieldAccess.cpp:94:20:94:20 | y | val |
|
||||
| FieldAccess.cpp:113:5:113:5 | x | ptr |
|
||||
| FieldAccess.cpp:116:3:116:3 | v | this |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
int myTarget(int);
|
||||
|
||||
int call(int (*target)(int), int val) {
|
||||
return target(val);
|
||||
}
|
||||
|
||||
void testFunctionAccess() {
|
||||
int (*myFunctionPointer)(int) = &myTarget; // FunctionAccess
|
||||
|
||||
call(myFunctionPointer, 1);
|
||||
call(myTarget, 2); // FunctionAccess
|
||||
(&myTarget)(3); // FunctionAccess
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
| FunctionAccess.cpp:9:36:9:43 | myTarget | FunctionAccess.cpp:2:5:2:12 | myTarget |
|
||||
| FunctionAccess.cpp:12:8:12:15 | myTarget | FunctionAccess.cpp:2:5:2:12 | myTarget |
|
||||
| FunctionAccess.cpp:13:5:13:12 | myTarget | FunctionAccess.cpp:2:5:2:12 | myTarget |
|
||||
@@ -0,0 +1,4 @@
|
||||
import cpp
|
||||
|
||||
from FunctionAccess fa
|
||||
select fa, fa.getTarget()
|
||||
Reference in New Issue
Block a user