public static ImmutableArray <TypeInferenceInfo> GetTypeInferenceInfo( this ITypeInferenceService service, SemanticModel semanticModel, SyntaxNode expression, CancellationToken cancellationToken ) => service.GetTypeInferenceInfo( semanticModel, expression, nameOpt: null, cancellationToken: cancellationToken );
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())); }