Skip to content

Commit 38a38fd

Browse files
authored
Merge pull request github#6003 from hvitved/csharp/external-summaries
C#: CSV-based flow summaries
2 parents 206a37c + 66e4940 commit 38a38fd

38 files changed

+1864
-721
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
lgtm,codescanning
2+
* The following has changed in `Type::getQualifiedName`/`Type::hasQualifiedName`:
3+
- Type parameters now have the qualified name which is simply the name of the type
4+
parameter itself. Example: in `class C<T> { }`, `T` has qualified name `T`.
5+
- Constructed types now use qualified names for type arguments. For example, the
6+
qualified name of `C<int>` is `C<System.Int32>`. This also includes array types
7+
and pointer types.
8+
- Nested types are now delimited by `+` instead of `.`. For example, the qualified
9+
name of `Inner` in `class Outer { class Inner { } }` is `Outer+Inner`.

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
185185
/** Gets the generic that defines this type parameter. */
186186
UnboundGeneric getGeneric() { type_parameters(this, _, result, _) }
187187

188+
final override predicate hasQualifiedName(string qualifier, string name) {
189+
qualifier = "" and
190+
name = this.getName()
191+
}
192+
188193
override string getAPrimaryQlClass() { result = "TypeParameter" }
189194
}
190195

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ class Declaration extends DotNet::Declaration, Element, @declaration {
3434
* ```
3535
*/
3636
string getQualifiedNameWithTypes() {
37-
result = this.getDeclaringType().getQualifiedName() + "." + this.toStringWithTypes()
37+
exists(string qual |
38+
qual = this.getDeclaringType().getQualifiedName() and
39+
if this instanceof NestedType
40+
then result = qual + "+" + this.toStringWithTypes()
41+
else result = qual + "." + this.toStringWithTypes()
42+
)
3843
}
3944

4045
/**
@@ -326,6 +331,7 @@ class Virtualizable extends Member, @virtualizable {
326331
* (An example where `getOverridee*().getImplementee()` would be incorrect.)
327332
* - If this member is `D.M` then `I.M = getAnUltimateImplementee()`.
328333
*/
334+
pragma[nomagic]
329335
Virtualizable getAnUltimateImplementee() {
330336
exists(Virtualizable implementation, ValueOrRefType implementationType |
331337
implements(implementation, result, implementationType)

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

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,50 @@ private predicate isObjectClass(Class c) { c instanceof ObjectType }
5555
* Either a value type (`ValueType`) or a reference type (`RefType`).
5656
*/
5757
class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_or_ref_type {
58+
/** Gets the name of this type without `<...>` brackets, in case it is a constructed type. */
59+
private string getNameWithoutBrackets() {
60+
exists(UnboundGenericType unbound, string name |
61+
unbound = this.(ConstructedType).getUnboundDeclaration() and
62+
name = unbound.getName() and
63+
result = name.prefix(name.length() - unbound.getNumberOfTypeParameters() - 1)
64+
)
65+
or
66+
not this instanceof ConstructedType and
67+
result = this.getName()
68+
}
69+
70+
language[monotonicAggregates]
71+
private string getQualifiedTypeArguments() {
72+
result =
73+
strictconcat(Type t, int i |
74+
t = this.(ConstructedType).getTypeArgument(i)
75+
|
76+
t.getQualifiedName(), "," order by i
77+
)
78+
}
79+
5880
/**
5981
* Holds if this type has the qualified name `qualifier`.`name`.
6082
*
6183
* For example the class `System.IO.IOException` has
6284
* `qualifier`=`System.IO` and `name`=`IOException`.
6385
*/
6486
override predicate hasQualifiedName(string qualifier, string name) {
65-
name = this.getName() and
66-
if exists(this.getDeclaringType())
67-
then qualifier = this.getDeclaringType().getQualifiedName()
68-
else qualifier = this.getNamespace().getQualifiedName()
87+
exists(string name0 |
88+
not this instanceof ConstructedType and
89+
name = name0
90+
or
91+
name = name0 + "<" + this.getQualifiedTypeArguments() + ">"
92+
|
93+
exists(string enclosing |
94+
this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
95+
name0 = enclosing + "+" + this.getNameWithoutBrackets()
96+
)
97+
or
98+
not exists(this.getDeclaringType()) and
99+
qualifier = this.getNamespace().getQualifiedName() and
100+
name0 = this.getNameWithoutBrackets()
101+
)
69102
}
70103

71104
/** Gets the namespace containing this type. */
@@ -994,6 +1027,13 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type {
9941027
not type_location(this, _) and
9951028
result = this.getElementType().getALocation()
9961029
}
1030+
1031+
final override predicate hasQualifiedName(string qualifier, string name) {
1032+
exists(Type elementType, string name0 |
1033+
elementType.hasQualifiedName(qualifier, name0) and
1034+
name = name0 + this.getDimensionString(elementType)
1035+
)
1036+
}
9971037
}
9981038

9991039
/**
@@ -1013,6 +1053,13 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type {
10131053
override string toString() { result = DotNet::PointerType.super.toString() }
10141054

10151055
override string getAPrimaryQlClass() { result = "PointerType" }
1056+
1057+
final override predicate hasQualifiedName(string qualifier, string name) {
1058+
exists(string name0 |
1059+
this.getReferentType().hasQualifiedName(qualifier, name0) and
1060+
name = name0 + "*"
1061+
)
1062+
}
10161063
}
10171064

10181065
/**
@@ -1083,6 +1130,10 @@ class TupleType extends ValueType, @tuple_type {
10831130
override string getLabel() { result = getUnderlyingType().getLabel() }
10841131

10851132
override Type getChild(int i) { result = this.getUnderlyingType().getChild(i) }
1133+
1134+
final override predicate hasQualifiedName(string qualifier, string name) {
1135+
this.getUnderlyingType().hasQualifiedName(qualifier, name)
1136+
}
10861137
}
10871138

10881139
/**

0 commit comments

Comments
 (0)