C#: Fix DB inconsistencies, and rework id generation.

This commit is contained in:
Calum Grant
2019-07-18 17:42:47 +01:00
parent 39a45ceefe
commit 61ab9431ab
25 changed files with 387 additions and 179 deletions

View File

@@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
var type = Type.Create(Context, symbol.Type);
trapFile.events(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition));

View File

@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateMetadataHandle(trapFile);
PopulateAttributes();
ContainingType.PopulateGenerics();
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
Field unboundFieldKey = Field.Create(Context, symbol.OriginalDefinition);
trapFile.fields(this, (symbol.IsConst ? 2 : 1), symbol.Name, ContainingType, Type.Type.TypeRef, unboundFieldKey);

View File

@@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
var type = Type.Create(Context, symbol.Type);
trapFile.indexers(this, symbol.GetName(useMetadataName: true), ContainingType, type.TypeRef, OriginalDefinition);

View File

@@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (symbol.IsGenericMethod && !IsSourceDeclaration)
{
trapFile.Write('<');
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta));
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta, TypeNameContext.MethodName));
trapFile.Write('>');
}
trapFile.Write(";localfunction");

View File

@@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (symbol is ILocalSymbol local)
{
PopulateNullability(trapFile, local.NullableAnnotation);
PopulateNullability(trapFile, local.GetAnnotatedType());
if (local.IsRef)
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
}

View File

@@ -108,6 +108,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
protected static void BuildMethodId(Method m, TextWriter trapFile)
{
// AddSignatureTypeToId(m.Context, trapFile, m.symbol, m.ContainingType.symbol, false);
trapFile.WriteSubId(m.ContainingType);
AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations);
@@ -129,7 +130,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) => { 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, TypeNameContext.MethodName); trapFile.Write((int)ta.Nullability); });
trapFile.Write('>');
}
}
@@ -199,12 +200,12 @@ namespace Semmle.Extraction.CSharp.Entities
/// to make the reference to <code>#3</code> in the label definition <code>#4</code> for
/// <code>T</code> valid.
/// </summary>
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type)
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, TypeNameContext assemblyPrefix)
{
if (type.ContainsTypeParameters(cx, method))
type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
type.BuildTypeId(cx, trapFile, (cx0, tb0, type0, _) => AddSignatureTypeToId(cx, tb0, method, type0, assemblyPrefix), assemblyPrefix, method);
else
trapFile.WriteSubId(Type.Create(cx, type));
trapFile.WriteSubId(Type.Create(cx, type).TypeRef);
}
protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
@@ -215,13 +216,13 @@ namespace Semmle.Extraction.CSharp.Entities
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType);
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, TypeNameContext.MethodParam);
}
foreach (var param in method.Parameters)
{
trapFile.WriteSeparator(",", ref index);
AddSignatureTypeToId(cx, trapFile, method, param.Type);
AddSignatureTypeToId(cx, trapFile, method, param.Type, TypeNameContext.MethodParam);
switch (param.RefKind)
{
case RefKind.Out:
@@ -345,11 +346,10 @@ namespace Semmle.Extraction.CSharp.Entities
foreach (var tp in symbol.GetAnnotatedTypeArguments())
{
trapFile.type_arguments(Type.Create(Context, tp.Symbol), child, this);
var ta = tp.Nullability.GetTypeAnnotation();
if (ta != Kinds.TypeAnnotation.None)
trapFile.type_argument_annotation(this, child, ta);
child++;
}
trapFile.type_nullability(this, NullabilityEntity.Create(Context, new Nullability(symbol)));
}
else
{
@@ -380,7 +380,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateMethodBody(trapFile);
PopulateGenerics(trapFile);
PopulateMetadataHandle(trapFile);
PopulateNullability(trapFile, symbol.ReturnNullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedReturnType());
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.PushesLabel;

View File

@@ -86,7 +86,8 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";parameter");
}
public override bool NeedsPopulation => true;
// If we don't have the type of the parameter, do not populate it.
public override bool NeedsPopulation => symbol.Type.TypeKind != TypeKind.Error;
string Name
{
@@ -103,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateAttributes();
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
PopulateRefKind(trapFile, symbol.RefKind);
if (symbol.Name != Original.symbol.Name)

View File

@@ -15,6 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
// trapFile.WriteSubId(ContainingType.TypeRef);
trapFile.WriteSubId(ContainingType);
trapFile.Write('.');
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations);
@@ -28,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateAttributes();
PopulateModifiers(trapFile);
BindComments();
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
PopulateRefKind(trapFile, symbol.RefKind);
var type = Type.Create(Context, symbol.Type);

View File

