diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory_Methods.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory_Methods.cs index d8f22dac45f64..6236f384f6ce1 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory_Methods.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory_Methods.cs @@ -103,7 +103,14 @@ private IVariableDeclaratorOperation CreateVariableDeclaratorInternal(BoundLocal } // Static members cannot have an implicit this receiver - if (symbol != null && symbol.IsStatic && instance.WasCompilerGenerated && instance.Kind == BoundKind.ThisReference) + if (symbol?.IsStatic == true && instance.WasCompilerGenerated && instance.Kind == BoundKind.ThisReference) + { + return null; + } + + // Local functions are not invoked on receivers from a language point of view, and thus we do not expose + // a receiver for them. + if (symbol is MethodSymbol { MethodKind: MethodKind.LocalFunction }) { return null; } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IInvocationOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IInvocationOperation.cs index 7c9b02b8fa03a..3c9faf8ce18b2 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IInvocationOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IInvocationOperation.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests @@ -1312,5 +1313,81 @@ static void M1(object o1, object o2, object o3) { } "; VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); } + + [Theory, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + [InlineData("static")] + [InlineData("")] + public void Invocation_LocalFunction_01(string modifier) + { + var code = @" +using System; + +/**/localFunction()/**/; + +" + modifier + @" void localFunction() {} +"; + + var expectedDiagnostics = DiagnosticDescription.None; + var expectedTree = @" +IInvocationOperation (void localFunction()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'localFunction()') + Instance Receiver: + null + Arguments(0) +"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } + + [Fact, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + public void Invocation_LocalFunction_02() + { + var code = @" +using System; + +int localVariable = 1; +/**/localFunction()/**/; + +int localFunction() => localVariable; +"; + + var expectedDiagnostics = DiagnosticDescription.None; + var expectedTree = @" +IInvocationOperation (System.Int32 localFunction()) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'localFunction()') + Instance Receiver: + null + Arguments(0) +"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } + + [Fact, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + public void Invocation_LocalFunction_03() + { + var code = @" +using System; + +int localVariable = 1; +/**/localFunction()/**/; + +static int localFunction() => localVariable; +"; + + var expectedDiagnostics = new DiagnosticDescription[] + { + // (7,31): error CS8421: A static local function cannot contain a reference to 'localVariable'. + // static int localFunction() => localVariable; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "localVariable").WithArguments("localVariable").WithLocation(7, 31) + }; + + var expectedTree = @" +IInvocationOperation (System.Int32 localFunction()) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'localFunction()') + Instance Receiver: + null + Arguments(0) +"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } } } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IMethodReferenceOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IMethodReferenceOperation.cs index 6f3c64b5371f6..bfcecfd6b12f5 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IMethodReferenceOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IMethodReferenceOperation.cs @@ -305,5 +305,89 @@ void M(C c1, C c2, System.Func m1, System.Func m2) VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); } + + [Fact, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + public void MethodReference_LocalFunction_01() + { + var code = @" +using System; +Action a = /**/localFunction/**/; + +void localFunction() {} +"; + + var expectedDiagnostics = DiagnosticDescription.None; + var expectedTree = @" +IMethodReferenceOperation: void localFunction() (OperationKind.MethodReference, Type: null) (Syntax: 'localFunction') + Instance Receiver: + null"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } + + [Fact, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + public void MethodReference_LocalFunction_02() + { + var code = @" +using System; +Action a = /**/localFunction/**/; + +static void localFunction() {} +"; + + var expectedDiagnostics = DiagnosticDescription.None; + var expectedTree = @" +IMethodReferenceOperation: void localFunction() (Static) (OperationKind.MethodReference, Type: null) (Syntax: 'localFunction') + Instance Receiver: + null"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } + + [Fact, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + public void MethodReference_LocalFunction_03() + { + var code = @" +using System; +int local = 1; +Func a = /**/localFunction/**/; + +int localFunction() => local; +"; + + var expectedDiagnostics = DiagnosticDescription.None; + var expectedTree = @" +IMethodReferenceOperation: System.Int32 localFunction() (OperationKind.MethodReference, Type: null) (Syntax: 'localFunction') + Instance Receiver: + null"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } + + [Fact, WorkItem(51715, "https://github.com/dotnet/roslyn/issues/51715")] + public void MethodReference_LocalFunction_04() + { + var code = @" +using System; +int local = 1; +Func a = /**/localFunction/**/; + +static int localFunction() => local; +"; + + var expectedDiagnostics = new DiagnosticDescription[] + { + // (6,31): error CS8421: A static local function cannot contain a reference to 'local'. + // static int localFunction() => local; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "local").WithArguments("local").WithLocation(6, 31) + }; + + var expectedTree = @" +IMethodReferenceOperation: System.Int32 localFunction() (Static) (OperationKind.MethodReference, Type: null) (Syntax: 'localFunction') + Instance Receiver: + null"; + + VerifyOperationTreeAndDiagnosticsForTest(code, expectedTree, expectedDiagnostics); + } } }