Skip to content

Commit 1974602

Browse files
committed
C#: Tidy code for constructing underlying tuple structs
1 parent 6c5b30d commit 1974602

3 files changed

Lines changed: 34 additions & 25 deletions

File tree

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@ namespace Semmle.Extraction.CSharp.Entities
1111
{
1212
class NamedType : Type<INamedTypeSymbol>
1313
{
14-
NamedType(Context cx, INamedTypeSymbol init, bool fromTuple)
14+
NamedType(Context cx, INamedTypeSymbol init, bool constructUnderlyingTupleType)
1515
: base(cx, init)
1616
{
1717
typeArgumentsLazy = new Lazy<Type[]>(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray());
18-
this.fromTuple = fromTuple;
18+
this.constructUnderlyingTupleType = constructUnderlyingTupleType;
1919
}
2020

2121
public static NamedType Create(Context cx, INamedTypeSymbol type) =>
2222
type.IsTupleType
2323
? NamedTupleTypeFactory.Instance.CreateEntity(cx, (type, false), (type, false))
2424
: NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
2525

26+
/// <summary>
27+
/// Creates a named type entity from a tuple type. Unlike `Create`, this
28+
/// will create an entity for the underlying `System.ValueTuple` struct.
29+
/// For example, `(int, string)` will result in an entity for
30+
/// `System.ValueTuple<int, string>`.
31+
/// </summary>
2632
public static NamedType CreateNamedTypeFromTupleType(Context cx, INamedTypeSymbol type) =>
2733
NamedTupleTypeFactory.Instance.CreateEntity(cx, (type, true), (type, true));
2834

@@ -58,7 +64,9 @@ public override void Populate(TextWriter trapFile)
5864
}
5965
else
6066
{
61-
var unbound = fromTuple ? CreateNamedTypeFromTupleType(Context, symbol.ConstructedFrom) : Type.Create(Context, symbol.ConstructedFrom);
67+
var unbound = constructUnderlyingTupleType
68+
? CreateNamedTypeFromTupleType(Context, symbol.ConstructedFrom)
69+
: Type.Create(Context, symbol.ConstructedFrom);
6270
trapFile.constructed_generic(this, unbound.TypeRef);
6371

6472
for (int i = 0; i < symbol.TypeArguments.Length; ++i)
@@ -68,7 +76,7 @@ public override void Populate(TextWriter trapFile)
6876
}
6977
}
7078

71-
PopulateType(trapFile, getTupleAsTuple: !fromTuple);
79+
PopulateType(trapFile, constructUnderlyingTupleType);
7280

7381
if (symbol.EnumUnderlyingType != null)
7482
{
@@ -84,7 +92,7 @@ public override void Populate(TextWriter trapFile)
8492
}
8593

8694
readonly Lazy<Type[]> typeArgumentsLazy;
87-
private readonly bool fromTuple;
95+
private readonly bool constructUnderlyingTupleType;
8896

8997
public Type[] TypeArguments => typeArgumentsLazy.Value;
9098

@@ -125,7 +133,7 @@ public override void WriteId(TextWriter trapFile)
125133
trapFile.Write('*');
126134
else
127135
{
128-
symbol.BuildTypeId(Context, trapFile, symbol, getTupleAsTuple: !fromTuple);
136+
symbol.BuildTypeId(Context, trapFile, symbol, constructUnderlyingTupleType);
129137
trapFile.Write(";type");
130138
}
131139
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static bool ConstructedOrParentIsConstructed(INamedTypeSymbol symbol)
4747
symbol.ContainingType != null && ConstructedOrParentIsConstructed(symbol.ContainingType);
4848
}
4949

50-
static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t, bool getTupleAsTuple)
50+
static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t, bool constructUnderlyingTupleType)
5151
{
5252
switch (t.SpecialType)
5353
{
@@ -72,7 +72,7 @@ static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t, bool getTupleAsTup
7272
{
7373
case TypeKind.Class: return Kinds.TypeKind.CLASS;
7474
case TypeKind.Struct:
75-
return ((INamedTypeSymbol)t).IsTupleType && getTupleAsTuple
75+
return ((INamedTypeSymbol)t).IsTupleType && !constructUnderlyingTupleType
7676
? Kinds.TypeKind.TUPLE
7777
: Kinds.TypeKind.STRUCT;
7878
case TypeKind.Interface: return Kinds.TypeKind.INTERFACE;
@@ -87,17 +87,17 @@ static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t, bool getTupleAsTup
8787
}
8888
}
8989

90-
protected void PopulateType(TextWriter trapFile, bool getTupleAsTuple = true)
90+
protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleType = false)
9191
{
9292
PopulateMetadataHandle(trapFile);
9393
PopulateAttributes();
9494

9595
trapFile.Write("types(");
9696
trapFile.WriteColumn(this);
9797
trapFile.Write(',');
98-
trapFile.WriteColumn((int)GetClassType(Context, symbol, getTupleAsTuple));
98+
trapFile.WriteColumn((int)GetClassType(Context, symbol, constructUnderlyingTupleType));
9999
trapFile.Write(",\"");
100-
symbol.BuildDisplayName(Context, trapFile, getTupleAsTuple);
100+
symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType);
101101
trapFile.WriteLine("\")");
102102

