C#: Remove assembly prefix from all extractor IDs

This commit is contained in:
Tom Hvitved
2020-08-27 14:29:14 +02:00
parent 7628caa2db
commit d17f88bbcd
40 changed files with 418 additions and 362 deletions

View File

@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities
Context.TrapWriter.Writer.commentblock_binding(this, entity, binding);
}
public static CommentBlock Create(Context cx, ICommentBlock block) => CommentBlockFactory.Instance.CreateEntity(cx, block);
public static CommentBlock Create(Context cx, ICommentBlock block) => CommentBlockFactory.Instance.CreateEntity(cx, block, block);
class CommentBlockFactory : ICachedEntityFactory<ICommentBlock, CommentBlock>
{

View File

@@ -129,7 +129,11 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";commentline");
}
static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) => CommentLineFactory.Instance.CreateEntity(cx, loc, type, text, raw);
static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw)
{
var init = (loc, type, text, raw);
return CommentLineFactory.Instance.CreateEntity(cx, init, init);
}
class CommentLineFactory : ICachedEntityFactory<(Microsoft.CodeAnalysis.Location, CommentLineType, string, string), CommentLine>
{

View File

@@ -101,6 +101,8 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(Type.Type);
trapFile.Write(" ");
trapFile.WriteSubId(ContainingType);
trapFile.Write('.');
trapFile.Write(symbol.Name);

View File

@@ -108,6 +108,9 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
protected static void BuildMethodId(Method m, TextWriter trapFile)
{
m.symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.symbol);
trapFile.Write(" ");
trapFile.WriteSubId(m.ContainingType);
AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations);
@@ -129,7 +132,7 @@ namespace Semmle.Extraction.CSharp.Entities
// 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) => { ta.Symbol.BuildNestedTypeId(m.Context, tb0, m.symbol); trapFile.Write((int)ta.Nullability); });
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { ta.Symbol.BuildOrWriteId(m.Context, tb0, m.symbol); trapFile.Write((int)ta.Nullability); });
trapFile.Write('>');
}
}
@@ -171,13 +174,17 @@ namespace Semmle.Extraction.CSharp.Entities
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
method.ReceiverType.BuildNestedTypeId(cx, trapFile, method);
method.ReceiverType.BuildOrWriteId(cx, trapFile, method);
trapFile.Write(" ");
trapFile.Write(method.ReducedFrom.Parameters.First().Name);
}
foreach (var param in method.Parameters)
{
trapFile.WriteSeparator(",", ref index);
param.Type.BuildNestedTypeId(cx, trapFile, method);
param.Type.BuildOrWriteId(cx, trapFile, method);
trapFile.Write(" ");
trapFile.Write(param.Name);
switch (param.RefKind)
{
case RefKind.Out:
@@ -200,11 +207,8 @@ namespace Semmle.Extraction.CSharp.Entities
public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter trapFile, IEnumerable<ISymbol> explicitInterfaceImplementations)
{
foreach (var i in explicitInterfaceImplementations)
{
trapFile.Write(';');
i.ContainingType.BuildNestedTypeId(cx, trapFile, null);
}
if (explicitInterfaceImplementations.Any())
trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType)));
}
public virtual string Name => symbol.Name;

View File

