Example #1
0
 public Lambda(AnonymousFunctionExpressionSyntax lambda)
 {
     Body = lambda.Body;
     Syntax = lambda;
     if (lambda is ParenthesizedLambdaExpressionSyntax) Parameters = ((ParenthesizedLambdaExpressionSyntax)lambda).ParameterList.Parameters;
     if (lambda is AnonymousMethodExpressionSyntax) Parameters = ((AnonymousMethodExpressionSyntax)lambda).ParameterList.Parameters;
     if (lambda is SimpleLambdaExpressionSyntax) Parameters = new[] { ((SimpleLambdaExpressionSyntax)lambda).Parameter };
 }
Example #2
0
 public virtual void Visit(AnonymousFunctionExpressionSyntax anonymousFunctionExpressionSyntax)
 {
     foreach (var parameterSyntax in anonymousFunctionExpressionSyntax.Parameter)
     {
         Visit(parameterSyntax);
     }
     Visit(anonymousFunctionExpressionSyntax.Statements);
 }
        private static SyntaxNode ReplaceAnonymousWithLocalFunction(
            HostSolutionServices services, SyntaxNode currentRoot,
            LocalDeclarationStatementSyntax localDeclaration, AnonymousFunctionExpressionSyntax anonymousFunction,
            IMethodSymbol delegateMethod, ParameterListSyntax parameterList, bool makeStatic)
        {
            var newLocalFunctionStatement = CreateLocalFunctionStatement(localDeclaration, anonymousFunction, delegateMethod, parameterList, makeStatic)
                                            .WithTriviaFrom(localDeclaration)
                                            .WithAdditionalAnnotations(Formatter.Annotation);

            var editor = new SyntaxEditor(currentRoot, services);

            editor.ReplaceNode(localDeclaration, newLocalFunctionStatement);

            var anonymousFunctionStatement = anonymousFunction.GetAncestor <StatementSyntax>();

            if (anonymousFunctionStatement != localDeclaration)
            {
                // This is the split decl+init form.  Remove the second statement as we're
                // merging into the first one.
                editor.RemoveNode(anonymousFunctionStatement);
            }

            return(editor.GetChangedRoot());
        }
        private ITypeSymbol GetLambdaReturnType(AnonymousFunctionExpressionSyntax lambda)
        {
            var symbol = ((INamedTypeSymbol)semantic.GetTypeInfo(lambda).ConvertedType).TypeArguments.Last();

            return(symbol);
        }
 private static SeparatedSyntaxList <ParameterSyntax> GetParameters(AnonymousFunctionExpressionSyntax expression)
 => expression switch
 {
Example #6
0
        private static bool CanReplaceAnonymousWithLocalFunction(
            SemanticModel semanticModel, INamedTypeSymbol?expressionTypeOpt, ISymbol local, BlockSyntax block,
            AnonymousFunctionExpressionSyntax anonymousFunction, out ImmutableArray <Location> referenceLocations, CancellationToken cancellationToken)
        {
            // Check all the references to the anonymous function and disallow the conversion if
            // they're used in certain ways.
            var references = ArrayBuilder <Location> .GetInstance();

            referenceLocations = ImmutableArray <Location> .Empty;
            var anonymousFunctionStart = anonymousFunction.SpanStart;

            foreach (var descendentNode in block.DescendantNodes())
            {
                var descendentStart = descendentNode.Span.Start;
                if (descendentStart <= anonymousFunctionStart)
                {
                    // This node is before the local declaration.  Can ignore it entirely as it could
                    // not be an access to the local.
                    continue;
                }

                if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax? identifierName))
                {
                    if (identifierName.Identifier.ValueText == local.Name &&
                        local.Equals(semanticModel.GetSymbolInfo(identifierName, cancellationToken).GetAnySymbol()))
                    {
                        if (identifierName.IsWrittenTo(semanticModel, cancellationToken))
                        {
                            // Can't change this to a local function if it is assigned to.
                            return(false);
                        }

                        var nodeToCheck = identifierName.WalkUpParentheses();
                        if (nodeToCheck.Parent is BinaryExpressionSyntax)
                        {
                            // Can't change this if they're doing things like delegate addition with
                            // the lambda.
                            return(false);
                        }

                        if (nodeToCheck.Parent is InvocationExpressionSyntax invocationExpression)
                        {
                            references.Add(invocationExpression.GetLocation());
                        }
                        else if (nodeToCheck.Parent is MemberAccessExpressionSyntax memberAccessExpression)
                        {
                            if (memberAccessExpression.Parent is InvocationExpressionSyntax explicitInvocationExpression &&
                                memberAccessExpression.Name.Identifier.ValueText == WellKnownMemberNames.DelegateInvokeName)
                            {
                                references.Add(explicitInvocationExpression.GetLocation());
                            }
                            else
                            {
                                // They're doing something like "del.ToString()".  Can't do this with a
                                // local function.
                                return(false);
                            }
                        }
                        else
                        {
                            references.Add(nodeToCheck.GetLocation());
                        }

                        var convertedType = semanticModel.GetTypeInfo(nodeToCheck, cancellationToken).ConvertedType;
                        if (!convertedType.IsDelegateType())
                        {
                            // We can't change this anonymous function into a local function if it is
                            // converted to a non-delegate type (i.e. converted to 'object' or
                            // 'System.Delegate'). Local functions are not convertible to these types.
                            // They're only convertible to other delegate types.
                            return(false);
                        }

                        if (nodeToCheck.IsInExpressionTree(semanticModel, expressionTypeOpt, cancellationToken))
                        {
                            // Can't reference a local function inside an expression tree.
                            return(false);
                        }
                    }
                }
            }
 public TameAnonymousFunctionExpressionSyntax(AnonymousFunctionExpressionSyntax node)
 {
     Node = node;
     AddChildren();
 }
