-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Closed
Description
The binder from GetBinder all in TryBindNameofOperator should never be null.
But currently, it could be during speculation using a MethodBodySemanticModel (see test below, which would crash without this mitigation).
This also happens in completion scenarios in the IDE (see tests that use skipSpeculation and are marked with the current issue).
In short, the model returned by TryGetSpeculativeSemanticModelForMethodBody should not directly try to bind the expression, it should first create an AttributeSemanticModel first in some cases.
This affects new nameof scenarios (test plan), but likely other existing scenarios too.
private bool TryBindNameofOperator(InvocationExpressionSyntax node, BindingDiagnosticBag diagnostics, out BoundExpression result)
{
if (node.MayBeNameofOperator())
{
var binder = this.GetBinder(node);
if (binder is null)
{
// This could happen during speculation due to a bug, but should be removed
// Tracked by https://github.com/dotnet/roslyn/issues/60801
result = null;
return false;
}
if (binder.EnclosingNameofArgument == node.ArgumentList.Arguments[0].Expression)
{
result = binder.BindNameofOperatorInternal(node, diagnostics);
return true;
}
}
result = null;
return false;
}
[Fact]
public void ParameterScope_InMethodAttributeNameOf_GetSymbolInfoOnSpeculativeMethodBodySemanticModel()
{
var source = @"
class C
{
void M()
{
[My(nameof(parameter))]
void local(int parameter) { }
}
}
public class MyAttribute : System.Attribute
{
public MyAttribute(string name1) { }
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext);
comp.VerifyDiagnostics(
// (7,14): warning CS8321: The local function 'local' is declared but never used
// void local(int parameter) { }
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14)
);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var tree2 = CSharpSyntaxTree.ParseText(source);
var method = tree2.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel));
var invocation = tree2.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
Assert.Equal("nameof(parameter)", invocation.ToString());
var symbolInfo = speculativeModel.GetSymbolInfo(invocation);
Assert.Null(symbolInfo.Symbol);
}
Note to self: I have some notes from brainstorming with Aleksey on how to fix this.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Done