mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #7646 from hvitved/csharp/roslyn-tuple-elements-workaround
C#: Workaround Roslyn bug in `INamedTypeSymbol.TupleElements`
This commit is contained in:
@@ -90,7 +90,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
var tts = (TupleTypeSyntax)syntax;
|
||||
var tt = (TupleType)type;
|
||||
Emit(trapFile, loc ?? syntax.GetLocation(), parent, type);
|
||||
tts.Elements.Zip(tt.TupleElements, (s, t) => Create(Context, s.Type, this, t.Type)).Enumerate();
|
||||
foreach (var (s, t) in tts.Elements.Zip(tt.TupleElements, (s, t) => (s, t?.Type)))
|
||||
{
|
||||
if (t is not null)
|
||||
Create(Context, s.Type, this, t);
|
||||
}
|
||||
return;
|
||||
case SyntaxKind.GenericName:
|
||||
Emit(trapFile, loc ?? syntax.GetLocation(), parent, type);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
private TupleType(Context cx, INamedTypeSymbol init) : base(cx, init)
|
||||
{
|
||||
tupleElementsLazy = new Lazy<Field[]>(() => Symbol.TupleElements.Select(t => Field.Create(cx, t)).ToArray());
|
||||
tupleElementsLazy = new Lazy<Field?[]>(() => Symbol.GetTupleElementsMaybeNull().Select(t => t is null ? null : Field.Create(cx, t)).ToArray());
|
||||
}
|
||||
|
||||
// All tuple types are "local types"
|
||||
@@ -47,7 +47,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
var index = 0;
|
||||
foreach (var element in TupleElements)
|
||||
trapFile.tuple_element(this, index++, element);
|
||||
{
|
||||
if (element is not null)
|
||||
trapFile.tuple_element(this, index++, element);
|
||||
}
|
||||
|
||||
// Note: symbol.Locations seems to be very inconsistent
|
||||
// about what locations are available for a tuple type.
|
||||
@@ -56,9 +59,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.type_location(this, Context.CreateLocation(l));
|
||||
}
|
||||
|
||||
private readonly Lazy<Field[]> tupleElementsLazy;
|
||||
public Field[] TupleElements => tupleElementsLazy.Value;
|
||||
private readonly Lazy<Field?[]> tupleElementsLazy;
|
||||
public Field?[] TupleElements => tupleElementsLazy.Value;
|
||||
|
||||
public override IEnumerable<Type> TypeMentions => TupleElements.Select(e => e.Type);
|
||||
public override IEnumerable<Type> TypeMentions =>
|
||||
TupleElements.OfType<Field>().Select(e => e.Type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,17 +280,30 @@ namespace Semmle.Extraction.CSharp
|
||||
private static void BuildFunctionPointerTypeId(this IFunctionPointerTypeSymbol funptr, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) =>
|
||||
BuildFunctionPointerSignature(funptr, trapFile, s => s.BuildOrWriteId(cx, trapFile, symbolBeingDefined));
|
||||
|
||||
/// <summary>
|
||||
/// Workaround for a Roslyn bug: https://github.com/dotnet/roslyn/issues/53943
|
||||
/// </summary>
|
||||
public static IEnumerable<IFieldSymbol?> GetTupleElementsMaybeNull(this INamedTypeSymbol type) =>
|
||||
type.TupleElements;
|
||||
|
||||
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
|
||||
{
|
||||
if (!constructUnderlyingTupleType && named.IsTupleType)
|
||||
{
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", named.TupleElements,
|
||||
f =>
|
||||
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
|
||||
(i, f) =>
|
||||
{
|
||||
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
|
||||
trapFile.Write(":");
|
||||
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
if (f is null)
|
||||
{
|
||||
trapFile.Write($"null({i})");
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
|
||||
trapFile.Write(":");
|
||||
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
}
|
||||
}
|
||||
);
|
||||
trapFile.Write(")");
|
||||
@@ -464,8 +477,14 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(
|
||||
",",
|
||||
namedType.TupleElements.Select(f => f.Type),
|
||||
t => t.BuildDisplayName(cx, trapFile));
|
||||
namedType.GetTupleElementsMaybeNull(),
|
||||
(i, f) =>
|
||||
{
|
||||
if (f is null)
|
||||
trapFile.Write($"null({i})");
|
||||
else
|
||||
f.Type.BuildDisplayName(cx, trapFile);
|
||||
});
|
||||
trapFile.Write(")");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -232,19 +232,33 @@ namespace Semmle.Extraction
|
||||
/// <param name="items">The list of items.</param>
|
||||
/// <param name="action">The action on each item.</param>
|
||||
/// <returns>The original trap builder (fluent interface).</returns>
|
||||
public static T1 BuildList<T1, T2>(this T1 trapFile, string separator, IEnumerable<T2> items, Action<T2> action)
|
||||
public static T1 BuildList<T1, T2>(this T1 trapFile, string separator, IEnumerable<T2> items, Action<int, T2> action)
|
||||
where T1 : TextWriter
|
||||
{
|
||||
var first = true;
|
||||
var i = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
trapFile.Write(separator);
|
||||
action(item);
|
||||
action(i++, item);
|
||||
}
|
||||
return trapFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a trap builder using a separator and an action for each item in the list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the items.</typeparam>
|
||||
/// <param name="trapFile">The trap builder to append to.</param>
|
||||
/// <param name="separator">The separator string (e.g. ",")</param>
|
||||
/// <param name="items">The list of items.</param>
|
||||
/// <param name="action">The action on each item.</param>
|
||||
/// <returns>The original trap builder (fluent interface).</returns>
|
||||
public static T1 BuildList<T1, T2>(this T1 trapFile, string separator, IEnumerable<T2> items, Action<T2> action)
|
||||
where T1 : TextWriter =>
|
||||
trapFile.BuildList(separator, items, (_, item) => action(item));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user