103103
// Visit base types

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

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,11 @@ bool IdDependsOnImpl(ITypeSymbol type)
152152
/// <param name="cx">The extraction context.</param>
153153
/// <param name="trapFile">The trap builder used to store the result.</param>
154154
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
155-
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool getTupleAsTuple = true) =>
156-
type.BuildTypeId(cx, trapFile, symbolBeingDefined, true, getTupleAsTuple);
155+
/// <param name="constructUnderlyingTupleType">Whether to build a type ID for the underlying `System.ValueTuple` struct in the case of tuple types.</param>
156+
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType = false) =>
157+
type.BuildTypeId(cx, trapFile, symbolBeingDefined, true, constructUnderlyingTupleType);
157158

158-
static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool getTupleAsTuple)
159+
static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
159160
{
160161
using (cx.StackGuard)
161162
{
@@ -173,7 +174,7 @@ static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile,
173174
case TypeKind.Delegate:
174175
case TypeKind.Error:
175176
var named = (INamedTypeSymbol)type;
176-
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, getTupleAsTuple);
177+
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
177178
return;
178179
case TypeKind.Pointer:
179180
var ptr = (IPointerTypeSymbol)type;
@@ -195,7 +196,7 @@ static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile,
195196
}
196197
}
197198

198-
static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool getTupleAsTuple = true)
199+
static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType = false)
199200
{
200201
// We need to keep track of the symbol being defined in order to avoid cyclic labels.
201202
// For example, in
@@ -214,8 +215,8 @@ static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile,
214215
if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined))
215216
trapFile.Write("__self__");
216217
else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined))
217-
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, getTupleAsTuple);
218-
else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && !getTupleAsTuple)
218+
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
219+
else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && constructUnderlyingTupleType)
219220
trapFile.WriteSubId(NamedType.CreateNamedTypeFromTupleType(cx, namedType));
220221
else
221222
trapFile.WriteSubId(CreateEntity(cx, symbol));
@@ -264,9 +265,9 @@ private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool
264265
trapFile.Write("::");
265266
}
266267

267-
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool getTupleAsTuple)
268+
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
268269
{
269-
if (getTupleAsTuple && named.IsTupleType)
270+
if (!constructUnderlyingTupleType && named.IsTupleType)
270271
{
271272
trapFile.Write('(');
272273
trapFile.BuildList(",", named.TupleElements,
@@ -310,7 +311,7 @@ void AddContaining()
310311
}
311312
else
312313
{
313-
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass, getTupleAsTuple);
314+
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType);
314315
trapFile.Write('<');
315316
// Encode the nullability of the type arguments in the label.
316317
// Type arguments with different nullability can result in
@@ -362,7 +363,7 @@ static void BuildAnonymousName(this INamedTypeSymbol type, Context cx, TextWrite
362363
/// Constructs a display name string for this type symbol.
363364
/// </summary>
364365
/// <param name="trapFile">The trap builder used to store the result.</param>
365-
public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWriter trapFile, bool getTupleAsTuple = true)
366+
public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType = false)
366367
{
367368
using (cx.StackGuard)
368369
{
@@ -386,7 +387,7 @@ public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWrite
386387
case TypeKind.Delegate:
387388
case TypeKind.Error:
388389
var named = (INamedTypeSymbol)type;
389-
named.BuildNamedTypeDisplayName(cx, trapFile, getTupleAsTuple);
390+
named.BuildNamedTypeDisplayName(cx, trapFile, constructUnderlyingTupleType);
390391
return;
391392
case TypeKind.Pointer:
392393
var ptr = (IPointerTypeSymbol)type;
@@ -405,9 +406,9 @@ public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWrite
405406
}
406407
}
407408

408-
public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool getTupleAsTuple)
409+
public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType)
409410
{
410-
if (getTupleAsTuple && namedType.IsTupleType)
411+
if (!constructUnderlyingTupleType && namedType.IsTupleType)
411412
{
412413
trapFile.Write('(');
413414
trapFile.BuildList(",", namedType.TupleElements.Select(f => f.Type),

0 commit comments

Comments
 (0)