Skip to content

Commit 96ee0f6

Browse files
authored
Merge pull request github#11935 from geoffw0/protocol-extension
Swift: Flow sources through protocol extensions
2 parents bc36a75 + b9d487a commit 96ee0f6

File tree

4 files changed

+110
-26
lines changed

4 files changed

+110
-26
lines changed

swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -424,33 +424,53 @@ private Element interpretElement0(
424424
)
425425
or
426426
// Member functions
427-
exists(NominalTypeDecl nomTypeDecl, Decl decl, MethodDecl method |
427+
exists(NominalTypeDecl namedTypeDecl, Decl declWithMethod, MethodDecl method |
428428
method.getName() = name and
429-
method = decl.getAMember() and
430-
nomTypeDecl.getFullName() = type and
429+
method = declWithMethod.getAMember() and
430+
namedTypeDecl.getFullName() = type and
431431
matchesSignature(method, signature) and
432432
result = method
433433
|
434+
// member declared in the named type or a subtype of it (or an extension of any)
434435
subtypes = true and
435-
decl.asNominalTypeDecl() = nomTypeDecl.getADerivedTypeDecl*()
436+
declWithMethod.asNominalTypeDecl() = namedTypeDecl.getADerivedTypeDecl*()
436437
or
438+
// member declared in a type that's extended with a protocol that is the named type
439+
exists(ExtensionDecl e |
440+
e.getExtendedTypeDecl().getADerivedTypeDecl*() = declWithMethod.asNominalTypeDecl()
441+
|
442+
subtypes = true and
443+
e.getAProtocol() = namedTypeDecl.getADerivedTypeDecl*()
444+
)
445+
or
446+
// member declared directly in the named type (or an extension of it)
437447
subtypes = false and
438-
decl.asNominalTypeDecl() = nomTypeDecl
448+
declWithMethod.asNominalTypeDecl() = namedTypeDecl
439449
)
440450
or
441451
// Fields
442452
signature = "" and
443-
exists(NominalTypeDecl nomTypeDecl, Decl decl, FieldDecl field |
453+
exists(NominalTypeDecl namedTypeDecl, Decl declWithField, FieldDecl field |
444454
field.getName() = name and
445-
field = decl.getAMember() and
446-
nomTypeDecl.getFullName() = type and
455+
field = declWithField.getAMember() and
456+
namedTypeDecl.getFullName() = type and
447457
result = field
448458
|
459+
// field declared in the named type or a subtype of it (or an extension of any)
449460
subtypes = true and
450-
decl.asNominalTypeDecl() = nomTypeDecl.getADerivedTypeDecl*()
461+
declWithField.asNominalTypeDecl() = namedTypeDecl.getADerivedTypeDecl*()
462+
or
463+
// field declared in a type that's extended with a protocol that is the named type
464+
exists(ExtensionDecl e |
465+
e.getExtendedTypeDecl().getADerivedTypeDecl*() = declWithField.asNominalTypeDecl()
466+
|
467+
subtypes = true and
468+
e.getAProtocol() = namedTypeDecl.getADerivedTypeDecl*()
469+
)
451470
or
471+
// field declared directly in the named type (or an extension of it)
452472
subtypes = false and
453-
decl.asNominalTypeDecl() = nomTypeDecl
473+
declWithField.asNominalTypeDecl() = namedTypeDecl
454474
)
455475
)
456476
}

swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,26 @@
5555
| generics.swift:67:9:67:27 | call to source11() | external |
5656
| generics.swift:68:9:68:18 | .source12 | external |
5757
| generics.swift:69:9:69:27 | call to source13() | external |
58-
| generics.swift:88:9:88:15 | .source1 | external |
59-
| generics.swift:89:9:89:15 | .source2 | external |
60-
| generics.swift:90:9:90:14 | .source1 | external |
61-
| generics.swift:91:9:91:14 | .source2 | external |
62-
| generics.swift:92:9:92:15 | .source1 | external |
63-
| generics.swift:93:9:93:15 | .source2 | external |
64-
| generics.swift:112:9:112:15 | .source1 | external |
65-
| generics.swift:113:9:113:15 | .source2 | external |
58+
| generics.swift:93:9:93:15 | .source0 | external |
59+
| generics.swift:94:9:94:15 | .source1 | external |
60+
| generics.swift:95:9:95:15 | .source2 | external |
61+
| generics.swift:96:9:96:14 | .source0 | external |
62+
| generics.swift:97:9:97:14 | .source1 | external |
63+
| generics.swift:98:9:98:14 | .source2 | external |
64+
| generics.swift:99:9:99:15 | .source0 | external |
65+
| generics.swift:100:9:100:15 | .source1 | external |
66+
| generics.swift:101:9:101:15 | .source2 | external |
67+
| generics.swift:125:9:125:15 | .source0 | external |
68+
| generics.swift:126:9:126:15 | .source1 | external |
69+
| generics.swift:127:9:127:15 | .source2 | external |
70+
| generics.swift:128:9:128:14 | .source0 | external |
71+
| generics.swift:129:9:129:14 | .source1 | external |
72+
| generics.swift:130:9:130:14 | .source2 | external |
73+
| generics.swift:131:9:131:15 | .source0 | external |
74+
| generics.swift:132:9:132:15 | .source1 | external |
75+
| generics.swift:133:9:133:15 | .source2 | external |
76+
| generics.swift:162:9:162:22 | call to source2() | external |
77+
| generics.swift:163:9:163:22 | call to source3() | external |
6678
| nsdata.swift:18:17:18:40 | call to NSData.init(contentsOf:) | external |
6779
| nsdata.swift:19:17:19:53 | call to NSData.init(contentsOf:options:) | external |
6880
| string.swift:56:21:56:44 | call to String.init(contentsOf:) | external |

swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,15 @@ class CustomTestSourcesCsv extends SourceModelCsv {
2222
";MyDerived2;true;source11();;;ReturnValue;remote", ";MyDerived2;true;source12;;;;remote",
2323
";MyDerived2;true;source13();;;ReturnValue;remote",
2424
// ---
25-
";MyProtocol;true;source1;;;;remote", ";MyProtocol;true;source2;;;;remote",
25+
";MyParentProtocol;true;source0;;;;remote", ";MyProtocol;true;source1;;;;remote",
26+
";MyProtocol;true;source2;;;;remote",
2627
// ---
27-
";MyProtocol2;true;source1;;;;remote", ";MyProtocol2;true;source2;;;;remote",
28+
";MyParentProtocol2;true;source0;;;;remote", ";MyProtocol2;true;source1;;;;remote",
29+
";MyProtocol2;true;source2;;;;remote",
30+
// ---
31+
";MyProtocol3;true;source1();;;ReturnValue;remote",
32+
";MyProtocol3;true;source2();;;ReturnValue;remote",
33+
";MyProtocol3;true;source3();;;ReturnValue;remote"
2834
]
2935
}
3036
}

swift/ql/test/library-tests/dataflow/flowsources/generics.swift

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ func useDerived(generic: MyGeneric<Int>, generic2: MyGeneric<Any>, derived: MyDe
7171

7272
// ---
7373

74-
protocol MyProtocol {
74+
protocol MyParentProtocol {
75+
var source0: Int { get }
76+
}
77+
78+
protocol MyProtocol : MyParentProtocol {
7579
var source1: Int { get }
7680
var source2: Int { get }
7781
}
@@ -81,21 +85,29 @@ class MyImpl<T> : MyProtocol {
8185
}
8286

8387
extension MyImpl {
88+
var source0: Int { get { return 0 } }
8489
var source2: Int { get { return 0 } }
8590
}
8691

8792
func useProtocol(proto: MyProtocol, impl: MyImpl<Int>, impl2: MyImpl<Any>) {
93+
_ = proto.source0 // SOURCE
8894
_ = proto.source1 // SOURCE
8995
_ = proto.source2 // SOURCE
96+
_ = impl.source0 // SOURCE
9097
_ = impl.source1 // SOURCE
9198
_ = impl.source2 // SOURCE
99+
_ = impl2.source0 // SOURCE
92100
_ = impl2.source1 // SOURCE
93101
_ = impl2.source2 // SOURCE
94102
}
95103

96104
// ---
97105

98-
protocol MyProtocol2 {
106+
protocol MyParentProtocol2 {
107+
var source0: Int { get }
108+
}
109+
110+
protocol MyProtocol2 : MyParentProtocol2 {
99111
var source1: Int { get }
100112
var source2: Int { get }
101113
}
@@ -105,14 +117,48 @@ class MyImpl2<T> {
105117
}
106118

107119
extension MyImpl2 : MyProtocol2 {
120+
var source0: Int { get { return 0 } }
108121
var source2: Int { get { return 0 } }
109122
}
110123

111124
func useProtocol2(proto: MyProtocol2, impl: MyImpl2<Int>, impl2: MyImpl2<Any>) {
125+
_ = proto.source0 // SOURCE
112126
_ = proto.source1 // SOURCE
113127
_ = proto.source2 // SOURCE
114-
_ = impl.source1 // SOURCE [NOT DETECTED]
115-
_ = impl.source2 // SOURCE [NOT DETECTED]
116-
_ = impl2.source1 // SOURCE [NOT DETECTED]
117-
_ = impl2.source2 // SOURCE [NOT DETECTED]
128+
_ = impl.source0 // SOURCE
129+
_ = impl.source1 // SOURCE
130+
_ = impl.source2 // SOURCE
131+
_ = impl2.source0 // SOURCE
132+
_ = impl2.source1 // SOURCE
133+
_ = impl2.source2 // SOURCE
134+
}
135+
136+
// ---
137+
138+
protocol MyProtocol3 {
139+
func source1() -> Int
140+
func source2() -> Int
141+
func source3() -> Int
142+
}
143+
144+
class MyParentClass3 {
145+
func source1() -> Int { return 0 }
146+
}
147+
148+
class MyClass3 : MyParentClass3 {
149+
func source2() -> Int { return 0 }
150+
func source3() -> Int { return 0 }
151+
}
152+
153+
extension MyClass3 : MyProtocol3 {
154+
}
155+
156+
class MyChildClass3: MyClass3 {
157+
override func source3() -> Int { return 0 }
158+
}
159+
160+
func useProtocol3(impl: MyChildClass3) {
161+
_ = impl.source1() // not a source (`MyProtocol3.source1` is the declared source and `MyParentClass3` doesn't extend it)
162+
_ = impl.source2() // SOURCE
163+
_ = impl.source3() // SOURCE
118164
}

0 commit comments

Comments
 (0)