@@ -10,9 +10,75 @@ private import Caching
10
10
* equal modulo identity conversions and type parameters.
11
11
*/
12
12
module Gvn {
13
+ /**
14
+ * Gets the name of type `t`, including the enclosing type of `t` as a qualifier,
15
+ * but only if the enclosing type is not a `GenericType`.
16
+ */
17
+ string getNameNested ( Type t ) {
18
+ if not t instanceof NestedType or t .( NestedType ) .getDeclaringType ( ) instanceof GenericType
19
+ then result = t .getName ( )
20
+ else result = getNameNested ( t .( NestedType ) .getDeclaringType ( ) ) + "." + t .getName ( )
21
+ }
22
+
23
+ /**
24
+ * A generic type. This is either a type with a type parameter, a type with
25
+ * a type argument, or a nested type with a generic enclosing type.
26
+ *
27
+ * In this class, type parameters and type arguments are collectively referred
28
+ * to as "arguments".
29
+ */
30
+ class GenericType extends Type {
31
+ GenericType ( ) {
32
+ exists ( this .getChild ( 0 ) )
33
+ or
34
+ this .( NestedType ) .getDeclaringType ( ) instanceof GenericType
35
+ }
36
+
37
+ /** Gets the generic containing type, if any. */
38
+ GenericType getGenericDeclaringType ( ) { result = this .( NestedType ) .getDeclaringType ( ) }
39
+
40
+ /**
41
+ * Gets the number of arguments of the generic containing type, or 0 if there
42
+ * is no generic containing type.
43
+ */
44
+ int getNumberOfDeclaringArguments ( ) {
45
+ result = this .getGenericDeclaringType ( ) .getNumberOfArguments ( )
46
+ or
47
+ not exists ( this .getGenericDeclaringType ( ) ) and result = 0
48
+ }
49
+
50
+ /** Gets the number of arguments of this type, not taking nested types into account. */
51
+ int getNumberOfArgumentsSelf ( ) { result = count ( int i | exists ( this .getChild ( i ) ) and i >= 0 ) }
52
+
53
+ /** Gets the number of arguments of this type, taking nested types into account. */
54
+ int getNumberOfArguments ( ) {
55
+ result = this .getNumberOfDeclaringArguments ( ) + this .getNumberOfArgumentsSelf ( )
56
+ }
57
+
58
+ /** Gets the `i`th argument of this type, taking nested types into account. */
59
+ Type getArgument ( int i ) {
60
+ result = this .getGenericDeclaringType ( ) .getArgument ( i )
61
+ or
62
+ exists ( int offset |
63
+ offset = this .getNumberOfDeclaringArguments ( ) and
64
+ result = this .getChild ( i - offset ) and
65
+ i >= offset
66
+ )
67
+ }
68
+
69
+ /** Gets a textual representation of this type, taking nested types into account. */
70
+ string toStringNested ( ) {
71
+ exists ( string name | name = getNameNested ( this ) |
72
+ result = this .getGenericDeclaringType ( ) .toStringNested ( ) + "." + name
73
+ or
74
+ not exists ( this .getGenericDeclaringType ( ) ) and result = name
75
+ )
76
+ }
77
+ }
78
+
13
79
private class LeafType extends Type {
14
80
LeafType ( ) {
15
- not exists ( this . getAChild ( ) ) and
81
+ not this instanceof GenericType and
16
82
not this instanceof TypeParameter and
17
83
not this instanceof DynamicType
18
84
}
@@ -28,29 +94,37 @@ module Gvn {
28
94
or
29
95
this = TArrayTypeKind ( _, _) and result = 1
30
96
or
31
- exists ( UnboundGenericType ugt | this = TConstructedType ( ugt ) |
32
- result = ugt . getNumberOfTypeParameters ( )
97
+ exists ( GenericType t | this = TConstructedType ( t . getSourceDeclaration ( ) ) |
98
+ result = t . getNumberOfArguments ( )
33
99
)
34
100
}
35
101
36
- /** Gets a textual representation of this kind when applied to arguments `args`. */
102
+ /** Gets the source declaration type that this kind corresponds to, if any. */
103
+ GenericType getConstructedSourceDeclaration ( ) { this = TConstructedType ( result ) }
104
+
105
+ /**
106
+ * Gets a textual representation of this kind when applied to arguments `args`.
107
+ *
108
+ * This predicate is restricted to built-in generics (pointers, nullables, and
109
+ * arrays).
110
+ */
37
111
bindingset [ args]
38
- string toString ( string args ) {
112
+ string toStringBuiltin ( string args ) {
39
113
this = TPointerTypeKind ( ) and result = args + "*"
40
114
or
41
115
this = TNullableTypeKind ( ) and result = args + "?"
42
116
or
43
117
exists ( int rnk | this = TArrayTypeKind ( _, rnk ) |
44
118
result = args + "[" + concat ( int i | i in [ 0 .. rnk - 2 ] | "," ) + "]"
45
119
)
46
- or
47
- exists ( UnboundGenericType ugt | this = TConstructedType ( ugt ) |
48
- result = ugt .getNameWithoutBrackets ( ) + "<" + args + ">"
49
- )
50
120
}
51
121
52
122
/** Gets a textual representation of this kind. */
53
- string toString ( ) { result = toString ( "" ) }
123
+ string toString ( ) {
124
+ result = this .toStringBuiltin ( "" )
125
+ or
126
+ result = this .getConstructedSourceDeclaration ( ) .toStringNested ( )
127
+ }
54
128
55
129
/** Gets the location of this kind. */
56
130
Location getLocation ( ) { result instanceof EmptyLocation }
@@ -64,11 +138,9 @@ module Gvn {
64
138
or
65
139
t = any ( ArrayType at | result = TArrayTypeKind ( at .getDimension ( ) , at .getRank ( ) ) )
66
140
or
67
- result = TConstructedType ( t .( ConstructedType ) .getUnboundGeneric ( ) )
68
- or
69
- result = TConstructedType ( t .( TupleType ) .getUnderlyingType ( ) .getUnboundGeneric ( ) )
141
+ result = TConstructedType ( t .getSourceDeclaration ( ) )
70
142
or
71
- result = TConstructedType ( t )
143
+ result = TConstructedType ( t . ( TupleType ) . getUnderlyingType ( ) . getSourceDeclaration ( ) )
72
144
}
73
145
74
146
/**
@@ -107,7 +179,7 @@ module Gvn {
107
179
override CompoundTypeKind getKind ( ) { result = l .getKind ( ) }
108
180
}
109
181
110
- private ConstructedGvnTypeList gvnConstructed ( Type t , CompoundTypeKind k , int i ) {
182
+ private ConstructedGvnTypeList gvnConstructed ( GenericType t , CompoundTypeKind k , int i ) {
111
183
result = TConstructedGvnTypeNil ( k ) and
112
184
i = - 1 and
113
185
k = getTypeKind ( t )
@@ -118,14 +190,16 @@ module Gvn {
118
190
}
119
191
120
192
pragma [ noinline]
121
- private GvnType gvnTypeChild ( Type t , int i ) { result = getGlobalValueNumber ( t .getChild ( i ) ) }
193
+ private GvnType gvnTypeArgument ( GenericType t , int i ) {
194
+ result = getGlobalValueNumber ( t .getArgument ( i ) )
195
+ }
122
196
123
197
pragma [ noinline]
124
198
private predicate gvnConstructedCons (
125
- Type t , CompoundTypeKind k , int i , GvnType head , ConstructedGvnTypeList tail
199
+ GenericType t , CompoundTypeKind k , int i , GvnType head , ConstructedGvnTypeList tail
126
200
) {
127
201
tail = gvnConstructed ( t , k , i - 1 ) and
128
- head = gvnTypeChild ( t , i )
202
+ head = gvnTypeArgument ( t , i )
129
203
}
130
204
131
205
private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
@@ -150,17 +224,47 @@ module Gvn {
150
224
)
151
225
}
152
226
227
+ /**
228
+ * Gets a textual representation of this constructed type, restricted
229
+ * to the prefix `t` of the underlying source declaration type.
230
+ *
231
+ * The `toString()` calculation needs to be split up into prefixes, in
232
+ * order to apply the type arguments correctly. For example, a source
233
+ * declaration type `A<>.B.C<,>` applied to types `int, string, bool`
234
+ * needs to be printed as `A<int>.B.C<string,bool>`.
235
+ */
236
+ language [ monotonicAggregates]
237
+ private string toStringConstructed ( GenericType t ) {
238
+ t = this .getKind ( ) .getConstructedSourceDeclaration ( ) .getGenericDeclaringType * ( ) and
239
+ exists ( int offset , int children , string name , string nameArgs |
240
+ offset = t .getNumberOfDeclaringArguments ( ) and
241
+ children = t .getNumberOfArgumentsSelf ( ) and
242
+ name = getNameNested ( t ) and
243
+ if children = 0
244
+ then nameArgs = name
245
+ else
246
+ exists ( string offsetArgs |
247
+ offsetArgs =
248
+ concat ( int i |
249
+ i in [ offset .. offset + children - 1 ]
250
+ |
251
+ this .getArg ( i ) .toString ( ) , "," order by i
252
+ ) and
253
+ nameArgs = name .prefix ( name .length ( ) - children - 1 ) + "<" + offsetArgs + ">"
254
+ )
255
+ |
256
+ offset = 0 and result = nameArgs
257
+ or
258
+ result = this .toStringConstructed ( t .getGenericDeclaringType ( ) ) + "." + nameArgs
259
+ )
260
+ }
261
+
153
262
language [ monotonicAggregates]
154
263
string toString ( ) {
155
- exists ( CompoundTypeKind k , string args |
156
- k = this .getKind ( ) and
157
- args =
158
- concat ( int i |
159
- i in [ 0 .. k .getNumberOfTypeParameters ( ) - 1 ]
160
- |
161
- this .getArg ( i ) .toString ( ) , "," order by i
162
- ) and
163
- result = k .toString ( args )
264
+ exists ( CompoundTypeKind k | k = this .getKind ( ) |
265
+ result = k .toStringBuiltin ( this .getArg ( 0 ) .toString ( ) )
266
+ or
267
+ result = this .toStringConstructed ( k .getConstructedSourceDeclaration ( ) )
164
268
)
165
269
}
166
270
@@ -366,7 +470,12 @@ module Gvn {
366
470
TArrayTypeKind ( int dim , int rnk ) {
367
471
exists ( ArrayType at | dim = at .getDimension ( ) and rnk = at .getRank ( ) )
368
472
} or
369
- TConstructedType ( UnboundGenericType ugt ) { exists ( ugt .getATypeParameter ( ) ) }
473
+ TConstructedType ( GenericType sourceDecl ) {
474
+ sourceDecl = any ( GenericType t ) .getSourceDeclaration ( ) and
475
+ not sourceDecl instanceof PointerType and
476
+ not sourceDecl instanceof NullableType and
477
+ not sourceDecl instanceof ArrayType
478
+ }
370
479
371
480
cached
372
481
newtype TGvnType =
0 commit comments