@@ -10,9 +10,75 @@ private import Caching
1010 * equal modulo identity conversions and type parameters.
1111 */
1212module 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+
1379 private class LeafType extends Type {
1480 LeafType ( ) {
15- not exists ( this . getAChild ( ) ) and
81+ not this instanceof GenericType and
1682 not this instanceof TypeParameter and
1783 not this instanceof DynamicType
1884 }
@@ -28,29 +94,37 @@ module Gvn {
2894 or
2995 this = TArrayTypeKind ( _, _) and result = 1
3096 or
31- exists ( UnboundGenericType ugt | this = TConstructedType ( ugt ) |
32- result = ugt . getNumberOfTypeParameters ( )
97+ exists ( GenericType t | this = TConstructedType ( t . getSourceDeclaration ( ) ) |
98+ result = t . getNumberOfArguments ( )
3399 )
34100 }
35101
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+ */
37111 bindingset [ args]
38- string toString ( string args ) {
112+ string toStringBuiltin ( string args ) {
39113 this = TPointerTypeKind ( ) and result = args + "*"
40114 or
41115 this = TNullableTypeKind ( ) and result = args + "?"
42116 or
43117 exists ( int rnk | this = TArrayTypeKind ( _, rnk ) |
44118 result = args + "[" + concat ( int i | i in [ 0 .. rnk - 2 ] | "," ) + "]"
45119 )
46- or
47- exists ( UnboundGenericType ugt | this = TConstructedType ( ugt ) |
48- result = ugt .getNameWithoutBrackets ( ) + "<" + args + ">"
49- )
50120 }
51121
52122 /** 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+ }
54128
55129 /** Gets the location of this kind. */
56130 Location getLocation ( ) { result instanceof EmptyLocation }
@@ -64,11 +138,9 @@ module Gvn {
64138 or
65139 t = any ( ArrayType at | result = TArrayTypeKind ( at .getDimension ( ) , at .getRank ( ) ) )
66140 or
67- result = TConstructedType ( t .( ConstructedType ) .getUnboundGeneric ( ) )
68- or
69- result = TConstructedType ( t .( TupleType ) .getUnderlyingType ( ) .getUnboundGeneric ( ) )
141+ result = TConstructedType ( t .getSourceDeclaration ( ) )
70142 or
71- result = TConstructedType ( t )
143+ result = TConstructedType ( t . ( TupleType ) . getUnderlyingType ( ) . getSourceDeclaration ( ) )
72144 }
73145
74146 /**
@@ -107,7 +179,7 @@ module Gvn {
107179 override CompoundTypeKind getKind ( ) { result = l .getKind ( ) }
108180 }
109181
110- private ConstructedGvnTypeList gvnConstructed ( Type t , CompoundTypeKind k , int i ) {
182+ private ConstructedGvnTypeList gvnConstructed ( GenericType t , CompoundTypeKind k , int i ) {
111183 result = TConstructedGvnTypeNil ( k ) and
112184 i = - 1 and
113185 k = getTypeKind ( t )
@@ -118,14 +190,16 @@ module Gvn {
118190 }
119191
120192 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+ }
122196
123197 pragma [ noinline]
124198 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
126200 ) {
127201 tail = gvnConstructed ( t , k , i - 1 ) and
128- head = gvnTypeChild ( t , i )
202+ head = gvnTypeArgument ( t , i )
129203 }
130204
131205 private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
@@ -150,17 +224,47 @@ module Gvn {
150224 )
151225 }
152226
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+
153262 language [ monotonicAggregates]
154263 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 ( ) )
164268 )
165269 }
166270
@@ -366,7 +470,12 @@ module Gvn {
366470 TArrayTypeKind ( int dim , int rnk ) {
367471 exists ( ArrayType at | dim = at .getDimension ( ) and rnk = at .getRank ( ) )
368472 } 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+ }
370479
371480 cached
372481 newtype TGvnType =
0 commit comments