Skip to content

Commit 26194be

Browse files
committed
Add workaround for equal lambda parameter symbols with different hashcodes
1 parent d2822c2 commit 26194be

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ protected override void PopulateExpression(TextWriter trapFile) { }
1818
private void VisitParameter(ParameterSyntax p)
1919
{
2020
var symbol = Context.GetModel(p).GetDeclaredSymbol(p)!;
21+
Context.CacheLambdaParameterSymbol(symbol, p);
2122
Parameter.Create(Context, symbol, this);
2223
}
2324

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,17 @@ private Kind ParamKind
5555
}
5656
}
5757

58-
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) =>
59-
ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original));
58+
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null)
59+
{
60+
var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param);
61+
return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original));
62+
}
6063

61-
public static Parameter Create(Context cx, IParameterSymbol param) =>
62-
ParameterFactory.Instance.CreateEntity(cx, param, (param, null, null));
64+
public static Parameter Create(Context cx, IParameterSymbol param)
65+
{
66+
var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param);
67+
return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null));
68+
}
6369

6470
public override void WriteId(EscapingTextWriter trapFile)
6571
{

csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,36 @@ public SemanticModel GetModel(SyntaxNode node)
3939
private SemanticModel? cachedModelForTree;
4040
private SemanticModel? cachedModelForOtherTrees;
4141

42+
// The below is a workaround to the bug reported in https://github.com/dotnet/roslyn/issues/58226
43+
// Lambda parameters that are equal according to `SymbolEqualityComparer.Default`, might have different
44+
// hash-codes, and as a result might not be found in `symbolEntityCache` by hash-code lookup.
45+
internal IParameterSymbol GetPossiblyCachedParameterSymbol(IParameterSymbol param)
46+
{
47+
if ((param.ContainingSymbol as IMethodSymbol)?.MethodKind != MethodKind.AnonymousFunction)
48+
{
49+
return param;
50+
}
51+
52+
foreach (var sr in param.DeclaringSyntaxReferences)
53+
{
54+
var syntax = sr.GetSyntax();
55+
if (lambdaParameterCache.TryGetValue(syntax, out var cached) &&
56+
SymbolEqualityComparer.Default.Equals(param, cached))
57+
{
58+
return cached;
59+
}
60+
}
61+
62+
return param;
63+
}
64+
65+
internal void CacheLambdaParameterSymbol(IParameterSymbol param, SyntaxNode syntax)
66+
{
67+
lambdaParameterCache[syntax] = param;
68+
}
69+
70+
private readonly Dictionary<SyntaxNode, IParameterSymbol> lambdaParameterCache = new Dictionary<SyntaxNode, IParameterSymbol>();
71+
4272
/// <summary>
4373
/// The current compilation unit.
4474
/// </summary>

0 commit comments

Comments
 (0)