Skip to content

Commit 166a6b0

Browse files
authored
Merge pull request github#6268 from tamasvajk/feature/generic-type-name
C#: Remove type args/params from generic type names in extractor
2 parents 497f367 + 2434240 commit 166a6b0

File tree

13 files changed

+4327
-105
lines changed

13 files changed

+4327
-105
lines changed

csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -482,22 +482,6 @@ private static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, C
482482
{
483483
trapFile.Write(TrapExtensions.EncodeString(namedType.Name));
484484
}
485-
486-
if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any())
487-
{
488-
trapFile.Write('<');
489-
trapFile.BuildList(
490-
",",
491-
namedType.TypeArguments,
492-
p =>
493-
{
494-
if (IsReallyBound(namedType))
495-
{
496-
p.BuildDisplayName(cx, trapFile);
497-
}
498-
});
499-
trapFile.Write('>');
500-
}
501485
}
502486

503487
public static bool IsReallyUnbound(this INamedTypeSymbol type) =>

csharp/ql/src/definitions.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,10 @@ private class TypeMentionUse extends Use, TypeMention {
158158
Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, _) and
159159
endcolumn =
160160
startcolumn +
161-
this.getType().(ConstructedType).getUnboundGeneric().getNameWithoutBrackets().length() - 1
161+
this.getType().(ConstructedType).getUnboundGeneric().getUndecoratedName().length() - 1
162162
or
163163
Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, _) and
164-
endcolumn =
165-
startcolumn + this.getType().(UnboundGenericType).getNameWithoutBrackets().length() - 1
164+
endcolumn = startcolumn + this.getType().(UnboundGenericType).getUndecoratedName().length() - 1
166165
or
167166
not this.getType() instanceof ConstructedType and
168167
not this.getType() instanceof UnboundGenericType and

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ class AnnotatedConstructedType extends AnnotatedType {
407407

408408
override string toString() {
409409
result =
410-
annotations.getTypePrefix() + type.getUnboundGeneric().getNameWithoutBrackets() + "<" +
410+
annotations.getTypePrefix() + type.getUnboundGeneric().getUndecoratedName() + "<" +
411411
this.getTypeArgumentsString() + ">" + annotations.getTypeSuffix()
412412
}
413413

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class ExtensionMethod extends Method {
313313
override predicate isStatic() { any() }
314314

315315
/** Gets the type being extended by this method. */
316+
pragma[noinline]
316317
Type getExtendedType() { result = getParameter(0).getType() }
317318

318319
override string getAPrimaryQlClass() { result = "ExtensionMethod" }

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

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,36 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric {
105105

106106
override Location getALocation() { type_location(this, result) }
107107

108-
/** Gets the name of this generic type without the `<...>` brackets. */
109-
string getNameWithoutBrackets() {
110-
result = getName().prefix(getName().length() - getNumberOfTypeParameters() - 1)
108+
override UnboundGenericType getUnboundDeclaration() {
109+
result = ValueOrRefType.super.getUnboundDeclaration()
110+
}
111+
112+
final override Type getChild(int n) { result = getTypeParameter(n) }
113+
114+
private string getTypeParameterCommas() {
115+
result = strictconcat(int i | exists(this.getTypeParameter(i)) | "", ",")
111116
}
112117

113118
override string toStringWithTypes() {
114-
result = getNameWithoutBrackets() + "<" + this.typeParametersToString() + ">"
119+
result = this.getUndecoratedName() + "<" + this.typeParametersToString() + ">"
115120
}
116121

117-
override UnboundGenericType getUnboundDeclaration() {
118-
result = ValueOrRefType.super.getUnboundDeclaration()
122+
final override string getName() {
123+
result = this.getUndecoratedName() + "<" + this.getTypeParameterCommas() + ">"
119124
}
120125

121-
final override Type getChild(int n) { result = getTypeParameter(n) }
126+
final override predicate hasQualifiedName(string qualifier, string name) {
127+
exists(string name0 | name = name0 + "<" + this.getTypeParameterCommas() + ">" |
128+
exists(string enclosing |
129+
this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
130+
name0 = enclosing + "+" + this.getUndecoratedName()
131+
)
132+
or
133+
not exists(this.getDeclaringType()) and
134+
qualifier = this.getNamespace().getQualifiedName() and
135+
name0 = this.getUndecoratedName()
136+
)
137+
}
122138
}
123139

124140
/**
@@ -332,8 +348,8 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType {
332348

333349
override string toStringWithTypes() {
334350
result =
335-
getNameWithoutBrackets() + "<" + this.typeParametersToString() + ">(" +
336-
parameterTypesToString() + ")"
351+
getUndecoratedName() + "<" + this.typeParametersToString() + ">(" + parameterTypesToString() +
352+
")"
337353
}
338354
}
339355

@@ -360,22 +376,49 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric {
360376

361377
override UnboundGenericType getUnboundGeneric() { constructed_generic(this, getTypeRef(result)) }
362378

363-
override string toStringWithTypes() {
379+
final override Type getChild(int n) { result = getTypeArgument(n) }
380+
381+
language[monotonicAggregates]
382+
private string getTypeArgumentsString() {
364383
result =
365-
getUnboundGeneric().getNameWithoutBrackets() + "<" + this.getTypeArgumentsString() + ">"
384+
strictconcat(Type t, int i | t = this.getTypeArgument(i) | t.toString(), ", " order by i)
366385
}
367386

368-
final override Type getChild(int n) { result = getTypeArgument(n) }
387+
language[monotonicAggregates]
388+
private string getTypeArgumentsNames() {
389+
result = strictconcat(Type t, int i | t = this.getTypeArgument(i) | t.getName(), "," order by i)
390+
}
369391

370392
language[monotonicAggregates]
371-
private string getTypeArgumentsString() {
393+
private string getTypeArgumentsQualifiedNames() {
372394
result =
373-
concat(int i |
374-
exists(this.getTypeArgument(i))
395+
strictconcat(Type t, int i |
396+
t = this.getTypeArgument(i)
375397
|
376-
this.getTypeArgument(i).toString(), ", " order by i
398+
t.getQualifiedName(), "," order by i
377399
)
378400
}
401+
402+
final override string toStringWithTypes() {
403+
result = this.getUndecoratedName() + "<" + this.getTypeArgumentsString() + ">"
404+
}
405+
406+
final override string getName() {
407+
result = this.getUndecoratedName() + "<" + this.getTypeArgumentsNames() + ">"
408+
}
409+
410+
final override predicate hasQualifiedName(string qualifier, string name) {
411+
exists(string name0 | name = name0 + "<" + this.getTypeArgumentsQualifiedNames() + ">" |
412+
exists(string enclosing |
413+
this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
414+
name0 = enclosing + "+" + this.getUndecoratedName()
415+
)
416+
or
417+
not exists(this.getDeclaringType()) and
418+
qualifier = this.getNamespace().getQualifiedName() and
419+
name0 = this.getUndecoratedName()
420+
)
421+
}
379422
}
380423

381424
/**

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

Lines changed: 44 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -55,27 +55,12 @@ 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-
}
58+
/**
59+
* DEPRECATED: use `getUndecoratedName()` instead.
60+
*
61+
* Gets the name of this type without `<...>` brackets, in case it is a generic type.
62+
*/
63+
deprecated string getNameWithoutBrackets() { types(this, _, result) }
7964

8065
/**
8166
* Holds if this type has the qualified name `qualifier`.`name`.
@@ -84,21 +69,14 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
8469
* `qualifier`=`System.IO` and `name`=`IOException`.
8570
*/
8671
override predicate hasQualifiedName(string qualifier, string name) {
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()
72+
exists(string enclosing |
73+
this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
74+
name = enclosing + "+" + this.getUndecoratedName()
10175
)
76+
or
77+
not exists(this.getDeclaringType()) and
78+
qualifier = this.getNamespace().getQualifiedName() and
79+
name = this.getUndecoratedName()
10280
}
10381

10482
/** Gets the namespace containing this type. */
@@ -112,16 +90,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
11290

11391
override ValueOrRefType getDeclaringType() { none() }
11492

115-
override string getUndecoratedName() {
116-
if this.getName().indexOf("<") > 0
117-
then
118-
exists(string name, int p |
119-
name = this.getName() and p = min(int p2 | p2 = name.indexOf("<") and p2 > 0)
120-
|
121-
result = name.substring(0, p)
122-
)
123-
else result = this.getName()
124-
}
93+
override string getUndecoratedName() { types(this, _, result) }
12594

12695
/** Gets a nested child type, if any. */
12796
NestedType getAChildType() { nested_types(result, this, _) }
@@ -201,6 +170,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
201170
* }
202171
* ```
203172
*/
173+
pragma[inline]
204174
predicate hasMethod(Method m) { this.hasMember(m) }
205175

206176
/**
@@ -227,6 +197,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
227197
* }
228198
* ```
229199
*/
200+
pragma[inline]
230201
predicate hasCallable(Callable c) {
231202
hasMethod(c)
232203
or
@@ -256,25 +227,15 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_
256227
* }
257228
* ```
258229
*/
230+
pragma[inline]
259231
predicate hasMember(Member m) {
260-
// For performance reasons, split up into "cheap" computation
261-
// (non-overridden members) and "expensive" computation
262-
// (overridden members). The latter is cached, and generally
263-
// much smaller than the full relation.
264-
hasNonOverriddenMember(m)
232+
m = this.getAMember()
233+
or
234+
hasNonOverriddenMember(this.getBaseClass+(), m)
265235
or
266236
hasOverriddenMember(m)
267237
}
268238

269-
private predicate hasNonOverriddenMember(Member m) {
270-
isNonOverridden(m) and
271-
(
272-
m = getAMember()
273-
or
274-
getBaseClass+().getAMember() = m and not m.isPrivate()
275-
)
276-
}
277-
278239
cached
279240
private predicate hasOverriddenMember(Virtualizable v) {
280241
v.isOverridden() and
@@ -753,8 +714,12 @@ class RefType extends ValueOrRefType, @ref_type {
753714
override predicate isRefType() { any() }
754715
}
755716

756-
// Helper predicate to avoid slow "negation_body"
757-
private predicate isNonOverridden(Member m) { not m.(Virtualizable).isOverridden() }
717+
pragma[noinline]
718+
private predicate hasNonOverriddenMember(Class c, Member m) {
719+
m = c.getAMember() and
720+
not m.(Virtualizable).isOverridden() and
721+
not m.isPrivate()
722+
}
758723

759724
/**
760725
* A `class`, for example
@@ -963,6 +928,15 @@ class NullableType extends ValueType, DotNet::ConstructedGeneric, @nullable_type
963928
override Type getTypeArgument(int p) { p = 0 and result = getUnderlyingType() }
964929

965930
override string getAPrimaryQlClass() { result = "NullableType" }
931+
932+
final override string getName() {
933+
result = "Nullable<" + this.getUnderlyingType().getName() + ">"
934+
}
935+
936+
final override predicate hasQualifiedName(string qualifier, string name) {
937+
qualifier = "System" and
938+
name = "Nullable<" + this.getUnderlyingType().getQualifiedName() + ">"
939+
}
966940
}
967941

968942
/**
@@ -1046,7 +1020,7 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type {
10461020

10471021
override Type getChild(int n) { result = getReferentType() and n = 0 }
10481022

1049-
override string getName() { result = DotNet::PointerType.super.getName() }
1023+
override string getName() { types(this, _, result) }
10501024

10511025
override Location getALocation() { result = getReferentType().getALocation() }
10521026

@@ -1120,11 +1094,14 @@ class TupleType extends ValueType, @tuple_type {
11201094
override string toStringWithTypes() {
11211095
result =
11221096
"(" +
1123-
concat(int i |
1124-
exists(getElement(i))
1125-
|
1126-
getElement(i).getType().toStringWithTypes(), ", " order by i
1127-
) + ")"
1097+
concat(Type t, int i | t = getElement(i).getType() | t.toStringWithTypes(), ", " order by i)
1098+
+ ")"
1099+
}
1100+
1101+
language[monotonicAggregates]
1102+
override string getName() {
1103+
result =
1104+
"(" + concat(Type t, int i | t = getElement(i).getType() | t.getName(), "," order by i) + ")"
11281105
}
11291106

11301107
override string getLabel() { result = getUnderlyingType().getLabel() }

csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ module SystemDataEntity {
3939
/** The `System.Data.Entity.DbSet` class. */
4040
class DbSet extends Class {
4141
DbSet() {
42-
this.getUnboundDeclaration().(csharp::UnboundGenericClass).getNameWithoutBrackets() = "DbSet"
42+
this.getUnboundDeclaration().(csharp::UnboundGenericClass).getUndecoratedName() = "DbSet"
4343
}
4444

4545
/** Gets the `SqlQuery` method. */
@@ -100,7 +100,7 @@ module SystemDataEntityInfrastructure {
100100
this.getABaseType*()
101101
.getUnboundDeclaration()
102102
.(csharp::UnboundGenericClass)
103-
.getNameWithoutBrackets() = "DbRawSqlQuery"
103+
.getUndecoratedName() = "DbRawSqlQuery"
104104
}
105105
}
106106
}

csharp/ql/src/semmle/code/dotnet/Element.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class Element extends @dotnet_element {
5757
/** An element that has a name. */
5858
class NamedElement extends Element, @dotnet_named_element {
5959
/** Gets the name of this element. */
60+
cached
6061
string getName() { none() }
6162

6263
/** Holds if this element has name 'name'. */

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
2+
* without actually changing any of the dbscheme predicates. It contains a date
3+
* to allow for such updates in the future as well.
4+
*
5+
* 2021-07-14
6+
*
7+
* DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
8+
* previously seen state (matching a previously seen SHA), which would make the upgrade
9+
* mechanism not work properly.
10+
*/
111

212
/**
313
* An invocation of the compiler. Note that more than one file may be

0 commit comments

Comments
 (0)