Skip to content

Commit 0466e36

Browse files
committed
C#: Teach Implements.qll about nested types
1 parent f9ece0a commit 0466e36

File tree

4 files changed

+54
-14
lines changed

4 files changed

+54
-14
lines changed

csharp/ql/src/semmle/code/csharp/Implements.qll

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ private module Gvn {
250250

251251
private class LeafType extends Type {
252252
LeafType() {
253-
not exists(this.getAChild()) and
253+
not this instanceof Unification::GenericType and
254254
not this instanceof MethodTypeParameter and
255255
not this instanceof DynamicType
256256
}
@@ -267,7 +267,9 @@ private module Gvn {
267267
gvnConstructedCons(_, _, _, head, tail)
268268
}
269269

270-
private ConstructedGvnTypeList gvnConstructed(Type t, Unification::CompoundTypeKind k, int i) {
270+
private ConstructedGvnTypeList gvnConstructed(
271+
Unification::GenericType t, Unification::CompoundTypeKind k, int i
272+
) {
271273
result = TConstructedGvnTypeNil(k) and
272274
i = -1 and
273275
k = Unification::getTypeKind(t)
@@ -278,14 +280,17 @@ private module Gvn {
278280
}
279281

280282
pragma[noinline]
281-
private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
283+
private GvnType gvnTypeChildExt(Unification::GenericType t, int i) {
284+
result = getGlobalValueNumber(t.getChildExt(i))
285+
}
282286

283287
pragma[noinline]
284288
private predicate gvnConstructedCons(
285-
Type t, Unification::CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
289+
Unification::GenericType t, Unification::CompoundTypeKind k, int i, GvnType head,
290+
ConstructedGvnTypeList tail
286291
) {
287292
tail = gvnConstructed(t, k, i - 1) and
288-
head = gvnTypeChild(t, i)
293+
head = gvnTypeChildExt(t, i)
289294
}
290295

291296
/** Gets the global value number for a given type. */
@@ -319,6 +324,8 @@ private module Gvn {
319324
}
320325

321326
private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
327+
Unification::CompoundTypeKind getKind() { this = gvnConstructed(_, result, _) }
328+
322329
private int length() {
323330
this = TConstructedGvnTypeNil(_) and result = -1
324331
or
@@ -338,17 +345,47 @@ private module Gvn {
338345
)
339346
}
340347

348+
/**
349+
* Gets a textual representation of this constructed type, restricted
350+
* to the prefix `t` of the underlying source declaration type.
351+
*
352+
* The `toString()` calculation needs to be split up into prefixes, in
353+
* order to apply the type arguments correctly. For example, a source
354+
* declaration type `A<>.B.C<,>` applied to types `int, string, bool`
355+
* needs to be printed as `A<int>.B.C<string,bool>`.
356+
*/
357+
language[monotonicAggregates]
358+
private string toStringConstructed(Unification::GenericType t) {
359+
t = this.getKind().getConstructedSourceDeclaration().getQualifier*() and
360+
exists(int offset, int children, string name, string nameArgs |
361+
offset = t.getNumberOfQualifierChildrenExt() and
362+
children = t.getNumberOfChildrenSelf() and
363+
name = Unification::getQualifiedName(t) and
364+
if children = 0
365+
then nameArgs = name
366+
else
367+
exists(string offsetArgs |
368+
offsetArgs =
369+
concat(int i |
370+
i in [offset .. offset + children - 1]
371+
|
372+
this.getArg(i).toString(), "," order by i
373+
) and
374+
nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">"
375+
)
376+
|
377+
offset = 0 and result = nameArgs
378+
or
379+
result = this.toStringConstructed(t.getQualifier()) + "." + nameArgs
380+
)
381+
}
382+
341383
language[monotonicAggregates]
342384
string toString() {
343-
exists(Unification::CompoundTypeKind k, string args |
344-
this = gvnConstructed(_, k, _) and
345-
args =
346-
concat(int i |
347-
i in [0 .. k.getNumberOfTypeParameters() - 1]
348-
|
349-
this.getArg(i).toString(), "," order by i
350-
) and
351-
result = k.toString(args)
385+
exists(Unification::CompoundTypeKind k | k = this.getKind() |
386+
result = k.toStringBuiltin(this.getArg(0).toString())
387+
or
388+
result = this.toStringConstructed(k.getConstructedSourceDeclaration())
352389
)
353390
}
354391

csharp/ql/test/library-tests/overrides/Implements.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@
2727
| overrides.cs:268:29:268:36 | Property | overrides.cs:216:13:216:20 | Property |
2828
| overrides.cs:269:29:269:32 | Item | overrides.cs:217:13:217:16 | Item |
2929
| overrides.cs:270:44:270:48 | Event | overrides.cs:218:28:218:32 | Event |
30+
| overrides.cs:284:25:284:28 | M | overrides.cs:279:18:279:21 | M |

csharp/ql/test/library-tests/overrides/Overrides19.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
| overrides.cs:249:22:249:25 | M | overrides.cs:247:11:247:12 | A6 | overrides.cs:162:11:162:14 | M | overrides.cs:160:22:160:26 | I2<Object[]> |
1010
| overrides.cs:259:27:259:30 | M | overrides.cs:257:11:257:12 | A8 | overrides.cs:223:26:223:29 | M | overrides.cs:221:11:221:12 | A1 |
1111
| overrides.cs:267:27:267:30 | M | overrides.cs:265:11:265:12 | A9 | overrides.cs:223:26:223:29 | M | overrides.cs:221:11:221:12 | A1 |
12+
| overrides.cs:284:25:284:28 | M | overrides.cs:282:15:282:17 | A10 | overrides.cs:279:18:279:21 | M | overrides.cs:277:19:277:20 | I6 |

csharp/ql/test/library-tests/overrides/Overrides22.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@
4747
| overrides.G2.M<S>(string, S) | overrides.G.M<S>(string, S) | overrides |
4848
| overrides.G.M<S>(string, S) | overrides.I2<String>.M<S>(string, S) | implements |
4949
| overrides.H<>.M<S>(TA, S) | overrides.I2<TA>.M<S>(TA, S) | implements |
50+
| overrides.Outer<>.A10.M<T>(Inner) | overrides.Outer<>.I6.M<T>(Inner) | implements |

0 commit comments

Comments
 (0)