@@ -152,11 +152,17 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static Modifier Create(Context cx, string modifier) =>
ModifierFactory.Instance.CreateEntity(cx, new ModifierKey(modifier));
public static Modifier Create(Context cx, string modifier)
{
var modifierKey = new ModifierKey(modifier);
return ModifierFactory.Instance.CreateEntity(cx, modifierKey, modifierKey);
}
public static Modifier Create(Context cx, Accessibility access) =>
ModifierFactory.Instance.CreateEntity(cx, new ModifierKey(AccessbilityModifier(access)));
public static Modifier Create(Context cx, Accessibility access)
{
var modifierKey = new ModifierKey(AccessbilityModifier(access));
return ModifierFactory.Instance.CreateEntity(cx, modifierKey, modifierKey);
}
class ModifierFactory : ICachedEntityFactory<ModifierKey, Modifier>
{

View File

@@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";namespace");
}
public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntity2(cx, ns);
public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntityFromSymbol(cx, ns);
class NamespaceFactory : ICachedEntityFactory<INamespaceSymbol, Namespace>
{

View File

@@ -66,10 +66,10 @@ namespace Semmle.Extraction.CSharp.Entities
}
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
ParameterFactory.Instance.CreateEntity(cx, param, parent, original);
ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original));
public static Parameter Create(Context cx, IParameterSymbol param) =>
ParameterFactory.Instance.CreateEntity(cx, param, null, null);
ParameterFactory.Instance.CreateEntity(cx, param, (param, null, null));
public override void WriteId(TextWriter trapFile)
{
@@ -202,7 +202,8 @@ namespace Semmle.Extraction.CSharp.Entities
return obj != null && obj.GetType() == typeof(VarargsType);
}
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null);
static readonly object cacheKey = new object();
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, cacheKey, null);
class VarargsTypeFactory : ICachedEntityFactory<string, VarargsType>
{
@@ -237,7 +238,8 @@ namespace Semmle.Extraction.CSharp.Entities
return obj != null && obj.GetType() == typeof(VarargsParam);
}
public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, method);
static readonly object cacheKey = new object();
public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, cacheKey, method);
class VarargsParamFactory : ICachedEntityFactory<Method, VarargsParam>
{
@@ -264,19 +266,27 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.param_location(this, Original.Location);
}
public override int GetHashCode() => symbol.GetHashCode() + 31 * ConstructedType.GetHashCode();
public override bool Equals(object obj)
sealed class ConstructedExtensionParameterCacheKey
{
var other = obj as ConstructedExtensionParameter;
if (other == null || other.GetType() != typeof(ConstructedExtensionParameter))
return false;
public readonly IParameterSymbol Parameter;
public readonly ITypeSymbol ConstructedType;
public ConstructedExtensionParameterCacheKey(IParameterSymbol parameter, ITypeSymbol constructedType)
{
Parameter = parameter;
ConstructedType = constructedType;
}
return SymbolEqualityComparer.Default.Equals(symbol, other.symbol) && SymbolEqualityComparer.Default.Equals(ConstructedType, other.ConstructedType);
public override int GetHashCode() =>
(Parameter, ConstructedType).GetHashCode();
public override bool Equals(object obj) =>
obj is ConstructedExtensionParameterCacheKey k &&
SymbolEqualityComparer.Default.Equals(k.Parameter, Parameter) &&
SymbolEqualityComparer.Default.Equals(k.ConstructedType, ConstructedType);
}
public static ConstructedExtensionParameter Create(Context cx, Method method, Parameter parameter) =>
ExtensionParamFactory.Instance.CreateEntity(cx, (method, parameter));
ExtensionParamFactory.Instance.CreateEntity(cx, new ConstructedExtensionParameterCacheKey(parameter.symbol, method.symbol.ReceiverType), (method, parameter));
class ExtensionParamFactory : ICachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter>
{

View File

@@ -13,8 +13,12 @@ namespace Semmle.Extraction.CSharp.Entities
protected Property(Context cx, IPropertySymbol init)
: base(cx, init) { }
Type Type => Type.Create(Context, symbol.Type);
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(Type);
trapFile.Write(" ");
trapFile.WriteSubId(ContainingType);
trapFile.Write('.');
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations);
@@ -31,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateNullability(trapFile, symbol.GetAnnotatedType());
PopulateRefKind(trapFile, symbol.RefKind);
var type = Type.Create(Context, symbol.Type);
var type = Type;
trapFile.properties(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition));
var getter = symbol.GetMethod;

View File

@@ -109,7 +109,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, symbol);
trapFile.Write(";type");
}
@@ -149,8 +149,7 @@ namespace Semmle.Extraction.CSharp.Entities
public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init);
}
// Do not create typerefs of constructed generics as they are always in the current trap file, and there is a possibility
// that a generic could make the typedef ambiguous which leads to performance problems in QL.
// Do not create typerefs of constructed generics as they are always in the current trap file.
// Create typerefs for constructed error types in case they are fully defined elsewhere.
// We cannot use `!this.NeedsPopulation` because this would not be stable as it would depend on
// the assembly that was being extracted at the time.
@@ -168,8 +167,22 @@ namespace Semmle.Extraction.CSharp.Entities
referencedType = Type.Create(cx, symbol);
}
sealed class NamedTypeRefCacheKey
{
public readonly INamedTypeSymbol Symbol;
public NamedTypeRefCacheKey(INamedTypeSymbol symbol) => Symbol = symbol;
public override int GetHashCode() =>
11 * Symbol.GetHashCode();
public override bool Equals(object obj) =>
obj is NamedTypeRefCacheKey k && SymbolEqualityComparer.IncludeNullability.Equals(k.Symbol, Symbol);
}
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) =>
NamedTypeRefFactory.Instance.CreateEntity2(cx, type);
// We need to use a different cache key than `type` to avoid mixing up
// `NamedType`s and `NamedTypeRef`s
NamedTypeRefFactory.Instance.CreateEntity(cx, new NamedTypeRefCacheKey(type), type);
class NamedTypeRefFactory : ICachedEntityFactory<INamedTypeSymbol, NamedTypeRef>
{
@@ -182,7 +195,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
referencedType.symbol.BuildNestedTypeId(Context, trapFile, referencedType.symbol);
trapFile.WriteSubId(referencedType);
trapFile.Write(";typeRef");
}

