Skip to content

Commit 9b7e129

Browse files
committed
Scope: Special case lambda expressions
Lambda expressions have special visibility rules that affect identifier hiding, which we incorporate into the Scope hiding calculations. Note: Lambda expressions are not currently tied into the parent scope hierarchy, so this change doesn't affect calculations until getParentScope(Element e) is extended to support them.
1 parent 47b3fb2 commit 9b7e129

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

cpp/common/src/codingstandards/cpp/Scope.qll

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
*/
44

55
import cpp
6+
import codingstandards.cpp.ConstHelpers
7+
8+
/**
9+
* a `Variable` that is nonvolatile and const
10+
* and of type `IntegralOrEnumType`
11+
*/
12+
class NonVolatileConstIntegralOrEnumVariable extends Variable {
13+
NonVolatileConstIntegralOrEnumVariable() {
14+
not this.isVolatile() and
15+
this.isConst() and
16+
this.getUnspecifiedType() instanceof IntegralOrEnumType
17+
}
18+
}
619

720
/**
821
* Internal module, exposed for testing.
@@ -210,6 +223,52 @@ class Scope extends Element {
210223
}
211224
}
212225

226+
/**
227+
* A scope representing the generated `operator()` of a lambda function.
228+
*/
229+
class LambdaScope extends Scope {
230+
Closure closure;
231+
232+
LambdaScope() { this = closure.getLambdaFunction() }
233+
234+
override UserVariable getAVariableHiddenByThisOrNestedScope(string name) {
235+
// Handle special cases for lambdas
236+
exists(UserVariable hiddenVariable, LambdaExpression lambdaExpr |
237+
// Find the variable that is potentially hidden inside the lambda
238+
hiddenVariable = super.getAVariableHiddenByThisOrNestedScope(name) and
239+
result = hiddenVariable and
240+
lambdaExpr = closure.getLambdaExpression()
241+
|
242+
// A definition can be hidden if it is in scope and it is captured by the lambda,
243+
exists(LambdaCapture cap |
244+
lambdaExpr.getACapture() = cap and
245+
// The outer declaration is captured by the lambda
246+
hiddenVariable.getAnAccess() = cap.getInitializer()
247+
)
248+
or
249+
// it is is non-local,
250+
hiddenVariable instanceof GlobalVariable
251+
or
252+
// it has static or thread local storage duration,
253+
(hiddenVariable.isThreadLocal() or hiddenVariable.isStatic())
254+
or
255+
//it is a reference that has been initialized with a constant expression.
256+
hiddenVariable.getType().stripTopLevelSpecifiers() instanceof ReferenceType and
257+
hiddenVariable.getInitializer().getExpr() instanceof Literal
258+
or
259+
// //it const non-volatile integral or enumeration type and has been initialized with a constant expression
260+
hiddenVariable instanceof NonVolatileConstIntegralOrEnumVariable and
261+
hiddenVariable.getInitializer().getExpr() instanceof Literal
262+
or
263+
//it is constexpr and has no mutable members
264+
hiddenVariable.isConstexpr() and
265+
not exists(Class c |
266+
c = hiddenVariable.getType() and not c.getAMember() instanceof MutableVariable
267+
)
268+
)
269+
}
270+
}
271+
213272
class GeneratedBlockStmt extends BlockStmt {
214273
GeneratedBlockStmt() { this.getLocation() instanceof UnknownLocation }
215274
}

0 commit comments

Comments
 (0)