Skip to content

Commit 2dfc953

Browse files
committed
Unified: Handle self/Self
1 parent c364999 commit 2dfc953

6 files changed

Lines changed: 84 additions & 2 deletions

File tree

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,7 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig<Locatio
323323
}
324324

325325
predicate implicitDeclInScope(string name, AstNode scope) {
326-
none()
327-
// TODO: self
326+
any(NameBindingPlugin p).implicitLocalDeclInScope(scope, name)
328327
}
329328

330329
predicate accessCand(AstNode n, string name) { n.(PotentialLocalNameAccess).getName() = name }

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
private import unified
2+
private import StaticNameBinding
23
private import codeql.util.Unit
34
private import codeql.unified.internal.NameBindingPluginSwift // ensure overrides are seen
45

@@ -39,6 +40,19 @@ class NameBindingPlugin extends Unit {
3940
*/
4041
bindingset[cls, member]
4142
predicate isInheritableMember(ClassLikeDeclaration cls, Member member) { none() }
43+
44+
/**
45+
* Holds if there is an implicit local declaration with the given `name` in the given `scope`.
46+
*/
47+
predicate implicitLocalDeclInScope(AstNode scope, string name) { none() }
48+
49+
/**
50+
* Holds if there is an additional store step from `node1` to `node2` with the given `name`
51+
* in the name-binding graph.
52+
*/
53+
predicate additionalStoreStep(NameBindingNode node1, string name, NameBindingNode node2) {
54+
none()
55+
}
4256
}
4357

4458
/** Holds if `member` is an instance member. */

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
private import unified
66
private import codeql.unified.internal.NameBindingPlugin
7+
private import codeql.unified.internal.StaticNameBinding
78

89
class NameBindingPluginSwift extends NameBindingPlugin {
910
bindingset[e]
@@ -38,6 +39,23 @@ class NameBindingPluginSwift extends NameBindingPlugin {
3839
exists(cls) and
3940
not member.hasModifier("private")
4041
}
42+
43+
override predicate implicitLocalDeclInScope(AstNode scope, string name) {
44+
exists(ClassLikeDeclaration cls, FunctionDeclaration f |
45+
f = cls.getAMember() and
46+
this.isInstanceMember(cls, f) and
47+
scope = f.getBody() and
48+
name = "self"
49+
)
50+
}
51+
52+
override predicate additionalStoreStep(NameBindingNode node1, string name, NameBindingNode node2) {
53+
exists(ClassLikeDeclaration cls |
54+
name = ["self", "Self"] and
55+
node1.isIdentifier(cls.getNameNode()) and
56+
node2.isStaticMemberNamespace(cls)
57+
)
58+
}
4159
}
4260

4361
/** Holds if `node` is in a context where a bare name node should be seen as a reference rather than a declaration. */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ predicate storeStep(NameBindingNode node1, string name, NameBindingNode node2) {
210210
)
211211
or
212212
FolderHeuristic::storeStep(node1, name, node2)
213+
or
214+
any(NameBindingPlugin p).additionalStoreStep(node1, name, node2)
213215
}
214216

215217
predicate valueStep(NameBindingNode node1, NameBindingNode node2) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class A {
77
}
88
func instance_before() {
99
print(instanceVar) // $ access=instanceVar
10+
print(self.instanceVar) // $ access=self
1011
B(); // $ access=A.B
1112
let b: B = nil // $ access=A.B
1213
let c: C = nil // $ access=A.C
@@ -27,6 +28,7 @@ class A {
2728
}
2829
func instance_after() {
2930
print(instanceVar) // $ access=instanceVar
31+
print(self.instanceVar) // $ access=self
3032
B(); // $ access=A.B
3133
let b: B = nil // $ access=A.B
3234
let c: C = nil // $ access=A.C
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
private class A {
2+
let x = 123 // name=A.instance.x
3+
4+
func getX() {
5+
return self.x // not handled by static name binding
6+
}
7+
8+
static let y = 456 // name=A.type.y
9+
10+
func getY1() {
11+
return Self.y // $ access=A access=A.type.y
12+
}
13+
14+
static func getY2() {
15+
return self.y // $ access=A access=A.type.y
16+
}
17+
18+
class func z() -> Int { // name=A.type.z
19+
return 789
20+
}
21+
22+
class func getZ() {
23+
return self.z // $ access=A access=A.type.z
24+
}
25+
}
26+
27+
private class B : A { // $ access=A
28+
func getX2() {
29+
return self.x // not handled by static name binding
30+
}
31+
32+
func getY3() {
33+
return Self.y // $ access=B access=A.type.y
34+
}
35+
36+
static func getY4() {
37+
return self.y // $ access=B access=A.type.y
38+
}
39+
40+
class func z() -> Int { // name=B.type.z
41+
return 789
42+
}
43+
44+
class func getZ2() {
45+
return self.z // $ access=B access=B.type.z
46+
}
47+
}

0 commit comments

Comments
 (0)