提交 fdcbad2b 编写于 作者: A AlekseyTs

Merge pull request #4321 from AlekseyTs/Issue4028

Handle MemberBindingExpression in Binder.GetEventSymbol
......@@ -1559,6 +1559,9 @@ private static EventSymbol GetEventSymbol(BoundExpression expr, out BoundExpress
case SyntaxKind.IdentifierName:
eventSyntax = syntax;
break;
case SyntaxKind.MemberBindingExpression:
eventSyntax = ((MemberBindingExpressionSyntax)syntax).Name;
break;
default:
throw ExceptionUtilities.UnexpectedValue(syntax.Kind());
}
......
......@@ -1248,5 +1248,157 @@ interface I<in T, out U> {{ }}";
}
}
}
[Fact, WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")]
public void ConditionalAccessToEvent_01()
{
string source = @"
using System;
class TestClass
{
event Action test;
public static void Test(TestClass receiver)
{
Console.WriteLine(receiver?.test);
}
static void Main()
{
Console.WriteLine(""----"");
Test(null);
Console.WriteLine(""----"");
Test(new TestClass() {test = Main});
Console.WriteLine(""----"");
}
}
";
var compilation = CreateCompilationWithMscorlib(source, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput:
@"----
----
System.Action
----");
var tree = compilation.SyntaxTrees.Single();
var memberBinding = tree.GetRoot().DescendantNodes().OfType<MemberBindingExpressionSyntax>().Single();
var access = (ConditionalAccessExpressionSyntax)memberBinding.Parent;
Assert.Equal(".test", memberBinding.ToString());
Assert.Equal("receiver?.test", access.ToString());
var model = compilation.GetSemanticModel(tree);
Assert.Equal("event System.Action TestClass.test", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString());
Assert.Equal("event System.Action TestClass.test", model.GetSymbolInfo(memberBinding.Name).Symbol.ToTestDisplayString());
Assert.Null(model.GetSymbolInfo(access).Symbol);
}
[Fact, WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")]
public void ConditionalAccessToEvent_02()
{
string source = @"
using System;
class TestClass
{
event Action test;
public static void Test(TestClass receiver)
{
receiver?.test();
}
static void Main()
{
Console.WriteLine(""----"");
Test(null);
Console.WriteLine(""----"");
Test(new TestClass() {test = Target});
Console.WriteLine(""----"");
}
static void Target()
{
Console.WriteLine(""Target"");
}
}
";
var compilation = CreateCompilationWithMscorlib(source, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput:
@"----
----
Target
----");
var tree = compilation.SyntaxTrees.Single();
var memberBinding = tree.GetRoot().DescendantNodes().OfType<MemberBindingExpressionSyntax>().Single();
var invocation = (InvocationExpressionSyntax)memberBinding.Parent;
var access = (ConditionalAccessExpressionSyntax)invocation.Parent;
Assert.Equal(".test", memberBinding.ToString());
Assert.Equal(".test()", invocation.ToString());
Assert.Equal("receiver?.test()", access.ToString());
var model = compilation.GetSemanticModel(tree);
Assert.Equal("event System.Action TestClass.test", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString());
Assert.Equal("event System.Action TestClass.test", model.GetSymbolInfo(memberBinding.Name).Symbol.ToTestDisplayString());
Assert.Equal("void System.Action.Invoke()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
Assert.Null(model.GetSymbolInfo(access).Symbol);
}
[Fact, WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")]
public void ConditionalAccessToEvent_03()
{
string source = @"
using System;
class TestClass
{
event Action test;
public static void Test(TestClass receiver)
{
receiver?.test += Main;
}
static void Main()
{
}
}
";
var compilation = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
compilation.VerifyDiagnostics(
// (10,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// receiver?.test += Main;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "receiver?.test").WithLocation(10, 9)
);
var tree = compilation.SyntaxTrees.Single();
var memberBinding = tree.GetRoot().DescendantNodes().OfType<MemberBindingExpressionSyntax>().Single();
var access = (ConditionalAccessExpressionSyntax)memberBinding.Parent;
Assert.Equal(".test", memberBinding.ToString());
Assert.Equal("receiver?.test", access.ToString());
var model = compilation.GetSemanticModel(tree);
Assert.Equal("event System.Action TestClass.test", model.GetSymbolInfo(memberBinding).Symbol.ToTestDisplayString());
Assert.Equal("event System.Action TestClass.test", model.GetSymbolInfo(memberBinding.Name).Symbol.ToTestDisplayString());
Assert.Null(model.GetSymbolInfo(access).Symbol);
}
}
}
......@@ -9241,5 +9241,196 @@ M3
]]>)
End Sub
<Fact(), WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")>
Public Sub ConditionalAccessToEvent_01()
Dim compilationDef =
<compilation>
<file name="a.vb"><![CDATA[
Imports System
Class TestClass
Event TestEvent As Action
Sub Main(receiver As TestClass)
Console.WriteLine(receiver?.TestEvent)
End Sub
End Class
]]></file>
</compilation>
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib(compilationDef)
compilation.AssertTheseDiagnostics(<expected>
BC32022: 'Public Event TestEvent As Action' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
Console.WriteLine(receiver?.TestEvent)
~~~~~~~~~~
</expected>)
Dim tree = compilation.SyntaxTrees.Single()
Dim access = tree.GetRoot().DescendantNodes().OfType(Of ConditionalAccessExpressionSyntax)().Single()
Dim memberBinding = DirectCast(access.WhenNotNull, MemberAccessExpressionSyntax)
Assert.Equal(".TestEvent", memberBinding.ToString())
Assert.Equal("receiver?.TestEvent", access.ToString())
Dim model = compilation.GetSemanticModel(tree)
Dim info = model.GetSymbolInfo(memberBinding)
Assert.Equal(CandidateReason.NotAValue, info.CandidateReason)
Assert.Equal("Event TestClass.TestEvent As System.Action", info.CandidateSymbols.Single().ToTestDisplayString())
info = model.GetSymbolInfo(memberBinding.Name)
Assert.Equal(CandidateReason.NotAValue, info.CandidateReason)
Assert.Equal("Event TestClass.TestEvent As System.Action", info.CandidateSymbols.Single().ToTestDisplayString())
info = model.GetSymbolInfo(access)
Assert.Null(info.Symbol)
Assert.False(info.CandidateSymbols.Any())
End Sub
<Fact(), WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")>
Public Sub ConditionalAccessToEvent_02()
Dim compilationDef =
<compilation>
<file name="a.vb"><![CDATA[
Imports System
Class TestClass
Event TestEvent As Action
Shared Sub Test(receiver As TestClass)
RaiseEvent receiver?.TestEvent
End Sub
End Class
]]></file>
</compilation>
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib(compilationDef)
compilation.AssertTheseDiagnostics(<expected>
BC30451: 'receiver' is not declared. It may be inaccessible due to its protection level.
RaiseEvent receiver?.TestEvent
~~~~~~~~
BC30205: End of statement expected.
RaiseEvent receiver?.TestEvent
~
</expected>)
Dim tree = compilation.SyntaxTrees.Single()
Assert.False(tree.GetRoot().DescendantNodes().OfType(Of ConditionalAccessExpressionSyntax)().Any())
End Sub
<Fact(), WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")>
Public Sub ConditionalAccessToEvent_03()
Dim compilationDef =
<compilation>
<file name="a.vb"><![CDATA[
Imports System
Class TestClass
Event TestEvent As Action
Shared Sub Test(receiver As TestClass)
AddHandler receiver?.TestEvent, AddressOf Main
End Sub
Shared Sub Main()
End Sub
End Class
]]></file>
</compilation>
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib(compilationDef)
compilation.AssertTheseDiagnostics(<expected>
BC30677: 'AddHandler' or 'RemoveHandler' statement event operand must be a dot-qualified expression or a simple name.
AddHandler receiver?.TestEvent, AddressOf Main
~~~~~~~~~~~~~~~~~~~
</expected>)
Dim tree = compilation.SyntaxTrees.Single()
Dim access = tree.GetRoot().DescendantNodes().OfType(Of ConditionalAccessExpressionSyntax)().Single()
Dim memberBinding = DirectCast(access.WhenNotNull, MemberAccessExpressionSyntax)
Assert.Equal(".TestEvent", memberBinding.ToString())
Assert.Equal("receiver?.TestEvent", access.ToString())
Dim model = compilation.GetSemanticModel(tree)
Dim info = model.GetSymbolInfo(memberBinding)
Assert.Equal(CandidateReason.NotAValue, info.CandidateReason)
Assert.Equal("Event TestClass.TestEvent As System.Action", info.CandidateSymbols.Single().ToTestDisplayString())
info = model.GetSymbolInfo(memberBinding.Name)
Assert.Equal(CandidateReason.NotAValue, info.CandidateReason)
Assert.Equal("Event TestClass.TestEvent As System.Action", info.CandidateSymbols.Single().ToTestDisplayString())
info = model.GetSymbolInfo(access)
Assert.Null(info.Symbol)
Assert.False(info.CandidateSymbols.Any())
End Sub
<Fact(), WorkItem(4028, "https://github.com/dotnet/roslyn/issues/4028")>
Public Sub ConditionalAccessToEvent_04()
Dim compilationDef =
<compilation>
<file name="a.vb"><![CDATA[
Imports System
Class TestClass
Event TestEvent As Action
Shared Sub Test(receiver As TestClass)
receiver?.TestEvent()
End Sub
End Class
]]></file>
</compilation>
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib(compilationDef)
compilation.AssertTheseDiagnostics(<expected>
BC32022: 'Public Event TestEvent As Action' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
receiver?.TestEvent()
~~~~~~~~~~
</expected>)
Dim tree = compilation.SyntaxTrees.Single()
Dim access = tree.GetRoot().DescendantNodes().OfType(Of ConditionalAccessExpressionSyntax)().Single()
Dim invocation = DirectCast(access.WhenNotNull, InvocationExpressionSyntax)
Dim memberBinding = DirectCast(invocation.Expression, MemberAccessExpressionSyntax)
Assert.Equal(".TestEvent", memberBinding.ToString())
Assert.Equal(".TestEvent()", invocation.ToString())
Assert.Equal("receiver?.TestEvent()", access.ToString())
Dim model = compilation.GetSemanticModel(tree)
Dim info = model.GetSymbolInfo(memberBinding)
Assert.Equal(CandidateReason.NotAValue, info.CandidateReason)
Assert.Equal("Event TestClass.TestEvent As System.Action", info.CandidateSymbols.Single().ToTestDisplayString())
info = model.GetSymbolInfo(memberBinding.Name)
Assert.Equal(CandidateReason.NotAValue, info.CandidateReason)
Assert.Equal("Event TestClass.TestEvent As System.Action", info.CandidateSymbols.Single().ToTestDisplayString())
info = model.GetSymbolInfo(invocation)
Assert.Null(info.Symbol)
Assert.False(info.CandidateSymbols.Any())
info = model.GetSymbolInfo(access)
Assert.Null(info.Symbol)
Assert.False(info.CandidateSymbols.Any())
End Sub
End Class
End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册