-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathLambda.qll
More file actions
158 lines (136 loc) · 5.36 KB
/
Lambda.qll
File metadata and controls
158 lines (136 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/**
* 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 = this.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, _) }
/**
* Holds if the lambda has an explicitly specified parameter list, even when empty.
*/
predicate hasParameterList() { 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 = this.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 = this.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 = this.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 behavior 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().getAFieldExpr(this.getField())
)
}
}