IOperationTests_IAnonymousFunctionExpression.cs 9.6 KB
Newer Older
1 2
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

H
Heejae Chang 已提交
3
using System.Linq;
4 5
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Semantics;
6 7 8 9 10
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
11
    public partial class IOperationTests : SemanticModelTestBase
12
    {
J
Jinu 已提交
13
        [CompilerTrait(CompilerFeature.IOperation)]
14
        [Fact]
15
        public void IAnonymousFunctionExpression_BoundLambda_HasValidLambdaExpressionTree()
16 17 18 19 20 21 22 23
        {
            string source = @"
using System;

class Program
{
    static void Main(string[] args)
    {
H
Heejae Chang 已提交
24
        /*<bind>*/Action x = () => F();/*</bind>*/
25 26 27 28 29 30 31
    }

    static void F()
    {
    }
}
";
32
            string expectedOperationTree = @"
H
Heejae Chang 已提交
33 34
IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'Action x = () => F();')
  IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'x = () => F()')
35
    Variables: Local_1: System.Action x
36 37
    Initializer: IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.Action) (Syntax: '() => F()')
        Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
38
        Operand: IAnonymousFunctionExpression (Symbol: lambda expression) (OperationKind.AnonymousFunctionExpression, Type: null) (Syntax: '() => F()')
39 40 41 42 43 44 45
            IBlockStatement (2 statements) (OperationKind.BlockStatement) (Syntax: 'F()')
              IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'F()')
                Expression: IInvocationExpression (void Program.F()) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'F()')
                    Instance Receiver: null
                    Arguments(0)
              IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'F()')
                ReturnedValue: null
46 47 48
";
            var expectedDiagnostics = DiagnosticDescription.None;

H
Heejae Chang 已提交
49
            VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
50 51
        }

H
Heejae Chang 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
        [CompilerTrait(CompilerFeature.IOperation)]
        [Fact]
        public void IAnonymousFunctionExpression_BoundLambda_HasValidLambdaExpressionTree2()
        {
            string source = @"
using System;

class Program
{
    static void Main(string[] args)
    {
        Action x = /*<bind>*/() => F();/*</bind>*/
    }

    static void F()
    {
    }
}
";
            string expectedOperationTree = @"
IAnonymousFunctionExpression (Symbol: lambda expression) (OperationKind.AnonymousFunctionExpression, Type: null) (Syntax: '() => F()')
    IBlockStatement (2 statements) (OperationKind.BlockStatement) (Syntax: 'F()')
        IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'F()')
        Expression: IInvocationExpression (void Program.F()) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'F()')
            Instance Receiver: null
            Arguments(0)
        IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'F()')
        ReturnedValue: null
";
            var expectedDiagnostics = DiagnosticDescription.None;

            VerifyOperationTreeAndDiagnosticsForTest<ParenthesizedLambdaExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
        }

J
Jinu 已提交
86
        [CompilerTrait(CompilerFeature.IOperation)]
87
        [Fact]
88
        public void IAnonymousFunctionExpression_UnboundLambdaAsVar_HasValidLambdaExpressionTree()
89 90 91 92 93 94 95 96
        {
            string source = @"
using System;

class Program
{
    static void Main(string[] args)
    {
H
Heejae Chang 已提交
97
        /*<bind>*/var x = () => F();/*</bind>*/
98 99 100 101 102 103 104
    }

    static void F()
    {
    }
}
";
105
            string expectedOperationTree = @"
H
Heejae Chang 已提交
106 107
IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var x = () => F();')
  IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'x = () => F()')
108
    Variables: Local_1: var x
109
    Initializer: IAnonymousFunctionExpression (Symbol: lambda expression) (OperationKind.AnonymousFunctionExpression, Type: null, IsInvalid) (Syntax: '() => F()')
H
Heejae Chang 已提交
110 111
        IBlockStatement (1 statements) (OperationKind.BlockStatement, IsInvalid) (Syntax: 'F()')
          IExpressionStatement (OperationKind.ExpressionStatement, IsInvalid) (Syntax: 'F()')
112 113 114
            Expression: IInvocationExpression (void Program.F()) (OperationKind.InvocationExpression, Type: System.Void, IsInvalid) (Syntax: 'F()')
                Instance Receiver: null
                Arguments(0)
115 116 117
";
            var expectedDiagnostics = new DiagnosticDescription[] {
                // CS0815: Cannot assign lambda expression to an implicitly-typed variable
H
Heejae Chang 已提交
118 119
                //         /*<bind>*/var x = () => F();/*</bind>*/
                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, "x = () => F()").WithArguments("lambda expression").WithLocation(8, 23),