Example #8
0
        // An anonymous function can be of the form:
        //
        // delegate { }              (missing parameter list)
        // delegate (int x) { }      (typed parameter list)
        // x => ...                  (type-inferred parameter list)
        // (x) => ...                (type-inferred parameter list)
        // (x, y) => ...             (type-inferred parameter list)
        // ( ) => ...                (typed parameter list)
        // (ref int x) => ...        (typed parameter list)
        // (int x, out int y) => ... (typed parameter list)
        //
        // and so on. We want to canonicalize these various ways of writing the signatures.
        //
        // If we are in the first case then the name, modifier and type arrays are all null.
        // If we have a parameter list then the names array is non-null, but possibly empty.
        // If we have types then the types array is non-null, but possibly empty.
        // If we have no modifiers then the modifiers array is null; if we have any modifiers
        // then the modifiers array is non-null and not empty.

        private UnboundLambda AnalyzeAnonymousFunction(
            AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            ImmutableArray <string>              names    = default;
            ImmutableArray <RefKind>             refKinds = default;
            ImmutableArray <DeclarationScope>    scopes   = default;
            ImmutableArray <TypeWithAnnotations> types    = default;
            RefKind             returnRefKind             = RefKind.None;
            TypeWithAnnotations returnType = default;
            ImmutableArray <SyntaxList <AttributeListSyntax> > parameterAttributes = default;

            var namesBuilder = ArrayBuilder <string> .GetInstance();

            ImmutableArray <bool> discardsOpt = default;
            SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null;
            bool hasSignature;

            if (syntax is LambdaExpressionSyntax lambdaSyntax)
            {
                checkAttributes(syntax, lambdaSyntax.AttributeLists, diagnostics);
            }

            switch (syntax.Kind())
            {
            default:
            case SyntaxKind.SimpleLambdaExpression:
                // x => ...
                hasSignature = true;
                var simple = (SimpleLambdaExpressionSyntax)syntax;
                namesBuilder.Add(simple.Parameter.Identifier.ValueText);
                break;

            case SyntaxKind.ParenthesizedLambdaExpression:
                // (T x, U y) => ...
                // (x, y) => ...
                hasSignature = true;
                var paren = (ParenthesizedLambdaExpressionSyntax)syntax;
                if (paren.ReturnType is { } returnTypeSyntax)
                {
                    (returnRefKind, returnType) = BindExplicitLambdaReturnType(returnTypeSyntax, diagnostics);
                }
                parameterSyntaxList = paren.ParameterList.Parameters;
                CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics);
                break;

            case SyntaxKind.AnonymousMethodExpression:
                // delegate (int x) { }
                // delegate { }
                var anon = (AnonymousMethodExpressionSyntax)syntax;
                hasSignature = anon.ParameterList != null;
                if (hasSignature)
                {
                    parameterSyntaxList = anon.ParameterList !.Parameters;
                }
                break;
            }

            var isAsync  = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword);
            var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword);

            if (parameterSyntaxList != null)
            {
                var hasExplicitlyTypedParameterList = true;

                var typesBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance();

                var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance();

                var scopesBuilder = ArrayBuilder <DeclarationScope> .GetInstance();

                var attributesBuilder = ArrayBuilder <SyntaxList <AttributeListSyntax> > .GetInstance();

                // In the batch compiler case we probably should have given a syntax error if the
                // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in
                // this case. If we are, then rather than try to make partial deductions from the
                // typed formal parameters, simply bail out and treat it as an untyped lambda.
                //
                // However, we still want to give errors on every bad type in the list, even if one
                // is missing.

                int underscoresCount = 0;
                foreach (var p in parameterSyntaxList.Value)
                {
                    if (p.Identifier.IsUnderscoreToken())
                    {
                        underscoresCount++;
                    }

                    checkAttributes(syntax, p.AttributeLists, diagnostics);

                    if (p.Default != null)
                    {
                        Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken);
                    }

                    if (p.IsArgList)
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p);
                        continue;
                    }

                    var typeSyntax           = p.Type;
                    TypeWithAnnotations type = default;
                    var refKind = RefKind.None;
                    var scope   = DeclarationScope.Unscoped;

                    if (typeSyntax == null)
                    {
                        hasExplicitlyTypedParameterList = false;
                    }
                    else
                    {
                        type = BindType(typeSyntax, diagnostics);
                        ParameterHelpers.CheckParameterModifiers(p, diagnostics, parsingFunctionPointerParams: false, parsingLambdaParams: true);
                        refKind = ParameterHelpers.GetModifiers(p.Modifiers, out _, out _, out _, out scope);
                    }

                    namesBuilder.Add(p.Identifier.ValueText);
                    typesBuilder.Add(type);
                    refKindsBuilder.Add(refKind);
                    scopesBuilder.Add(scope);
                    attributesBuilder.Add(syntax.Kind() == SyntaxKind.ParenthesizedLambdaExpression ? p.AttributeLists : default);
