| File: Completion\KeywordRecommenders\UsingKeywordRecommender.cs | Web Access |
| Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; internal sealed class UsingKeywordRecommender() : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.UsingKeyword) { protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { // cases: // using (goo) { } // using Goo; // using Goo = Bar; // await using (goo) { } return context.IsStatementContext || context.IsGlobalStatementContext || IsUsingDirectiveContext(context, forGlobalKeyword: false, cancellationToken) || context.IsAwaitStatementContext(position, cancellationToken); } internal static bool IsUsingDirectiveContext(CSharpSyntaxContext context, bool forGlobalKeyword, CancellationToken cancellationToken) { // cases: // root: | // root: u| // extern alias a; // | // extern alias a; // u| // using Goo; // | // using Goo; // u| // using Goo = Bar; // | // using Goo = Bar; // u| // t valid: // namespace N {} // | // namespace N {} // u| // class C {} // | // class C {} // u| // | // extern alias a; // u| // extern alias a; var originalToken = context.LeftToken; var token = context.TargetToken; // root: u| // namespace N { u| // namespace N; u| // extern alias a; // u| // using Goo; // u| // using Goo = Bar; // u| // root: | if (token.Kind() == SyntaxKind.None) { // root namespace return IsValidContextAtTheRoot(context, originalToken, cancellationToken); } if ((token.Kind() == SyntaxKind.OpenBraceToken && token.Parent.IsKind(SyntaxKind.NamespaceDeclaration)) || (token.Kind() == SyntaxKind.SemicolonToken && token.Parent.IsKind(SyntaxKind.FileScopedNamespaceDeclaration))) { // a child using can't come before externs var nextToken = originalToken.GetNextToken(includeSkipped: true); if (nextToken.Kind() == SyntaxKind.ExternKeyword) { return false; } return true; } // extern alias a; // | // using Goo; // | if (token.Kind() == SyntaxKind.SemicolonToken) { if (token.Parent is (kind: SyntaxKind.ExternAliasDirective or SyntaxKind.UsingDirective)) { return true; } } // extern alias a; // global | // global using Goo; // global | // global | if (!forGlobalKeyword) { var previousToken = token.GetPreviousToken(includeSkipped: true); if (previousToken.Kind() == SyntaxKind.None) { // root namespace if (token.Kind() == SyntaxKind.GlobalKeyword) { return true; } else if (token.Kind() == SyntaxKind.IdentifierToken && SyntaxFacts.GetContextualKeywordKind((string)token.Value!) == SyntaxKind.GlobalKeyword) { return IsValidContextAtTheRoot(context, originalToken, cancellationToken); } } else if (previousToken.Kind() == SyntaxKind.SemicolonToken && previousToken.Parent is (kind: SyntaxKind.ExternAliasDirective or SyntaxKind.UsingDirective)) { if (token.Kind() == SyntaxKind.GlobalKeyword) { return true; } else if (token.Kind() == SyntaxKind.IdentifierToken && SyntaxFacts.GetContextualKeywordKind((string)token.Value!) == SyntaxKind.GlobalKeyword) { return true; } } } return false; static bool IsValidContextAtTheRoot(CSharpSyntaxContext context, SyntaxToken originalToken, CancellationToken cancellationToken) { // a using can't come before externs var nextToken = originalToken.GetNextToken(includeSkipped: true); if (nextToken.Kind() == SyntaxKind.ExternKeyword || ((CompilationUnitSyntax)context.SyntaxTree.GetRoot(cancellationToken)).Externs.Count > 0) { return false; } return true; } } }