Add workaround for equal lambda parameter symbols with different hashcodes

This commit is contained in:
Tamas Vajk
2021-12-13 11:59:24 +01:00
parent d2822c2acc
commit 26194be8b6
3 changed files with 41 additions and 4 deletions

View File

@@ -18,6 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private void VisitParameter(ParameterSyntax p)
{
var symbol = Context.GetModel(p).GetDeclaredSymbol(p)!;
Context.CacheLambdaParameterSymbol(symbol, p);
Parameter.Create(Context, symbol, this);
}

View File

@@ -55,11 +55,17 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) =>
ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original));
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null)
{
var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param);
return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original));
}
public static Parameter Create(Context cx, IParameterSymbol param) =>
ParameterFactory.Instance.CreateEntity(cx, param, (param, null, null));
public static Parameter Create(Context cx, IParameterSymbol param)
{
var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param);
return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null));
}
public override void WriteId(EscapingTextWriter trapFile)
{

View File

@@ -39,6 +39,36 @@ namespace Semmle.Extraction.CSharp
private SemanticModel? cachedModelForTree;
private SemanticModel? cachedModelForOtherTrees;
// The below is a workaround to the bug reported in https://github.com/dotnet/roslyn/issues/58226
// Lambda parameters that are equal according to `SymbolEqualityComparer.Default`, might have different
// hash-codes, and as a result might not be found in `symbolEntityCache` by hash-code lookup.
internal IParameterSymbol GetPossiblyCachedParameterSymbol(IParameterSymbol param)
{
if ((param.ContainingSymbol as IMethodSymbol)?.MethodKind != MethodKind.AnonymousFunction)
{
return param;
}
foreach (var sr in param.DeclaringSyntaxReferences)
{
var syntax = sr.GetSyntax();
if (lambdaParameterCache.TryGetValue(syntax, out var cached) &&
SymbolEqualityComparer.Default.Equals(param, cached))
{
return cached;
}
}
return param;
}
internal void CacheLambdaParameterSymbol(IParameterSymbol param, SyntaxNode syntax)
{
lambdaParameterCache[syntax] = param;
}
private readonly Dictionary<SyntaxNode, IParameterSymbol> lambdaParameterCache = new Dictionary<SyntaxNode, IParameterSymbol>();
/// <summary>
/// The current compilation unit.
/// </summary>