public override async Task <CheckResult> ShouldProvideCompletion(Document document, int position) { if (!document.SupportsSyntaxTree || !document.SupportsSemanticModel) { return(CheckResult.False()); } var syntaxRoot = await document.GetSyntaxRootAsync(); if (syntaxRoot == null) { return(CheckResult.False()); } var semanticModel = await document.GetSemanticModelAsync(); if (semanticModel == null) { return(CheckResult.False()); } // Walk up and save literal expression if present (we can autocomplete literals). var currentToken = syntaxRoot.FindToken(position - 1); var currentNode = currentToken.Parent; var literalExpression = RoslynUtils.WalkUpStringSyntaxOnce(ref currentNode, ref position); // Walk up parenthesis because the inference service doesn't handle that. currentToken = syntaxRoot.FindToken(position - 1); currentNode = currentToken.Parent; if (currentToken.Kind() != SyntaxKind.CloseParenToken) { RoslynUtils.WalkUpParenthesisExpressions(ref currentNode, ref position); } var inferredTypes = RoslynUtils.InferTypes(semanticModel, position, null, CancellationToken.None); if (inferredTypes.Any(RoslynUtils.TypeIsNodePath)) { return(CheckResult.True(literalExpression)); } // Our own custom inference for NodePath if (IsPathConstructorArgumentOfNodePath(syntaxRoot, semanticModel, currentNode, position)) { return(CheckResult.True(literalExpression)); } if (IsParenthesizedExprActuallyCastToNodePath(semanticModel, currentNode)) { return(CheckResult.True(literalExpression)); } return(CheckResult.False()); }
public override async Task <CheckResult> ShouldProvideCompletion(Document document, int position) { if (!document.SupportsSyntaxTree || !document.SupportsSemanticModel) { return(CheckResult.False()); } var syntaxRoot = await document.GetSyntaxRootAsync(); if (syntaxRoot == null) { return(CheckResult.False()); } var semanticModel = await document.GetSemanticModelAsync(); if (semanticModel == null) { return(CheckResult.False()); } // Walk up and save literal expression if present (we can autocomplete literals). var currentToken = syntaxRoot.FindToken(position - 1); var currentNode = currentToken.Parent; var literalExpression = RoslynUtils.WalkUpStringSyntaxOnce(ref currentNode, ref position); // Walk up parenthesis because the inference service doesn't handle that. currentToken = syntaxRoot.FindToken(position - 1); currentNode = currentToken.Parent; if (currentToken.Kind() != SyntaxKind.CloseParenToken) { RoslynUtils.WalkUpParenthesisExpressions(ref currentNode, ref position); } if (!(currentNode is ArgumentListSyntax argumentList && currentNode.Parent is InvocationExpressionSyntax invocation)) { return(CheckResult.False()); } var previousToken = syntaxRoot.FindToken(position - 1); if (previousToken != argumentList.OpenParenToken && previousToken.Kind() != SyntaxKind.CommaToken) { return(CheckResult.False()); } if (RoslynUtils.IsExpectedInvocationArgument(semanticModel, previousToken, invocation, argumentList, _expectedInvocations)) { return(CheckResult.True(literalExpression)); } return(CheckResult.False()); }
private static bool IsParenthesizedExprActuallyCastToNodePath(SemanticModel semanticModel, SyntaxNode currentNode) { // (NodePath)$$ which is detected as a parenthesized expression rather than a cast if (!(currentNode is ParenthesizedExpressionSyntax parenthesizedExpression)) { return(false); } if (!(parenthesizedExpression.Expression is IdentifierNameSyntax identifierNameSyntax)) { return(false); } var typeInfo = semanticModel.GetTypeInfo(identifierNameSyntax).Type; return(typeInfo != null && RoslynUtils.TypeIsNodePath(typeInfo)); }
private static bool IsPathConstructorArgumentOfNodePath(SyntaxNode syntaxRoot, SemanticModel semanticModel, SyntaxNode currentNode, int position) { // new NodePath($$) for NodePath(string) ctor if (!(currentNode is ArgumentListSyntax argumentList && currentNode.Parent is ObjectCreationExpressionSyntax objectCreation)) { return(false); } var previousToken = syntaxRoot.FindToken(position - 1); if (previousToken != argumentList.OpenParenToken) { return(false); } if (argumentList.Arguments.Count > 1) { return(false); // The NodePath constructor we are looking for has only one parameter } int index = RoslynUtils.GetArgumentListIndex(argumentList, previousToken); var info = semanticModel.GetSymbolInfo(objectCreation.Type); if (!(info.Symbol is INamedTypeSymbol type)) { return(false); } if (type.TypeKind == TypeKind.Delegate) { return(false); } if (!RoslynUtils.TypeIsNodePath(type)) { return(false); } var constructors = type.InstanceConstructors.Where(m => m.Parameters.Length == 1); var types = RoslynUtils.InferTypeInArgument(index, constructors.Select(m => m.Parameters), argumentOpt: null); return(types.Any(RoslynUtils.TypeIsString)); }