@@ -1012,5 +1012,63 @@ class TypeMention extends @type_mention {
10121012@type_or_ref getTypeRef ( @type type ) {
10131013 result = type
10141014 or
1015- typeref_type ( result , type )
1015+ type = result .( TypeRefs:: TypeRef ) .getCanonicalType ( )
1016+ }
1017+
1018+ /**
1019+ * Module for reasoning about typerefs.
1020+ */
1021+ // private
1022+ module TypeRefs {
1023+ /**
1024+ * A typeref is a reference to a type in some assembly.
1025+ * Often, a type can be present in multiple assemblies.
1026+ */
1027+ class TypeRef extends @typeref {
1028+ string getName ( ) { typerefs ( this , result ) }
1029+
1030+ string toString ( ) { result = getName ( ) }
1031+
1032+ Type getAType ( ) { typeref_type ( this , result ) }
1033+
1034+ /**
1035+ * Gets the "canonical type" represented by a typeref.
1036+ * This is because a typeref can reference multiple types, or a type with the same
1037+ * fully qualified name can exist in multiple assemblies.
1038+ * The canonical type is an arbitrarily chosen type from the list of candidate types.
1039+ */
1040+ Type getCanonicalType ( ) {
1041+ result = this .getAType ( ) and
1042+ isCanonicalType ( result )
1043+ }
1044+ }
1045+
1046+ /** Gets the location of a type. */
1047+ Location typeLocation ( Type t ) {
1048+ type_location ( t , result )
1049+ or
1050+ exists ( Type decl | constructed_generic ( decl , t ) and result = typeLocation ( decl ) )
1051+ }
1052+
1053+ /** Gets a "canonical location" for a type. A type has only one canonical location. */
1054+ Location canonicalTypeLocation ( Type t ) {
1055+ result = typeLocation ( t ) and
1056+ not locationIsBetter ( result , typeLocation ( t ) )
1057+ }
1058+
1059+ pragma [ inline]
1060+ private predicate locationIsBetter ( Location typeLocation , Location betterLocation ) {
1061+ typeLocation .( Assembly ) .getFullName ( ) < betterLocation .( Assembly ) .getFullName ( )
1062+ or
1063+ typeLocation instanceof Assembly and betterLocation instanceof SourceLocation
1064+ or
1065+ typeLocation .( SourceLocation ) .getFile ( ) .getAbsolutePath ( ) < betterLocation .( SourceLocation ) .getFile ( ) .getAbsolutePath ( )
1066+ }
1067+
1068+ predicate isCanonicalType ( Type type ) {
1069+ not exists ( TypeRef tr |
1070+ type = tr .getAType ( ) and
1071+ locationIsBetter ( canonicalTypeLocation ( type ) , canonicalTypeLocation ( tr .getAType ( ) ) )
1072+ )
1073+ }
10161074}
0 commit comments