protected override Task <bool> IsValidOpenBraceTokenAtPositionAsync(Document document, SyntaxToken token, int position, CancellationToken cancellationToken) { // check what parser thinks about the newly typed "<" and only proceed if parser thinks it is "<" of // type argument or parameter list if (token.CheckParent <TypeParameterListSyntax>(n => n.LessThanToken == token) || token.CheckParent <TypeArgumentListSyntax>(n => n.LessThanToken == token) || token.CheckParent <FunctionPointerParameterListSyntax>(n => n.LessThanToken == token)) { return(Task.FromResult(true)); } // type argument can be easily ambiguous with normal < operations if (token.Parent is not BinaryExpressionSyntax(SyntaxKind.LessThanExpression) node || node.OperatorToken != token) { return(Task.FromResult(false)); } // type_argument_list only shows up in the following grammar construct: // // generic_name // : identifier_token type_argument_list // // So if the prior token is not an identifier, this could not be a type-argument-list. var previousToken = token.GetPreviousToken(); if (previousToken.Parent is not IdentifierNameSyntax identifier) { return(Task.FromResult(false)); } return(IsSemanticTypeArgumentAsync(document, node.SpanStart, identifier, cancellationToken));
protected override async ValueTask <bool> IsValidOpenBraceTokenAtPositionAsync(Document document, SyntaxToken token, int position, CancellationToken cancellationToken) { // check what parser thinks about the newly typed "<" and only proceed if parser thinks it is "<" of // type argument or parameter list return(token.CheckParent <TypeParameterListSyntax>(n => n.LessThanToken == token) || token.CheckParent <TypeArgumentListSyntax>(n => n.LessThanToken == token) || token.CheckParent <FunctionPointerParameterListSyntax>(n => n.LessThanToken == token) || await PossibleTypeArgumentAsync(document, token, cancellationToken).ConfigureAwait(false)); }