Merge pull request #5865 from tamasvajk/feature/remove-base-class-dependency-id

C#: Remove base class from type IDs in trap files
This commit is contained in:
Tom Hvitved
2021-05-12 10:30:31 +02:00
committed by GitHub
10 changed files with 4240 additions and 64 deletions

View File

@@ -170,7 +170,8 @@ namespace Semmle.Extraction.CSharp.Entities
public static Expression? CreateGenerated(Context cx, IParameterSymbol parameter, IExpressionParentEntity parent,
int childIndex, Extraction.Entities.Location location)
{
if (!parameter.HasExplicitDefaultValue)
if (!parameter.HasExplicitDefaultValue ||
parameter.Type is IErrorTypeSymbol)
{
return null;
}

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(EscapingTextWriter trapFile)
{
Symbol.BuildTypeId(Context, trapFile, Symbol);
Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false);
trapFile.Write(";functionpointertype");
}

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(EscapingTextWriter trapFile)
{
Symbol.BuildTypeId(Context, trapFile, Symbol);
Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false);
trapFile.Write(";tuple");
}

View File

@@ -81,22 +81,45 @@ namespace Semmle.Extraction.CSharp.Entities
Symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType);
trapFile.WriteLine("\")");
var baseTypes = GetBaseTypeDeclarations();
// Visit base types
var baseTypes = new List<Type>();
if (Symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base)
{
var baseKey = Create(Context, @base);
trapFile.extend(this, baseKey.TypeRef);
if (Symbol.TypeKind != TypeKind.Struct)
baseTypes.Add(baseKey);
var bts = GetBaseTypeDeclarations(baseTypes, @base);
Context.PopulateLater(() =>
{
var baseKey = Create(Context, @base);
trapFile.extend(this, baseKey.TypeRef);
if (Symbol.TypeKind != TypeKind.Struct)
{
foreach (var bt in bts)
{
TypeMention.Create(Context, bt.Type, this, baseKey);
}
}
});
}
// Visit implemented interfaces
if (!(base.Symbol is IArrayTypeSymbol))
{
foreach (var t in base.Symbol.Interfaces.Select(i => Create(Context, i)))
foreach (var i in base.Symbol.Interfaces)
{
trapFile.implement(this, t.TypeRef);
baseTypes.Add(t);
var bts = GetBaseTypeDeclarations(baseTypes, i);
Context.PopulateLater(() =>
{
var interfaceKey = Create(Context, i);
trapFile.implement(this, interfaceKey.TypeRef);
foreach (var bt in bts)
{
TypeMention.Create(Context, bt.Type, this, interfaceKey);
}
});
}
}
@@ -145,23 +168,30 @@ namespace Semmle.Extraction.CSharp.Entities
}
Modifier.ExtractModifiers(Context, trapFile, this, Symbol);
}
if (IsSourceDeclaration && Symbol.FromSource())
private IEnumerable<BaseTypeSyntax> GetBaseTypeDeclarations()
{
if (!IsSourceDeclaration || !Symbol.FromSource())
{
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray();
var baseLists = declSyntaxReferences.OfType<ClassDeclarationSyntax>().Select(c => c.BaseList);
baseLists = baseLists.Concat(declSyntaxReferences.OfType<InterfaceDeclarationSyntax>().Select(c => c.BaseList));
baseLists = baseLists.Concat(declSyntaxReferences.OfType<StructDeclarationSyntax>().Select(c => c.BaseList));
baseLists
.Where(bl => bl is not null)
.SelectMany(bl => bl!.Types)
.Zip(
baseTypes.Where(bt => bt.Symbol.SpecialType != SpecialType.System_Object),
(s, t) => TypeMention.Create(Context, s.Type, this, t))
.Enumerate();
return Enumerable.Empty<BaseTypeSyntax>();
}
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray();
var baseLists = declSyntaxReferences.OfType<ClassDeclarationSyntax>().Select(c => c.BaseList);
baseLists = baseLists.Concat(declSyntaxReferences.OfType<InterfaceDeclarationSyntax>().Select(c => c.BaseList));
baseLists = baseLists.Concat(declSyntaxReferences.OfType<StructDeclarationSyntax>().Select(c => c.BaseList));
return baseLists
.Where(bl => bl is not null)
.SelectMany(bl => bl!.Types)
.ToList();
}
private IEnumerable<BaseTypeSyntax> GetBaseTypeDeclarations(IEnumerable<BaseTypeSyntax> baseTypes, INamedTypeSymbol type)
{
return baseTypes.Where(bt => SymbolEqualityComparer.Default.Equals(Context.GetModel(bt).GetTypeInfo(bt.Type).Type, type));
}
private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSymbol invokeMethod, Action<Type> storeReturnType)

View File

