Skip to content

Commit c4c4b97

Browse files
committed
unified: Fix enclosing callable of capture declarations
1 parent 7ded08c commit c4c4b97

4 files changed

Lines changed: 28 additions & 6 deletions

File tree

unified/ql/lib/codeql/unified/internal/FacadeAst.qll

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,23 @@ module Unified {
3333
)
3434
}
3535

36+
private AstNode overrideEnclosingCallableParent() {
37+
exists(FunctionExpr func |
38+
// Capture declarations are evaluated as part of the outer context, and
39+
// considered to be captured by the function expression.
40+
this = func.getACaptureDeclaration() and
41+
result = func.getParent()
42+
)
43+
}
44+
3645
/** Gets the nearest callable containing this AST node. */
3746
Callable getEnclosingCallable() {
38-
exists(AstNode parent | parent = this.getParent() |
47+
exists(AstNode parent |
48+
parent = this.overrideEnclosingCallableParent()
49+
or
50+
not exists(this.overrideEnclosingCallableParent()) and
51+
parent = this.getParent()
52+
|
3953
result = parent
4054
or
4155
not parent instanceof Callable and

unified/ql/test/library-tests/local-name-binding/self_access.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ class C {
1010
}
1111

1212
func t3() { // implicit-self=t3.self
13-
foo(123) { [self] in // name=closure.self
13+
foo(123) { [self] in // $ captured=closure.self // name=closure.self
1414
print(self) // $ access=closure.self
1515
print(instanceField) // $ access=instanceField implicit-qualifier=closure.self
1616
}
1717
}
1818

1919
func t4() { // implicit-self=t4.self
20-
foo(123) { [weak self] in // name=weak.self
20+
foo(123) { [weak self] in // $ captured=weak.self // name=weak.self
2121
// Here, 'self' is an Option<C> referring to .some(<outer self>) if it
2222
// has not been GC'ed yet. Swift does not allow unqualified self access here.
2323

unified/ql/test/library-tests/local-name-binding/test.ql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import utils.test.CommentUtil
44
import codeql.unified.internal.LocalNameBinding
55

66
module VariableAccessTest implements TestSig {
7-
string getARelevantTag() { result = ["access", "implicit-qualifier"] }
7+
string getARelevantTag() { result = ["access", "implicit-qualifier", "captured"] }
88

99
additional predicate declAt(LocalName v, string filepath, int line) {
1010
v.getLocation().hasLocationInfo(filepath, line, _, _, _)
@@ -51,6 +51,14 @@ module VariableAccessTest implements TestSig {
5151
access.isInstanceAccess() and // For now, don't annotate receiver access in static methods. It technically exists, it's just not important yet.
5252
tag = "implicit-qualifier"
5353
)
54+
or
55+
exists(LocalVariable v |
56+
v.isCaptured() and
57+
location = v.getLocation() and
58+
element = v.toString() and
59+
decl(v, value) and
60+
tag = "captured"
61+
)
5462
}
5563
}
5664

unified/ql/test/library-tests/local-name-binding/test.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func t16() throws {
135135

136136
// Closure captures
137137
func t17() {
138-
let x = 1 // name=x1
138+
let x = 1 // $ captured=x1 // name=x1
139139
let closure = { // name=closure1
140140
print(x) // $ access=x1
141141
}
@@ -181,7 +181,7 @@ func t21() {
181181
// Nested functions
182182
func t22() {
183183
let x = 1 // name=x1
184-
func inner() { // name=inner1
184+
func inner() { // $ captured=inner1 // name=inner1
185185
let x = 2 // name=x2
186186
print(x) // $ access=x2
187187
}

0 commit comments

Comments
 (0)