Skip to content

Commit fc121e1

Browse files
authored
Merge pull request github#5865 from tamasvajk/feature/remove-base-class-dependency-id
C#: Remove base class from type IDs in trap files
2 parents a247ae4 + 8e371fd commit fc121e1

File tree

10 files changed

+4240
-64
lines changed

10 files changed

+4240
-64
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ private static bool ContainsPattern(SyntaxNode node) =>
170170
public static Expression? CreateGenerated(Context cx, IParameterSymbol parameter, IExpressionParentEntity parent,
171171
int childIndex, Extraction.Entities.Location location)
172172
{
173-
if (!parameter.HasExplicitDefaultValue)
173+
if (!parameter.HasExplicitDefaultValue ||
174+
parameter.Type is IErrorTypeSymbol)
174175
{
175176
return null;
176177
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ private FunctionPointerType(Context cx, IFunctionPointerTypeSymbol init)
1313

1414
public override void WriteId(EscapingTextWriter trapFile)
1515
{
16-
Symbol.BuildTypeId(Context, trapFile, Symbol);
16+
Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false);
1717
trapFile.Write(";functionpointertype");
1818
}
1919

csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ private TupleType(Context cx, INamedTypeSymbol init) : base(cx, init)
3232

3333
public override void WriteId(EscapingTextWriter trapFile)
3434
{
35-
Symbol.BuildTypeId(Context, trapFile, Symbol);
35+
Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false);
3636
trapFile.Write(";tuple");
3737
}
3838

csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,45 @@ protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleTy
8181
Symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType);
8282
trapFile.WriteLine("\")");
8383

84+
var baseTypes = GetBaseTypeDeclarations();
85+
8486
// Visit base types
85-
var baseTypes = new List<Type>();
8687
if (Symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base)
8788
{
88-
var baseKey = Create(Context, @base);
89-
trapFile.extend(this, baseKey.TypeRef);
90-
if (Symbol.TypeKind != TypeKind.Struct)
91-
baseTypes.Add(baseKey);
89+
var bts = GetBaseTypeDeclarations(baseTypes, @base);
90+
91+
Context.PopulateLater(() =>
92+
{
93+
var baseKey = Create(Context, @base);
94+
trapFile.extend(this, baseKey.TypeRef);
95+
96+
if (Symbol.TypeKind != TypeKind.Struct)
97+
{
98+
foreach (var bt in bts)
99+
{
100+
TypeMention.Create(Context, bt.Type, this, baseKey);
101+
}
102+
}
103+
});
92104
}
93105

106+
// Visit implemented interfaces
94107
if (!(base.Symbol is IArrayTypeSymbol))
95108
{
96-
foreach (var t in base.Symbol.Interfaces.Select(i => Create(Context, i)))
109+
foreach (var i in base.Symbol.Interfaces)
97110
{
98-
trapFile.implement(this, t.TypeRef);
99-
baseTypes.Add(t);
111+
var bts = GetBaseTypeDeclarations(baseTypes, i);
112+
113+
Context.PopulateLater(() =>
114+
{
115+
var interfaceKey = Create(Context, i);
116+
trapFile.implement(this, interfaceKey.TypeRef);
117+
118+
foreach (var bt in bts)
119+
{
120+
TypeMention.Create(Context, bt.Type, this, interfaceKey);
121+
}
122+
});
100123
}
101124
}
102125

@@ -145,23 +168,30 @@ protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleTy
145168
}
146169

147170
Modifier.ExtractModifiers(Context, trapFile, this, Symbol);
171+
}
148172