@@ -121,8 +121,6 @@ namespace Semmle.Extraction.CSharp
named = named.TupleUnderlyingType;
if (IdDependsOnImpl(named.ContainingType))
return true;
if (IdDependsOnImpl(named.GetNonObjectBaseType(cx)))
return true;
if (IdDependsOnImpl(named.ConstructedFrom))
return true;
return named.TypeArguments.Any(IdDependsOnImpl);
@@ -160,10 +158,7 @@ namespace Semmle.Extraction.CSharp
/// <param name="trapFile">The trap builder used to store the result.</param>
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
/// <param name="constructUnderlyingTupleType">Whether to build a type ID for the underlying `System.ValueTuple` struct in the case of tuple types.</param>
public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType = false) =>
type.BuildTypeId(cx, trapFile, symbolBeingDefined, true, constructUnderlyingTupleType);
private static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
{
using (cx.StackGuard)
{
@@ -171,7 +166,7 @@ namespace Semmle.Extraction.CSharp
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
array.BuildArraySuffix(trapFile);
return;
case TypeKind.Class:
@@ -181,16 +176,16 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
return;
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('*');
return;
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('_');
trapFile.Write(tp.Name);
return;
@@ -207,7 +202,7 @@ namespace Semmle.Extraction.CSharp
}
}
private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType = false)
private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
{
if (symbol is null)
{
@@ -232,7 +227,7 @@ namespace Semmle.Extraction.CSharp
if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined))
trapFile.Write("__self__");
else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined))
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
type.BuildTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && constructUnderlyingTupleType)
trapFile.WriteSubId(NamedType.CreateNamedTypeFromTupleType(cx, namedType));
else
@@ -250,7 +245,7 @@ namespace Semmle.Extraction.CSharp
/// <paramref name="symbol" />.
/// </summary>
public static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) =>
symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, true);
symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
/// <summary>
/// Constructs an array suffix string for this array type symbol.
@@ -287,7 +282,7 @@ namespace Semmle.Extraction.CSharp
BuildFunctionPointerSignature(funptr, trapFile, s => s.BuildOrWriteId(cx, trapFile, symbolBeingDefined));
}
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
{
if (!constructUnderlyingTupleType && named.IsTupleType)
{
@@ -297,7 +292,7 @@ namespace Semmle.Extraction.CSharp
{
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
trapFile.Write(":");
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
}
);
trapFile.Write(")");
@@ -308,7 +303,7 @@ namespace Semmle.Extraction.CSharp
{
if (named.ContainingType is not null)
{
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('.');
}
else if (named.ContainingNamespace is not null)
@@ -333,35 +328,17 @@ namespace Semmle.Extraction.CSharp
}
else
{
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
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 => ta.Symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass)
ta => ta.Symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false)
);
trapFile.Write('>');
}
if (addBaseClass && named.GetNonObjectBaseType(cx) is INamedTypeSymbol @base)
{
// We need to limit unfolding of base classes. For example, in
//
// ```csharp
// class C1<T> { }
// class C2<T> : C1<C3<T>> { }
// class C3<T> : C1<C2<T>> { }
// class C4 : C3<C4> { }
// ```
//
// when we generate the label for `C4`, the base class `C3<C4>` has itself `C1<C2<C4>>` as
// a base class, which in turn has `C1<C3<C4>>` as a base class. The latter has the original
// base class `C3<C4>` as a type argument, which would lead to infinite unfolding.
trapFile.Write(" : ");
@base.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass: false);
}
}
private static void BuildNamespace(this INamespaceSymbol ns, Context cx, EscapingTextWriter trapFile)

View File

@@ -529,7 +529,7 @@ function_pointer_return_type(
int return_type_id: @type_or_ref ref);
extend(
unique int sub: @type ref,
int sub: @type ref,
int super: @type_or_ref ref);
anonymous_types(

View File

@@ -613,13 +613,13 @@ foreach.cs:
# 5| r5_28(glval<Int32>) = PointerAdd[4] : r5_1, r5_27
# 5| r5_29(Int32) = Constant[7] :
# 5| mu5_30(Int32) = Store[?] : &:r5_28, r5_29
# 7| r7_1(glval<IEnumerator>) = VariableAddress[#temp7:9] :
# 7| r7_1(glval<Boolean>) = VariableAddress[#temp7:9] :
# 7| r7_2(glval<Int32[]>) = VariableAddress[a_array] :
# 7| r7_3(Int32[]) = Load[a_array] : &:r7_2, ~m?
# 7| r7_4(<funcaddr>) = FunctionAddress[GetEnumerator] :
# 7| r7_5(IEnumerator) = Call[GetEnumerator] : func:r7_4, this:r7_3
# 7| mu7_6(<unknown>) = ^CallSideEffect : ~m?
# 7| mu7_7(IEnumerator) = Store[#temp7:9] : &:r7_1, r7_5
# 7| mu7_7(Boolean) = Store[#temp7:9] : &:r7_1, r7_5
#-----| Goto -> Block 1
# 7| Block 1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Removed unique base class constraint
compatibility: backwards