@@ -28,11 +28,14 @@ namespace Semmle.Extraction.CSharp.Entities
Attribute.ExtractAttributes(Context, symbol, this);
}
protected void PopulateNullability(TextWriter trapFile, NullableAnnotation annotation)
protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type)
{
var ta = annotation.GetTypeAnnotation();
if (ta != Kinds.TypeAnnotation.None)
trapFile.type_annotation(this, ta);
var ta = type.Nullability.GetTypeAnnotation();
var n = NullabilityEntity.Create(Context, Nullability.Create(type));
if (ta != Kinds.TypeAnnotation.None || !type.HasConsistentNullability())
{
trapFile.type_nullability(this, n);
}
}
protected void PopulateRefKind(TextWriter trapFile, RefKind kind)

View File

@@ -27,13 +27,11 @@ namespace Semmle.Extraction.CSharp.Entities
{
trapFile.array_element_type(this, Dimension, Rank, element.Type.TypeRef);
PopulateType(trapFile);
PopulateNullability(trapFile, symbol.ElementNullableAnnotation);
}
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(element.Type);
trapFile.Write((int)symbol.ElementNullableAnnotation);
symbol.BuildArraySuffix(trapFile);
trapFile.Write(";type");
}

View File

@@ -57,9 +57,6 @@ namespace Semmle.Extraction.CSharp.Entities
for (int i = 0; i < symbol.TypeArguments.Length; ++i)
{
var ta = symbol.TypeArgumentsNullableAnnotations[i].GetTypeAnnotation();
if (ta != Kinds.TypeAnnotation.None)
trapFile.type_argument_annotation(this, i, ta);
trapFile.type_arguments(TypeArguments[i].TypeRef, i, this);
}
}
@@ -114,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol);
trapFile.Write(";type");
}
@@ -154,33 +151,40 @@ namespace Semmle.Extraction.CSharp.Entities
public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init);
}
public override Type TypeRef => NamedTypeRef.Create(Context, symbol);
public override Type TypeRef => NamedTypeRef.Create(Context, this, symbol);
}
class NamedTypeRef : Type<INamedTypeSymbol>
class NamedTypeRef : Type<ITypeSymbol>
{
readonly Type referencedType;
public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol)
public NamedTypeRef(Context cx, Type type, ITypeSymbol symbol) : base(cx, symbol)
{
referencedType = Type.Create(cx, symbol);
referencedType = type;
}
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => NamedTypeRefFactory.Instance.CreateEntity2(cx, type);
public static NamedTypeRef Create(Context cx, Type referencedType, ITypeSymbol type) =>
NamedTypeRefFactory.Instance.CreateEntity2(cx, (referencedType, type));
class NamedTypeRefFactory : ICachedEntityFactory<INamedTypeSymbol, NamedTypeRef>
class NamedTypeRefFactory : ICachedEntityFactory<(Type, ITypeSymbol), NamedTypeRef>
{
public static readonly NamedTypeRefFactory Instance = new NamedTypeRefFactory();
public NamedTypeRef Create(Context cx, INamedTypeSymbol init) => new NamedTypeRef(cx, init);
public NamedTypeRef Create(Context cx, (Type, ITypeSymbol) init) => new NamedTypeRef(cx, init.Item1, init.Item2);
}
public override bool NeedsPopulation => true;
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(referencedType);
trapFile.Write(";typeRef");
void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub, ISymbol gc)
{
sub.BuildTypeId(cx0, tb0, ExpandType, TypeNameContext.TypeRef, gc);
}
// Prefix anonymous types because they shouldn't be visible outside of the current assembly.
symbol.BuildTypeId(Context, trapFile, ExpandType, TypeNameContext.TypeRef, symbol);
trapFile.Write(";typeref");
}
public override void Populate(TextWriter trapFile)

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol);
trapFile.Write(";tuple");
}
@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateGenerics();
var underlyingType = NamedType.Create(Context, symbol.TupleUnderlyingType);
trapFile.tuple_underlying_type(this, underlyingType);
trapFile.tuple_underlying_type(this, underlyingType.TypeRef);
int index = 0;
foreach (var element in TupleElements)

View File

@@ -95,6 +95,7 @@ namespace Semmle.Extraction.CSharp.Entities
var baseTypes = new List<Type>();
if (symbol.BaseType != null)
{
// !! Do not extend "object" if the base type is missing :-(
Type baseKey = Create(Context, symbol.BaseType);
trapFile.extend(this, baseKey.TypeRef);
if (symbol.TypeKind != TypeKind.Struct)
@@ -268,6 +269,10 @@ namespace Semmle.Extraction.CSharp.Entities
public static Type Create(Context cx, ITypeSymbol type)
{
type = type.DisambiguateType();
if (type is INamedTypeSymbol nt && nt.IsEvilTwin())
type = nt.ConstructedFrom;
const bool errorTypeIsNull = false;
return type == null || (errorTypeIsNull && type.TypeKind == TypeKind.Error) ?
NullType.Create(cx).Type : (Type)cx.CreateEntity(type);

View File

@@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
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, TypeNameContext.MethodParam); // Needed for op_explicit(), which differs only by return type.
trapFile.Write(' ');
BuildMethodId(this, trapFile);
}