149-
if (IsSourceDeclaration && Symbol.FromSource())
173+
private IEnumerable<BaseTypeSyntax> GetBaseTypeDeclarations()
174+
{
175+
if (!IsSourceDeclaration || !Symbol.FromSource())
150176
{
151-
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray();
152-
153-
var baseLists = declSyntaxReferences.OfType<ClassDeclarationSyntax>().Select(c => c.BaseList);
154-
baseLists = baseLists.Concat(declSyntaxReferences.OfType<InterfaceDeclarationSyntax>().Select(c => c.BaseList));
155-
baseLists = baseLists.Concat(declSyntaxReferences.OfType<StructDeclarationSyntax>().Select(c => c.BaseList));
156-
157-
baseLists
158-
.Where(bl => bl is not null)
159-
.SelectMany(bl => bl!.Types)
160-
.Zip(
161-
baseTypes.Where(bt => bt.Symbol.SpecialType != SpecialType.System_Object),
162-
(s, t) => TypeMention.Create(Context, s.Type, this, t))
163-
.Enumerate();
177+
return Enumerable.Empty<BaseTypeSyntax>();
164178
}
179+
180+
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray();
181+
182+
var baseLists = declSyntaxReferences.OfType<ClassDeclarationSyntax>().Select(c => c.BaseList);
183+
baseLists = baseLists.Concat(declSyntaxReferences.OfType<InterfaceDeclarationSyntax>().Select(c => c.BaseList));
184+
baseLists = baseLists.Concat(declSyntaxReferences.OfType<StructDeclarationSyntax>().Select(c => c.BaseList));
185+
186+
return baseLists
187+
.Where(bl => bl is not null)
188+
.SelectMany(bl => bl!.Types)
189+
.ToList();
190+
}
191+
192+
private IEnumerable<BaseTypeSyntax> GetBaseTypeDeclarations(IEnumerable<BaseTypeSyntax> baseTypes, INamedTypeSymbol type)
193+
{
194+
return baseTypes.Where(bt => SymbolEqualityComparer.Default.Equals(Context.GetModel(bt).GetTypeInfo(bt.Type).Type, type));
165195
}
166196

167197
private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSymbol invokeMethod, Action<Type> storeReturnType)

csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ bool IdDependsOnImpl(ITypeSymbol? type)
121121
named = named.TupleUnderlyingType;
122122
if (IdDependsOnImpl(named.ContainingType))
123123
return true;
124-
if (IdDependsOnImpl(named.GetNonObjectBaseType(cx)))
125-
return true;
126124
if (IdDependsOnImpl(named.ConstructedFrom))
127125
return true;
128126
return named.TypeArguments.Any(IdDependsOnImpl);
@@ -160,18 +158,15 @@ bool IdDependsOnImpl(ITypeSymbol? type)
160158
/// <param name="trapFile">The trap builder used to store the result.</param>
161159
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
162160
/// <param name="constructUnderlyingTupleType">Whether to build a type ID for the underlying `System.ValueTuple` struct in the case of tuple types.</param>
163-
public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType = false) =>
164-
type.BuildTypeId(cx, trapFile, symbolBeingDefined, true, constructUnderlyingTupleType);
165-
166-
private static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
161+
public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
167162
{
168163
using (cx.StackGuard)
169164
{
170165
switch (type.TypeKind)
171166
{
172167
case TypeKind.Array:
173168
var array = (IArrayTypeSymbol)type;
174-
array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
169+
array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
175170
array.BuildArraySuffix(trapFile);
176171
return;
177172
case TypeKind.Class:
@@ -181,16 +176,16 @@ private static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextW
181176
case TypeKind.Delegate:
182177
case TypeKind.Error:
183178
var named = (INamedTypeSymbol)type;
184-
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
179+
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
185180
return;
186181
case TypeKind.Pointer:
187182
var ptr = (IPointerTypeSymbol)type;
188-
ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
183+
ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
189184
trapFile.Write('*');
190185
return;
191186
case TypeKind.TypeParameter:
192187
var tp = (ITypeParameterSymbol)type;
193-
tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
188+
tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
194189
trapFile.Write('_');
195190
trapFile.Write(tp.Name);
196191
return;
@@ -207,7 +202,7 @@ private static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextW
207202
}
208203
}
209204

210-
private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType = false)
205+
private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
211206
{
212207
if (symbol is null)
213208
{
@@ -232,7 +227,7 @@ private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTex
232227
if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined))
233228
trapFile.Write("__self__");
234229
else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined))
235-
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
230+
type.BuildTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
236231
else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && constructUnderlyingTupleType)
237232
trapFile.WriteSubId(NamedType.CreateNamedTypeFromTupleType(cx, namedType));
238233
else
@@ -250,7 +245,7 @@ private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTex
250245
/// <paramref name="symbol" />.
251246
/// </summary>
252247
public static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) =>
253-
symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, true);
248+
symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
254249

