From 6e5c2ef0e73b028aa2516482724d7a3a3f9cca36 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 11 Feb 2020 19:34:56 +0000 Subject: [PATCH 01/21] C#: Remove assembly qualifier from some trap-ids. --- .../Semmle.Extraction.CSharp/Entities/Method.cs | 5 +---- .../Semmle.Extraction.CSharp/Entities/Types/NamedType.cs | 8 ++++++-- .../Semmle.Extraction.CSharp/Entities/Types/TupleType.cs | 2 +- .../Semmle.Extraction.CSharp/SymbolExtensions.cs | 9 ++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index aeb57609b8a1..2987d4aa48fd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -201,10 +201,7 @@ public override void WriteId(TextWriter trapFile) /// protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type) { - if (type.ContainsTypeParameters(cx, method)) - type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); - else - trapFile.WriteSubId(Type.Create(cx, type)); + type.BuildTypeId(cx, trapFile, false, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); } protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 93c13726750e..91004b7483a5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -108,7 +108,7 @@ public override IEnumerable Locations public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, true, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";type"); } @@ -174,7 +174,11 @@ class NamedTypeRefFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(referencedType); + void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol) + { + symbol.BuildTypeId(cx, trapFile, false, WriteType); + } + WriteType(Context, trapFile, referencedType.symbol); trapFile.Write(";typeRef"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index de6ea2170849..e0adee16142f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -32,7 +32,7 @@ class TupleTypeFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, false, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";tuple"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 6050ad910a52..c871da6e59aa 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -131,9 +131,9 @@ public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISy /// The extraction context. /// The trap builder used to store the result. /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction) + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, Action subTermAction) { - if (type.SpecialType != SpecialType.None) + if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType)) { /* * Use the keyword ("int" etc) for the built-in types. @@ -160,7 +160,7 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, subTermAction); + named.BuildNamedTypeId(cx, trapFile, prefix, subTermAction); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; @@ -211,9 +211,8 @@ private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool trapFile.Write("::"); } - static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) + static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, Action subTermAction) { - bool prefixAssembly = true; if (named.ContainingAssembly is null) prefixAssembly = false; if (named.IsTupleType) From 6649d72a2d863a765ceea9fbcc1957c78d64b2ab Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 12 Feb 2020 13:52:17 +0000 Subject: [PATCH 02/21] C#: Qualify type parameters with the entity that declares them --- .../Entities/Constructor.cs | 2 +- .../Entities/Method.cs | 14 +++---- .../Entities/Types/NamedType.cs | 8 ++-- .../Entities/Types/TupleType.cs | 2 +- .../Entities/UserOperator.cs | 2 +- .../SymbolExtensions.cs | 41 +++++++++++++------ 6 files changed, 42 insertions(+), 27 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 298f838cfb93..3230ad699f6f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -114,7 +114,7 @@ public override void WriteId(TextWriter trapFile) { if (symbol.IsStatic) trapFile.Write("static"); trapFile.WriteSubId(ContainingType); - AddParametersToId(Context, trapFile, symbol); + AddParametersToId(Context, trapFile, symbol, symbol); trapFile.Write(";constructor"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 2987d4aa48fd..7965e8f2b887 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -129,12 +129,12 @@ protected static void BuildMethodId(Method m, TextWriter trapFile) // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, m.symbol); trapFile.Write((int)ta.Nullability); }); trapFile.Write('>'); } } - AddParametersToId(m.Context, trapFile, m.symbol); + AddParametersToId(m.Context, trapFile, m.symbol, m.symbol); switch (m.symbol.MethodKind) { case MethodKind.PropertyGet: @@ -199,12 +199,12 @@ public override void WriteId(TextWriter trapFile) /// to make the reference to #3 in the label definition #4 for /// T valid. /// - protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type) + protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, ISymbol symbolBeingDefined) { - type.BuildTypeId(cx, trapFile, false, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); + type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g)); } - protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method) + protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol generic) { trapFile.Write('('); int index = 0; @@ -212,13 +212,13 @@ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethod if (method.MethodKind == MethodKind.ReducedExtension) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType); + AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, generic); } foreach (var param in method.Parameters) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type); + AddSignatureTypeToId(cx, trapFile, method, param.Type, generic); switch (param.RefKind) { case RefKind.Out: diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 91004b7483a5..150a3d8f0590 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -108,7 +108,7 @@ public override IEnumerable Locations public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, true, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";type"); } @@ -174,11 +174,11 @@ class NamedTypeRefFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol) + void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined) { - symbol.BuildTypeId(cx, trapFile, false, WriteType); + symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType); } - WriteType(Context, trapFile, referencedType.symbol); + WriteType(Context, trapFile, referencedType.symbol, referencedType.symbol); trapFile.Write(";typeRef"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index e0adee16142f..4f5e5f68d404 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -32,7 +32,7 @@ class TupleTypeFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, false, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";tuple"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 2a64a29fa0d2..9c94058af1ff 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -51,7 +51,7 @@ public override Type ContainingType public override void WriteId(TextWriter trapFile) { - AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type. + AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, symbol); // Needed for op_explicit(), which differs only by return type. trapFile.Write(' '); BuildMethodId(this, trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index c871da6e59aa..7acfc5027205 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -131,7 +131,7 @@ public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISy /// The extraction context. /// The trap builder used to store the result. /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, Action subTermAction) + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol SymbolBeingDefined, Action subTermAction) { if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType)) { @@ -150,7 +150,7 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra { case TypeKind.Array: var array = (IArrayTypeSymbol)type; - subTermAction(cx, trapFile, array.ElementType); + subTermAction(cx, trapFile, array.ElementType, SymbolBeingDefined); array.BuildArraySuffix(trapFile); return; case TypeKind.Class: @@ -160,15 +160,30 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, prefix, subTermAction); + named.BuildNamedTypeId(cx, trapFile, prefix, SymbolBeingDefined, subTermAction); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; - subTermAction(cx, trapFile, ptr.PointedAtType); + subTermAction(cx, trapFile, ptr.PointedAtType, SymbolBeingDefined); trapFile.Write('*'); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; + if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, SymbolBeingDefined)) + { + switch (tp.TypeParameterKind) + { + case TypeParameterKind.Method: + var method = Method.Create(cx, (IMethodSymbol)tp.ContainingSymbol); + trapFile.WriteSubId(method); + trapFile.Write('_'); + break; + case TypeParameterKind.Type: + subTermAction(cx, trapFile, tp.ContainingType, SymbolBeingDefined); + trapFile.Write('_'); + break; + } + } trapFile.Write(tp.Name); return; case TypeKind.Dynamic: @@ -211,7 +226,7 @@ private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool trapFile.Write("::"); } - static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, Action subTermAction) + static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, ISymbol symbolBeingDefined, Action subTermAction) { if (named.ContainingAssembly is null) prefixAssembly = false; @@ -223,7 +238,7 @@ static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter { trapFile.Write(f.Name); trapFile.Write(":"); - subTermAction(cx, tb0, f.Type); + subTermAction(cx, tb0, f.Type, symbolBeingDefined); } ); trapFile.Write(")"); @@ -232,7 +247,7 @@ static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter if (named.ContainingType != null) { - subTermAction(cx, trapFile, named.ContainingType); + subTermAction(cx, trapFile, named.ContainingType, symbolBeingDefined); trapFile.Write('.'); } else if (named.ContainingNamespace != null) @@ -254,14 +269,14 @@ static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter } else { - subTermAction(cx, trapFile, named.ConstructedFrom); + subTermAction(cx, trapFile, named.ConstructedFrom, symbolBeingDefined); trapFile.Write('<'); // Encode the nullability of the type arguments in the label. // Type arguments with different nullability can result in // a constructed type with different nullability of its members and methods, // so we need to create a distinct database entity for it. trapFile.BuildList(",", named.GetAnnotatedTypeArguments(), - (ta, tb0) => subTermAction(cx, tb0, ta.Symbol) + (ta, tb0) => subTermAction(cx, tb0, ta.Symbol, symbolBeingDefined) ); trapFile.Write('>'); } @@ -273,16 +288,16 @@ static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trap trapFile.Write('.'); } - static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName) + static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName) { var buildParam = includeParamName ? (prop, tb0) => { tb0.Write(prop.Name); tb0.Write(' '); - subTermAction(cx, tb0, prop.Type); + subTermAction(cx, tb0, prop.Type, null); } - : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type)); + : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type, null)); int memberCount = type.GetMembers().OfType().Count(); int hackTypeNumber = memberCount == 1 ? 1 : 0; trapFile.Write("<>__AnonType"); @@ -354,7 +369,7 @@ public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Co if (namedType.IsAnonymousType) { - namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false); + namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub, _) => sub.BuildDisplayName(cx0, tb0), false); } trapFile.Write(namedType.Name); From 4657ddcb7c40c268e7e76192f33973a39429002f Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 12 Feb 2020 16:23:48 +0000 Subject: [PATCH 03/21] C#: Avoid qualifying explicit interface implementations. --- .../Entities/Method.cs | 11 ++++--- .../Entities/Types/NamedType.cs | 8 ++--- .../Entities/Types/TupleType.cs | 2 +- .../SymbolExtensions.cs | 32 +++++++++++++++---- .../library-tests/aliases/aliases2.expected | 6 ++++ .../csharp8/NullableRefTypes.expected | 4 +-- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 7965e8f2b887..4f9dd5faac49 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -204,7 +204,7 @@ protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMet type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g)); } - protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol generic) + protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol symbolBeingDefined) { trapFile.Write('('); int index = 0; @@ -212,13 +212,13 @@ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethod if (method.MethodKind == MethodKind.ReducedExtension) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, generic); + AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, symbolBeingDefined); } foreach (var param in method.Parameters) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type, generic); + AddSignatureTypeToId(cx, trapFile, method, param.Type, symbolBeingDefined); switch (param.RefKind) { case RefKind.Out: @@ -241,9 +241,10 @@ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethod public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter trapFile, IEnumerable explicitInterfaceImplementations) { - if (explicitInterfaceImplementations.Any()) + foreach (var i in explicitInterfaceImplementations) { - trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType))); + trapFile.Write(';'); + i.ContainingType.BuildNestedTypeId(cx, trapFile, null); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 150a3d8f0590..3db1ae796a48 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -108,7 +108,7 @@ public override IEnumerable Locations public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";type"); } @@ -174,11 +174,7 @@ class NamedTypeRefFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined) - { - symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType); - } - WriteType(Context, trapFile, referencedType.symbol, referencedType.symbol); + referencedType.symbol.BuildNestedTypeId(Context, trapFile, referencedType.symbol); trapFile.Write(";typeRef"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index 4f5e5f68d404..b7e38fd88f4d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -32,7 +32,7 @@ class TupleTypeFactory : ICachedEntityFactory public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";tuple"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 7acfc5027205..17a493771c63 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -122,6 +122,24 @@ public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISy } } + /// + /// Write the identifier for the symbol to the trapfile . + /// If any nested types are found in the identifier, then they are written out explicitly, without + /// prefixing the assembly ID. + /// + /// The type to write. + /// The extraction context. + /// The trap file to write to. + /// The outer symbol being defined (to avoid recursive ids). + public static void BuildNestedTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined) + { + void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined) + { + symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType); + } + WriteType(cx, trapFile, type, symbolBeingDefined); + } + /// /// Constructs a unique string for this type symbol. /// @@ -130,8 +148,10 @@ public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISy /// /// The extraction context. /// The trap builder used to store the result. + /// Whether to prefix the type ID with the assembly ID. + /// The outer symbol being defined (to avoid recursive ids). /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol SymbolBeingDefined, Action subTermAction) + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol symbolBeingDefined, Action subTermAction) { if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType)) { @@ -150,7 +170,7 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra { case TypeKind.Array: var array = (IArrayTypeSymbol)type; - subTermAction(cx, trapFile, array.ElementType, SymbolBeingDefined); + subTermAction(cx, trapFile, array.ElementType, symbolBeingDefined); array.BuildArraySuffix(trapFile); return; case TypeKind.Class: @@ -160,16 +180,16 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, prefix, SymbolBeingDefined, subTermAction); + named.BuildNamedTypeId(cx, trapFile, prefix, symbolBeingDefined, subTermAction); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; - subTermAction(cx, trapFile, ptr.PointedAtType, SymbolBeingDefined); + subTermAction(cx, trapFile, ptr.PointedAtType, symbolBeingDefined); trapFile.Write('*'); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; - if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, SymbolBeingDefined)) + if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbolBeingDefined)) { switch (tp.TypeParameterKind) { @@ -179,7 +199,7 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tra trapFile.Write('_'); break; case TypeParameterKind.Type: - subTermAction(cx, trapFile, tp.ContainingType, SymbolBeingDefined); + subTermAction(cx, trapFile, tp.ContainingType, symbolBeingDefined); trapFile.Write('_'); break; } diff --git a/csharp/ql/test/library-tests/aliases/aliases2.expected b/csharp/ql/test/library-tests/aliases/aliases2.expected index 45870c5dda24..05fad62d6a83 100644 --- a/csharp/ql/test/library-tests/aliases/aliases2.expected +++ b/csharp/ql/test/library-tests/aliases/aliases2.expected @@ -1,3 +1,9 @@ | Program.cs:18:21:18:22 | c1 | Assembly1.dll:0:0:0:0 | Class | +| Program.cs:18:21:18:22 | c1 | Assembly2.dll:0:0:0:0 | Class | +| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class | +| Program.cs:19:21:19:22 | c2 | Assembly1.dll:0:0:0:0 | Class | | Program.cs:19:21:19:22 | c2 | Assembly2.dll:0:0:0:0 | Class | +| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class | +| Program.cs:20:15:20:16 | c3 | Assembly1.dll:0:0:0:0 | Class | +| Program.cs:20:15:20:16 | c3 | Assembly2.dll:0:0:0:0 | Class | | Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class | diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected index db4f3c6fb5d8..ff888cc88dde 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected @@ -241,9 +241,9 @@ expressionTypes | NullableRefTypes.cs:17:29:17:32 | null | null | | NullableRefTypes.cs:18:31:18:34 | this access | MyClass! | | NullableRefTypes.cs:19:33:19:36 | this access | MyClass! | -| NullableRefTypes.cs:26:44:26:53 | throw ... | MyClass![]! | +| NullableRefTypes.cs:26:44:26:53 | throw ... | MyClass?[]! | | NullableRefTypes.cs:26:50:26:53 | null | null | -| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass![]! | +| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass?[]! | | NullableRefTypes.cs:27:50:27:53 | null | null | | NullableRefTypes.cs:30:21:30:24 | null | null | | NullableRefTypes.cs:31:20:31:23 | this access | MyClass! | From d1cde2a8151dcb68445186d12d82feed64e18ae3 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 7 Apr 2020 19:58:48 +0100 Subject: [PATCH 04/21] C#: Address review comment. --- .../Semmle.Extraction.CSharp/Entities/Constructor.cs | 2 +- .../extractor/Semmle.Extraction.CSharp/Entities/Method.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 3230ad699f6f..298f838cfb93 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -114,7 +114,7 @@ public override void WriteId(TextWriter trapFile) { if (symbol.IsStatic) trapFile.Write("static"); trapFile.WriteSubId(ContainingType); - AddParametersToId(Context, trapFile, symbol, symbol); + AddParametersToId(Context, trapFile, symbol); trapFile.Write(";constructor"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 4f9dd5faac49..6a5e892791d4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -134,7 +134,7 @@ protected static void BuildMethodId(Method m, TextWriter trapFile) } } - AddParametersToId(m.Context, trapFile, m.symbol, m.symbol); + AddParametersToId(m.Context, trapFile, m.symbol); switch (m.symbol.MethodKind) { case MethodKind.PropertyGet: @@ -204,7 +204,7 @@ protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMet type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g)); } - protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol symbolBeingDefined) + protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method) { trapFile.Write('('); int index = 0; @@ -212,13 +212,13 @@ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethod if (method.MethodKind == MethodKind.ReducedExtension) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, symbolBeingDefined); + AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, method); } foreach (var param in method.Parameters) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type, symbolBeingDefined); + AddSignatureTypeToId(cx, trapFile, method, param.Type, method); switch (param.RefKind) { case RefKind.Out: From cd51a67c0dd4239c45a7e6da965b35dbcd9baddd Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 20 Apr 2020 09:32:35 +0100 Subject: [PATCH 05/21] C#: Take nullability into account when creating symbol entities. Otherwise, an entity with the wrong (cached) nullability could be created. --- .../Entities/Accessor.cs | 2 +- .../Entities/Constructor.cs | 2 +- .../Entities/Conversion.cs | 2 +- .../Entities/Destructor.cs | 2 +- .../Entities/Event.cs | 2 +- .../Entities/EventAccessor.cs | 2 +- .../Entities/Field.cs | 2 +- .../Entities/Indexer.cs | 2 +- .../Entities/LocalFunction.cs | 2 +- .../Entities/LocalVariable.cs | 2 +- .../Entities/OrdinaryMethod.cs | 2 +- .../Entities/Property.cs | 2 +- .../Entities/Types/ArrayType.cs | 2 +- .../Entities/Types/DynamicType.cs | 2 +- .../Entities/Types/NamedType.cs | 2 +- .../Entities/Types/PointerType.cs | 2 +- .../Entities/Types/TupleType.cs | 2 +- .../Entities/Types/Type.cs | 8 +++++++ .../Entities/Types/TypeParameter.cs | 2 +- .../Entities/UserOperator.cs | 2 +- csharp/extractor/Semmle.Extraction/Context.cs | 22 +++++++++++++++---- csharp/extractor/Semmle.Extraction/Entity.cs | 13 +++++++++++ .../csharp8/NullableRefTypes.expected | 2 +- 23 files changed, 59 insertions(+), 24 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs index 98c021c8a6d6..cc713b5ad2f3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs @@ -77,7 +77,7 @@ public override void Populate(TextWriter trapFile) } public new static Accessor Create(Context cx, IMethodSymbol symbol) => - AccessorFactory.Instance.CreateEntity(cx, symbol); + AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class AccessorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 298f838cfb93..a9baacbf7287 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -104,7 +104,7 @@ ConstructorDeclarationSyntax Syntax { case MethodKind.StaticConstructor: case MethodKind.Constructor: - return ConstructorFactory.Instance.CreateEntity(cx, constructor); + return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor); default: throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs index e365ca53ae0c..98758fb773f6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs @@ -11,7 +11,7 @@ class Conversion : UserOperator : base(cx, init) { } public new static Conversion Create(Context cx, IMethodSymbol symbol) => - ConversionFactory.Instance.CreateEntity(cx, symbol); + ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol); public override Microsoft.CodeAnalysis.Location ReportingLocation { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs index 33f3a330f944..65557b16b67f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs @@ -24,7 +24,7 @@ public override void Populate(TextWriter trapFile) } public new static Destructor Create(Context cx, IMethodSymbol symbol) => - DestructorFactory.Instance.CreateEntity(cx, symbol); + DestructorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class DestructorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs index 224c81b9524b..59f937a6331e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs @@ -60,7 +60,7 @@ public override void Populate(TextWriter trapFile) TypeMention.Create(Context, syntaxType, this, type); } - public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntity(cx, symbol); + public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol); class EventFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs index 7dc0a4dfcffa..da858b689dc3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs @@ -53,7 +53,7 @@ public override void Populate(TextWriter trapFile) } public new static EventAccessor Create(Context cx, IMethodSymbol symbol) => - EventAccessorFactory.Instance.CreateEntity(cx, symbol); + EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class EventAccessorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 7ae4572cd7d0..f126b7ff52f3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -18,7 +18,7 @@ class Field : CachedSymbol, IExpressionParentEntity type = new Lazy(() => Entities.Type.Create(cx, symbol.GetAnnotatedType())); } - public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntity(cx, field); + public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field); // Do not populate backing fields. // Populate Tuple fields. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs index b9ece3d8c8e1..af07c41dd6b7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs @@ -71,7 +71,7 @@ public override void Populate(TextWriter trapFile) TypeMention.Create(Context, syntax.Type, this, type); } - public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntity(cx, prop); + public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop); public override void WriteId(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index e570802ab3d8..8b90f6905dd3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -22,7 +22,7 @@ public override void WriteQuotedId(TextWriter trapFile) trapFile.Write('*'); } - public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field); + public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntityFromSymbol(cx, field); class LocalFunctionFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs index 6d0f14a014eb..02d89d08a2f7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs @@ -43,7 +43,7 @@ symbol is ILocalSymbol l ? public static LocalVariable Create(Context cx, ISymbol local) { - return LocalVariableFactory.Instance.CreateEntity(cx, local); + return LocalVariableFactory.Instance.CreateEntityFromSymbol(cx, local); } void DefineConstantValue(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index 23aa8af97215..ad41afd41895 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -51,7 +51,7 @@ public override void Populate(TextWriter trapFile) ExtractCompilerGenerated(trapFile); } - public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntity(cx, method); + public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method); class OrdinaryMethodFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index e5e2cc8ab261..05ff97db8050 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -113,7 +113,7 @@ public static Property Create(Context cx, IPropertySymbol prop) { bool isIndexer = prop.IsIndexer || prop.Parameters.Any(); - return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntity(cx, prop); + return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop); } public void VisitDeclaration(Context cx, PropertyDeclarationSyntax p) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs index c4a79a7764b0..9e2116603441 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs @@ -36,7 +36,7 @@ public override void WriteId(TextWriter trapFile) trapFile.Write(";type"); } - public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntity(cx, symbol); + public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); class ArrayTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs index f5b6bf36c440..bfaba1cff85c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs @@ -9,7 +9,7 @@ class DynamicType : Type DynamicType(Context cx, IDynamicTypeSymbol init) : base(cx, init) { } - public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntity(cx, type); + public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntityFromSymbol(cx, type); public override Microsoft.CodeAnalysis.Location ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 3db1ae796a48..f0a9c4f33ec9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -17,7 +17,7 @@ class NamedType : Type typeArgumentsLazy = new Lazy(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray()); } - public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntity(cx, type); + public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type); public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Error; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs index db8b5ff8c23b..229666e6260e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs @@ -29,7 +29,7 @@ public override void Populate(TextWriter trapFile) public Type PointedAtType { get; private set; } - public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntity(cx, symbol); + public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); class PointerTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index b7e38fd88f4d..ae9d3139a5c2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities /// class TupleType : Type { - public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntity(cx, type); + public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type); class TupleTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 7d9f5e3651e8..857d3def9456 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -324,6 +324,14 @@ public virtual IEnumerable TypeMentions } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public override bool Equals(object obj) + { + var other = obj as Type; + return other?.GetType() == GetType() && SymbolEqualityComparer.IncludeNullability.Equals(other.symbol, symbol); + } + + public override int GetHashCode() => SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol); } abstract class Type : Type where T : ITypeSymbol diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index 721583784548..1ad610fef2db 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -88,7 +88,7 @@ public override void Populate(TextWriter trapFile) } static public TypeParameter Create(Context cx, ITypeParameterSymbol p) => - TypeParameterFactory.Instance.CreateEntity(cx, p); + TypeParameterFactory.Instance.CreateEntityFromSymbol(cx, p); /// /// The variance of this type parameter. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 9c94058af1ff..a66ae7cb1e8b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -190,7 +190,7 @@ public static string OperatorSymbol(Context cx, string methodName) return result; } - public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntity(cx, symbol); + public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class UserOperatorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 85813400846c..c0cde3fdd439 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -62,7 +62,7 @@ public Entity CreateEntity(ICachedEntityFactory fact /// The new/existing entity. public Entity CreateNullableEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity { - return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); + return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init, objectEntityCache); } /// @@ -161,10 +161,14 @@ private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity) public Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + => CreateNonNullEntity(factory, init, objectEntityCache); + + + private Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init, IDictionary dictionary) where Entity : ICachedEntity { if (init is null) throw new ArgumentException("Unexpected null value", nameof(init)); - if (objectEntityCache.TryGetValue(init, out var cached)) + if (dictionary.TryGetValue(init, out var cached)) return (Entity)cached; using (StackGuard) @@ -173,7 +177,7 @@ public Entity CreateNonNullEntity(ICachedEntityFactory idLabelCache = new Dictionary(); #endif - readonly Dictionary objectEntityCache = new Dictionary(); + class SymbolComparer : IEqualityComparer + { + IEqualityComparer comparer = SymbolEqualityComparer.IncludeNullability; + + bool IEqualityComparer.Equals(object x, object y) => comparer.Equals((ISymbol)x, (ISymbol)y); + + int IEqualityComparer.GetHashCode(object obj) => comparer.GetHashCode((ISymbol)obj); + } + + readonly IDictionary objectEntityCache = new Dictionary(); + readonly IDictionary symbolEntityCache = new Dictionary(10000, new SymbolComparer()); readonly Dictionary entityLabelCache = new Dictionary(); readonly HashSet