120 121
            };

H
Heejae Chang 已提交
122
            VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
123 124
        }

J
Jinu 已提交
125
        [CompilerTrait(CompilerFeature.IOperation)]
126
        [Fact]
127
        public void IAnonymousFunctionExpression_UnboundLambdaAsDelegate_HasValidLambdaExpressionTree()
128 129 130 131 132 133 134 135
        {
            string source = @"
using System;

class Program
{
    static void Main(string[] args)
    {
H
Heejae Chang 已提交
136
        /*<bind>*/Action<int> x = () => F();/*</bind>*/
137 138 139 140 141 142 143
    }

    static void F()
    {
    }
}
";
144
            string expectedOperationTree = @"
H
Heejae Chang 已提交
145 146
IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'Action<int> ...  () => F();')
  IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'x = () => F()')
147
    Variables: Local_1: System.Action<System.Int32> x
148 149
    Initializer: IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.Action<System.Int32>, IsInvalid) (Syntax: '() => F()')
        Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
150
        Operand: IAnonymousFunctionExpression (Symbol: lambda expression) (OperationKind.AnonymousFunctionExpression, Type: null, IsInvalid) (Syntax: '() => F()')
151 152 153 154 155
            IBlockStatement (1 statements) (OperationKind.BlockStatement, IsInvalid) (Syntax: 'F()')
              IExpressionStatement (OperationKind.ExpressionStatement, IsInvalid) (Syntax: 'F()')
                Expression: IInvocationExpression (void Program.F()) (OperationKind.InvocationExpression, Type: System.Void, IsInvalid) (Syntax: 'F()')
                    Instance Receiver: null
                    Arguments(0)
156 157 158 159 160 161 162
";
            var expectedDiagnostics = new DiagnosticDescription[] {
                // CS1593: Delegate 'Action<int>' does not take 0 arguments
                //         Action<int> x /*<bind>*/= () => F()/*</bind>*/;
                Diagnostic(ErrorCode.ERR_BadDelArgCount, "() => F()").WithArguments("System.Action<int>", "0").WithLocation(8, 35)
            };

H
Heejae Chang 已提交
163
            VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
164
        }
165

J
Jinu 已提交
166
        [CompilerTrait(CompilerFeature.IOperation)]
167
        [Fact]
168
        public void IAnonymousFunctionExpression_UnboundLambda_ReferenceEquality()
169
        {
170
            string source = @"
171 172 173 174 175 176
using System;

class Program
{
    static void Main(string[] args)
    {
H
Heejae Chang 已提交
177
        /*<bind>*/var x = () => F();/*</bind>*/
178 179 180 181 182 183 184 185 186 187 188 189
    }

    static void F()
    {
    }
}
";

            var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
            var syntaxTree = compilation.SyntaxTrees[0];
            var semanticModel = compilation.GetSemanticModel(syntaxTree);

H
Heejae Chang 已提交
190 191
            var variableDeclaration = syntaxTree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().Single();
            var lambdaSyntax = (LambdaExpressionSyntax)variableDeclaration.Declaration.Variables.Single().Initializer.Value;
192 193

            var variableDeclarationOperation = (IVariableDeclarationStatement)semanticModel.GetOperationInternal(variableDeclaration);
194 195
            var variableTreeLambdaOperation = (IAnonymousFunctionExpression)variableDeclarationOperation.Declarations.Single().Initializer;
            var lambdaOperation = (IAnonymousFunctionExpression)semanticModel.GetOperationInternal(lambdaSyntax);
196 197 198 199 200 201

            // Assert that both ways of getting to the lambda (requesting the lambda directly, and requesting via the lambda syntax)
            // return the same bound node.
            Assert.Same(variableTreeLambdaOperation, lambdaOperation);

            var variableDeclarationOperationSecondRequest = (IVariableDeclarationStatement)semanticModel.GetOperationInternal(variableDeclaration);
202 203
            var variableTreeLambdaOperationSecondRequest = (IAnonymousFunctionExpression)variableDeclarationOperation.Declarations.Single().Initializer;
            var lambdaOperationSecondRequest = (IAnonymousFunctionExpression)semanticModel.GetOperationInternal(lambdaSyntax);
204 205

            // Assert that, when request the variable declaration or the lambda for a second time, there is no rebinding of the
206
            // underlying UnboundLambda, and we get the same IAnonymousFunctionExpression as before
207 208 209
            Assert.Same(variableTreeLambdaOperation, variableTreeLambdaOperationSecondRequest);
            Assert.Same(lambdaOperation, lambdaOperationSecondRequest);
        }
210 211
    }
}