Example #9
0
 public AnonymousFunctionData GetOrCreateAnonymousFunctionData(AnonymousFunctionExpressionSyntax node, MethodData methodData = null)
 {
     return((AnonymousFunctionData)GetNodeData(node, true, methodData: methodData));
 }
Example #10
0
 public AnonymousFunctionData GetAnonymousFunctionData(AnonymousFunctionExpressionSyntax node)
 {
     return((AnonymousFunctionData)GetNodeData(node));
 }
Example #11
0
        // An anonymous function can be of the form:
        //
        // delegate { }              (missing parameter list)
        // delegate (int x) { }      (typed parameter list)
        // x => ...                  (type-inferred parameter list)
        // (x) => ...                (type-inferred parameter list)
        // (x, y) => ...             (type-inferred parameter list)
        // ( ) => ...                (typed parameter list)
        // (ref int x) => ...        (typed parameter list)
        // (int x, out int y) => ... (typed parameter list)
        //
        // and so on. We want to canonicalize these various ways of writing the signatures.
        //
        // If we are in the first case then the name, modifier and type arrays are all null.
        // If we have a parameter list then the names array is non-null, but possibly empty.
        // If we have types then the types array is non-null, but possibly empty.
        // If we have no modifiers then the modifiers array is null; if we have any modifiers
        // then the modifiers array is non-null and not empty.

        private UnboundLambda AnalyzeAnonymousFunction(
            AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            var names    = default(ImmutableArray <string>);
            var refKinds = default(ImmutableArray <RefKind>);
            var types    = default(ImmutableArray <TypeWithAnnotations>);

            var namesBuilder = ArrayBuilder <string> .GetInstance();

            ImmutableArray <bool> discardsOpt = default;
            SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null;
            bool hasSignature;

            switch (syntax.Kind())
            {
            default:
            case SyntaxKind.SimpleLambdaExpression:
                // x => ...
                hasSignature = true;
                var simple = (SimpleLambdaExpressionSyntax)syntax;
                namesBuilder.Add(simple.Parameter.Identifier.ValueText);
                break;

            case SyntaxKind.ParenthesizedLambdaExpression:
                // (T x, U y) => ...
                // (x, y) => ...
                hasSignature = true;
                var paren = (ParenthesizedLambdaExpressionSyntax)syntax;
                parameterSyntaxList = paren.ParameterList.Parameters;
                CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics);
                break;

            case SyntaxKind.AnonymousMethodExpression:
                // delegate (int x) { }
                // delegate { }
                var anon = (AnonymousMethodExpressionSyntax)syntax;
                hasSignature = anon.ParameterList != null;
                if (hasSignature)
                {
                    parameterSyntaxList = anon.ParameterList !.Parameters;
                }
                break;
            }

            var isAsync  = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword);
            var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword);

            if (parameterSyntaxList != null)
            {
                var hasExplicitlyTypedParameterList = true;
                var allValue = true;

                var typesBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance();

                var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance();

                // In the batch compiler case we probably should have given a syntax error if the
                // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in
                // this case. If we are, then rather than try to make partial deductions from the
                // typed formal parameters, simply bail out and treat it as an untyped lambda.
                //
                // However, we still want to give errors on every bad type in the list, even if one
                // is missing.

                int underscoresCount = 0;
                foreach (var p in parameterSyntaxList.Value)
                {
                    if (p.Identifier.IsUnderscoreToken())
                    {
                        underscoresCount++;
                    }

                    foreach (var attributeList in p.AttributeLists)
                    {
                        Error(diagnostics, ErrorCode.ERR_AttributesNotAllowed, attributeList);
                    }

                    if (p.Default != null)
                    {
                        Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken);
                    }

                    if (p.IsArgList)
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p);
                        continue;
                    }

                    var typeSyntax           = p.Type;
                    TypeWithAnnotations type = default;
                    var refKind = RefKind.None;

                    if (typeSyntax == null)
                    {
                        hasExplicitlyTypedParameterList = false;
                    }
                    else
                    {
                        type = BindType(typeSyntax, diagnostics);
                        foreach (var modifier in p.Modifiers)
                        {
                            switch (modifier.Kind())
                            {
                            case SyntaxKind.RefKeyword:
                                refKind  = RefKind.Ref;
                                allValue = false;
                                break;

                            case SyntaxKind.OutKeyword:
                                refKind  = RefKind.Out;
                                allValue = false;
                                break;

                            case SyntaxKind.InKeyword:
                                refKind  = RefKind.In;
                                allValue = false;
                                break;

                            case SyntaxKind.ParamsKeyword:
                                // This was a parse error in the native compiler;
                                // it is a semantic analysis error in Roslyn. See comments to
                                // changeset 1674 for details.
                                Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
                                break;

                            case SyntaxKind.ThisKeyword:
                                Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier);
                                break;
                            }
                        }
                    }

                    namesBuilder.Add(p.Identifier.ValueText);
                    typesBuilder.Add(type);
                    refKindsBuilder.Add(refKind);
                }

                discardsOpt = computeDiscards(parameterSyntaxList.Value, underscoresCount);

                if (hasExplicitlyTypedParameterList)
                {
                    types = typesBuilder.ToImmutable();
                }

                if (!allValue)
                {
                    refKinds = refKindsBuilder.ToImmutable();
                }

                typesBuilder.Free();
                refKindsBuilder.Free();
            }

            if (hasSignature)
            {
                names = namesBuilder.ToImmutable();
            }

            namesBuilder.Free();

            return(new UnboundLambda(syntax, this, diagnostics.AccumulatesDependencies, refKinds, types, names, discardsOpt, isAsync, isStatic));
 public AnonymousFunctionData(BaseMethodData methodData, IMethodSymbol symbol, AnonymousFunctionExpressionSyntax node,
                              FunctionData parent = null) : base(symbol, parent ?? methodData)
 {
     MethodData = methodData ?? throw new ArgumentNullException(nameof(methodData));
     Node       = node ?? throw new ArgumentNullException(nameof(node));
 }
 private static void ReportAnonymousFunction(SyntaxNodeAnalysisContext context, AnonymousFunctionExpressionSyntax anonymousMethod)
 {
     DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseAnonymousFunctionOrMethodGroup, anonymousMethod, "method group");
 }
Example #14
0
 public static bool IsVoidReturn(this AnonymousFunctionExpressionSyntax methodDeclaration)
 {
     return(!((BlockSyntax)methodDeclaration.Body).Statements.Any(SyntaxKind.ReturnStatement));
 }
Example #15
0
 private BoundExpression BindAnonymousFunctionExpression(AnonymousFunctionExpressionSyntax syntax)
 {
     var boundParameters = syntax.Parameter.Select(BindParameter).ToList();
     var boundStatement = BindStatement(syntax.Statements);
     throw new NotImplementedException();
 }