public static ImmutableArray <TypeInferenceInfo> GetTypeInferenceInfo(
     this ITypeInferenceService service,
     SemanticModel semanticModel,
     SyntaxNode expression,
     CancellationToken cancellationToken
     ) =>
 service.GetTypeInferenceInfo(
     semanticModel,
     expression,
     nameOpt: null,
     cancellationToken: cancellationToken
     );
Пример #2
0
        private bool IsLambdaExpression(SemanticModel semanticModel, int position, SyntaxToken token, ITypeInferenceService typeInferrer, CancellationToken cancellationToken)
        {
            // Typing a generic type parameter, the tree might look like a binary expression around the < token.
            // If we infer a delegate type here (because that's what on the other side of the binop),
            // ignore it.
            if (token.Kind() == SyntaxKind.LessThanToken && token.Parent is BinaryExpressionSyntax)
            {
                return(false);
            }

            // We might be in the arguments to a parenthesized lambda
            if (token.Kind() == SyntaxKind.OpenParenToken || token.Kind() == SyntaxKind.CommaToken)
            {
                if (token.Parent != null && token.Parent is ParameterListSyntax)
                {
                    return(token.Parent.Parent != null && token.Parent.Parent is ParenthesizedLambdaExpressionSyntax);
                }
            }

            // A lambda that is being typed may be parsed as a tuple without names
            // For example, "(a, b" could be the start of either a tuple or lambda
            // But "(a: b, c" cannot be a lambda
            if (token.IsPossibleTupleElementNameContext(position) && token.Parent.IsKind(SyntaxKind.TupleExpression) &&
                !((TupleExpressionSyntax)token.Parent).HasNames())
            {
                position = token.Parent.SpanStart;
            }

            // Walk up a single level to allow for typing the beginning of a lambda:
            // new AssemblyLoadEventHandler(($$
            if (token.Kind() == SyntaxKind.OpenParenToken &&
                token.Parent.Kind() == SyntaxKind.ParenthesizedExpression)
            {
                position = token.Parent.SpanStart;
            }

            // WorkItem 834609: Automatic brace completion inserts the closing paren, making it
            // like a cast.
            if (token.Kind() == SyntaxKind.OpenParenToken &&
                token.Parent.Kind() == SyntaxKind.CastExpression)
            {
                position = token.Parent.SpanStart;
            }

            // If we're an argument to a function with multiple overloads,
            // open the builder if any overload takes a delegate at our argument position
            var inferredTypeInfo = typeInferrer.GetTypeInferenceInfo(semanticModel, position, cancellationToken: cancellationToken);

            return(inferredTypeInfo.Any(type => GetDelegateType(type, semanticModel.Compilation).IsDelegateType()));
        }
        private bool IsLambdaExpression(SemanticModel semanticModel, int position, SyntaxToken token, ITypeInferenceService typeInferrer, CancellationToken cancellationToken)
        {
            // Typing a generic type parameter, the tree might look like a binary expression around the < token.
            // If we infer a delegate type here (because that's what on the other side of the binop), 
            // ignore it.
            if (token.Kind() == SyntaxKind.LessThanToken && token.Parent is BinaryExpressionSyntax)
            {
                return false;
            }

            // We might be in the arguments to a parenthesized lambda
            if (token.Kind() == SyntaxKind.OpenParenToken || token.Kind() == SyntaxKind.CommaToken)
            {
                if (token.Parent != null && token.Parent is ParameterListSyntax)
                {
                    return token.Parent.Parent != null && token.Parent.Parent is ParenthesizedLambdaExpressionSyntax;
                }
            }

            // A lambda that is being typed may be parsed as a tuple without names
            // For example, "(a, b" could be the start of either a tuple or lambda
            // But "(a: b, c" cannot be a lambda
            if (token.SyntaxTree.IsPossibleTupleContext(token, position) && token.Parent.IsKind(SyntaxKind.TupleExpression) &&
               !((TupleExpressionSyntax)token.Parent).HasNames())
            {
                position = token.Parent.SpanStart;
            }

            // Walk up a single level to allow for typing the beginning of a lambda:
            // new AssemblyLoadEventHandler(($$
            if (token.Kind() == SyntaxKind.OpenParenToken &&
                token.Parent.Kind() == SyntaxKind.ParenthesizedExpression)
            {
                position = token.Parent.SpanStart;
            }

            // WorkItem 834609: Automatic brace completion inserts the closing paren, making it
            // like a cast.
            if (token.Kind() == SyntaxKind.OpenParenToken &&
                token.Parent.Kind() == SyntaxKind.CastExpression)
            {
                position = token.Parent.SpanStart;
            }

            // If we're an argument to a function with multiple overloads, 
            // open the builder if any overload takes a delegate at our argument position
            var inferredTypeInfo = typeInferrer.GetTypeInferenceInfo(semanticModel, position, cancellationToken: cancellationToken);

            return inferredTypeInfo.Any(type => GetDelegateType(type, semanticModel.Compilation).IsDelegateType());
        }
        private static bool IsLambdaExpression(SemanticModel semanticModel, int position, SyntaxToken token, ITypeInferenceService typeInferrer, CancellationToken cancellationToken)
        {
            // Not after `new`
            if (token.IsKind(SyntaxKind.NewKeyword) && token.Parent.IsKind(SyntaxKind.ObjectCreationExpression))
            {
                return(false);
            }

            // Typing a generic type parameter, the tree might look like a binary expression around the < token.
            // If we infer a delegate type here (because that's what on the other side of the binop),
            // ignore it.
            if (token.Kind() == SyntaxKind.LessThanToken && token.Parent is BinaryExpressionSyntax)
            {
                return(false);
            }

            // We might be in the arguments to a parenthesized lambda
            if (token.Kind() == SyntaxKind.OpenParenToken || token.Kind() == SyntaxKind.CommaToken)
            {
                if (token.Parent != null && token.Parent is ParameterListSyntax)
                {
                    return(token.Parent.Parent != null && token.Parent.Parent is ParenthesizedLambdaExpressionSyntax);
                }
            }

            // A lambda that is being typed may be parsed as a tuple without names
            // For example, "(a, b" could be the start of either a tuple or lambda
            // But "(a: b, c" cannot be a lambda
            if (token.SyntaxTree.IsPossibleTupleContext(token, position) &&
                token.Parent.IsKind(SyntaxKind.TupleExpression, out TupleExpressionSyntax tupleExpression) &&
                !tupleExpression.HasNames())
            {
                position = token.Parent.SpanStart;
            }

            // Walk up a single level to allow for typing the beginning of a lambda:
            // new AssemblyLoadEventHandler(($$
            if (token.Kind() == SyntaxKind.OpenParenToken &&
                token.Parent.Kind() == SyntaxKind.ParenthesizedExpression)
            {
                position = token.Parent.SpanStart;
            }

            // WorkItem 834609: Automatic brace completion inserts the closing paren, making it
            // like a cast.
            if (token.Kind() == SyntaxKind.OpenParenToken &&
                token.Parent.Kind() == SyntaxKind.CastExpression)
            {
                position = token.Parent.SpanStart;
            }

            // In the following situation, the type inferrer will infer Task to support target type preselection
            // Action a = Task.$$
            // We need to explicitly exclude invocation/member access from suggestion mode
            var previousToken = token.GetPreviousTokenIfTouchingWord(position);

            if (previousToken.IsKind(SyntaxKind.DotToken) &&
                previousToken.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                return(false);
            }

            // async lambda:
            //    Goo(async($$
            //    Goo(async(p1, $$
            if (token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken) && token.Parent.IsKind(SyntaxKind.ArgumentList) &&
                token.Parent.Parent is InvocationExpressionSyntax invocation &&
                invocation.Expression is IdentifierNameSyntax identifier)
            {
                if (identifier.Identifier.IsKindOrHasMatchingText(SyntaxKind.AsyncKeyword))
                {
                    return(true);
                }
            }

            // If we're an argument to a function with multiple overloads,
            // open the builder if any overload takes a delegate at our argument position
            var inferredTypeInfo = typeInferrer.GetTypeInferenceInfo(semanticModel, position, cancellationToken: cancellationToken);

            return(inferredTypeInfo.Any(type => GetDelegateType(type, semanticModel.Compilation).IsDelegateType()));
        }