255250
/// <summary>
256251
/// Constructs an array suffix string for this array type symbol.
@@ -287,7 +282,7 @@ private static void BuildFunctionPointerTypeId(this IFunctionPointerTypeSymbol f
287282
BuildFunctionPointerSignature(funptr, trapFile, s => s.BuildOrWriteId(cx, trapFile, symbolBeingDefined));
288283
}
289284

290-
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
285+
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
291286
{
292287
if (!constructUnderlyingTupleType && named.IsTupleType)
293288
{
@@ -297,7 +292,7 @@ private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, Es
297292
{
298293
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
299294
trapFile.Write(":");
300-
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
295+
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
301296
}
302297
);
303298
trapFile.Write(")");
@@ -308,7 +303,7 @@ void AddContaining()
308303
{
309304
if (named.ContainingType is not null)
310305
{
311-
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
306+
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
312307
trapFile.Write('.');
313308
}
314309
else if (named.ContainingNamespace is not null)
@@ -333,35 +328,17 @@ void AddContaining()
333328
}
334329
else
335330
{
336-
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
331+
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
337332
trapFile.Write('<');
338333
// Encode the nullability of the type arguments in the label.
339334
// Type arguments with different nullability can result in
340335
// a constructed type with different nullability of its members and methods,
341336
// so we need to create a distinct database entity for it.
342337
trapFile.BuildList(",", named.GetAnnotatedTypeArguments(),
343-
ta => ta.Symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass)
338+
ta => ta.Symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false)
344339
);
345340
trapFile.Write('>');
346341
}
347-
348-
if (addBaseClass && named.GetNonObjectBaseType(cx) is INamedTypeSymbol @base)
349-
{
350-
// We need to limit unfolding of base classes. For example, in
351-
//
352-
// ```csharp
353-
// class C1<T> { }
354-
// class C2<T> : C1<C3<T>> { }
355-
// class C3<T> : C1<C2<T>> { }
356-
// class C4 : C3<C4> { }
357-
// ```
358-
//
359-
// when we generate the label for `C4`, the base class `C3<C4>` has itself `C1<C2<C4>>` as
360-
// a base class, which in turn has `C1<C3<C4>>` as a base class. The latter has the original
361-
// base class `C3<C4>` as a type argument, which would lead to infinite unfolding.
362-
trapFile.Write(" : ");
363-
@base.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass: false);
364-
}
365342
}
366343

367344
private static void BuildNamespace(this INamespaceSymbol ns, Context cx, EscapingTextWriter trapFile)

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ function_pointer_return_type(
529529
int return_type_id: @type_or_ref ref);
530530

531531
extend(
532-
unique int sub: @type ref,
532+
int sub: @type ref,
533533
int super: @type_or_ref ref);
534534

535535
anonymous_types(

csharp/ql/test/experimental/ir/ir/raw_ir.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,13 +613,13 @@ foreach.cs:
613613
# 5| r5_28(glval<Int32>) = PointerAdd[4] : r5_1, r5_27
614614
# 5| r5_29(Int32) = Constant[7] :
615615
# 5| mu5_30(Int32) = Store[?] : &:r5_28, r5_29
616-
# 7| r7_1(glval<IEnumerator>) = VariableAddress[#temp7:9] :
616+
# 7| r7_1(glval<Boolean>) = VariableAddress[#temp7:9] :
617617
# 7| r7_2(glval<Int32[]>) = VariableAddress[a_array] :
618618
# 7| r7_3(Int32[]) = Load[a_array] : &:r7_2, ~m?
619619
# 7| r7_4(<funcaddr>) = FunctionAddress[GetEnumerator] :
620620
# 7| r7_5(IEnumerator) = Call[GetEnumerator] : func:r7_4, this:r7_3
621621
# 7| mu7_6(<unknown>) = ^CallSideEffect : ~m?
622-
# 7| mu7_7(IEnumerator) = Store[#temp7:9] : &:r7_1, r7_5
622+
# 7| mu7_7(Boolean) = Store[#temp7:9] : &:r7_1, r7_5
623623
#-----| Goto -> Block 1
624624

625625
# 7| Block 1

0 commit comments

Comments
 (0)