View File

@@ -27,7 +27,8 @@ namespace Semmle.Extraction.CSharp.Entities
return obj != null && obj.GetType() == typeof(NullType);
}
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None);
static readonly object cacheKey = new object();
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, cacheKey, null), NullableAnnotation.None);
class NullTypeFactory : ICachedEntityFactory<ITypeSymbol, NullType>
{

View File

@@ -127,7 +127,7 @@ namespace Semmle.Extraction.CSharp.Entities
symbol.WriteId(trapFile);
}
public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init);
public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init, init);
class NullabilityFactory : ICachedEntityFactory<Nullability, NullabilityEntity>
{

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, symbol);
trapFile.Write(";tuple");
}

View File

@@ -100,19 +100,14 @@ namespace Semmle.Extraction.CSharp.Entities
// Visit base types
var baseTypes = new List<Type>();
if (symbol.BaseType != null)
if (symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base)
{
Type baseKey = Create(Context, symbol.BaseType);
Type baseKey = Create(Context, @base);
trapFile.extend(this, baseKey.TypeRef);
if (symbol.TypeKind != TypeKind.Struct)
baseTypes.Add(baseKey);
}
if (symbol.TypeKind == TypeKind.Interface)
{
trapFile.extend(this, Create(Context, Context.Compilation.ObjectType));
}
if (!(base.symbol is IArrayTypeSymbol))
{
foreach (var t in base.symbol.Interfaces.Select(i => Create(Context, i)))
@@ -297,8 +292,22 @@ namespace Semmle.Extraction.CSharp.Entities
DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original)
: base(cx, init, parent, original) { }
sealed class DelegateTypeParameterCacheKey
{
public readonly IParameterSymbol Symbol;
public DelegateTypeParameterCacheKey(IParameterSymbol symbol) => Symbol = symbol;
public override int GetHashCode() =>
13 * Symbol.GetHashCode();
public override bool Equals(object obj) =>
obj is DelegateTypeParameterCacheKey k && SymbolEqualityComparer.IncludeNullability.Equals(k.Symbol, Symbol);
}
new public static DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
DelegateTypeParameterFactory.Instance.CreateEntity(cx, (param, parent, original));
// We need to use a different cache key than `param` to avoid mixing up
// `DelegateTypeParameter`s and `Parameter`s
DelegateTypeParameterFactory.Instance.CreateEntity(cx, new DelegateTypeParameterCacheKey(param), (param, parent, original));
class DelegateTypeParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), DelegateTypeParameter>
{

View File

@@ -38,17 +38,11 @@ namespace Semmle.Extraction.CSharp.Entities
if (symbol.HasUnmanagedTypeConstraint)
trapFile.general_type_parameter_constraints(constraints, 4);
ITypeSymbol baseType = symbol.HasValueTypeConstraint ?
Context.Compilation.GetTypeByMetadataName(valueTypeName) :
Context.Compilation.ObjectType;
if (symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated)
trapFile.general_type_parameter_constraints(constraints, 5);
foreach (var abase in symbol.GetAnnotatedTypeConstraints())
{
if (abase.Symbol.TypeKind != TypeKind.Interface)
baseType = abase.Symbol;
var t = Create(Context, abase.Symbol);
trapFile.specific_type_parameter_constraints(constraints, t.TypeRef);
if (!abase.HasObliviousNullability())
@@ -56,7 +50,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, symbol.Name);
trapFile.extend(this, Create(Context, baseType).TypeRef);
Namespace parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace);
trapFile.parent_namespace(this, parentNs);

View File

@@ -49,13 +49,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public override void WriteId(TextWriter trapFile)
{
symbol.ReturnType.BuildNestedTypeId(Context, trapFile, symbol); // Needed for op_explicit(), which differs only by return type.
trapFile.Write(' ');
BuildMethodId(this, trapFile);
}
/// <summary>
/// For some reason, some operators are missing from the Roslyn database of mscorlib.
/// This method returns <code>true</code> for such operators.
@@ -68,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (containingType != null)
{
var containingNamedType = containingType as INamedTypeSymbol;
return containingNamedType == null || !containingNamedType.MemberNames.Contains(symbol.Name);
return containingNamedType == null || !containingNamedType.GetMembers(symbol.Name).Contains(symbol);
}
var pointerType = symbol.Parameters.Select(p => p.Type).OfType<IPointerTypeSymbol>().FirstOrDefault();