From 959117397531415490a77bb44fe432a654494119 Mon Sep 17 00:00:00 2001 From: Omar Tawfik Date: Mon, 27 Feb 2017 21:33:24 -0800 Subject: [PATCH] Keyword recommendations in parameters --- .../KeywordCompletionProviderTests.cs | 176 ++++++++++++++++++ .../InKeywordRecommender.cs | 5 +- .../ReadOnlyKeywordRecommender.cs | 4 + .../ContextQuery/SyntaxNodeExtensions.cs | 1 + 4 files changed, 185 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs index 0665acaab8a..398d3d322ab 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs @@ -317,5 +317,181 @@ public async Task FormattingAfterCompletionCommit_InSingleLineMethod() }"; await VerifyProviderCommitAsync(markupBeforeCommit, "return", expectedCodeAfterCommit, commitChar: ';', textTypedSoFar: "return"); } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task ReadOnlyWillPopUpAfterRefInMethodParameterModifiers_Methods() + { + var code = @" +class Program +{ + public static void Test(ref $$ p) { } +}"; + + await VerifyItemExistsAsync(code, "readonly"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task ReadOnlyWillPopUpAfterRefInMethodParameterModifiers_SecondParameter() + { + var code = @" +class Program +{ + public static void Test(int p1, ref $$ p2) { } +}"; + + await VerifyItemExistsAsync(code, "readonly"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task ReadOnlyWillPopUpAfterRefInMethodParameterModifiers_Delegates() + { + var code = @" +public delegate int Delegate(ref $$ int p);"; + + await VerifyItemExistsAsync(code, "readonly"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task ReadOnlyWillPopUpAfterRefInMethodParameterModifiers_LocalFunctions() + { + var code = @" +class Program +{ + public static void Test() + { + void localFunc(ref $$ int p) { } + } +}"; + + await VerifyItemExistsAsync(code, "readonly"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task ReadOnlyWillPopUpAfterRefInMethodParameterModifiers_LambdaExpressions() + { + var code = @" +public delegate int Delegate(ref readonly int p); + +class Program +{ + public static void Test() + { + Delegate lambda = (ref $$ int p) => p; + } +}"; + + await VerifyItemExistsAsync(code, "readonly"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task ReadOnlyWillPopUpAfterRefInMethodParameterModifiers_AnonymousMethods() + { + var code = @" +public delegate int Delegate(ref readonly int p); + +class Program +{ + public static void Test() + { + Delegate anonymousDelegate = delegate (ref $$ int p) { return p; }; + } +}"; + + await VerifyItemExistsAsync(code, "readonly"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InWillPopUpAsParameterModifier_Methods() + { + var code = @" +class Program +{ + public static void Test($$ p) { } +}"; + + await VerifyItemExistsAsync(code, "in"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InWillPopUpAsParameterModifier_SecondParameter() + { + var code = @" +class Program +{ + public static void Test(int p1, $$ p2) { } +}"; + + await VerifyItemExistsAsync(code, "in"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InWillPopUpAsParameterModifier_Delegates() + { + var code = @" +public delegate int Delegate($$ int p);"; + + await VerifyItemExistsAsync(code, "in"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InWillPopUpAsParameterModifier_LocalFunctions() + { + var code = @" +class Program +{ + public static void Test() + { + void localFunc($$ int p) { } + } +}"; + + await VerifyItemExistsAsync(code, "in"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InWillPopUpAsParameterModifier_LambdaExpressions() + { + var code = @" +public delegate int Delegate(ref readonly int p); + +class Program +{ + public static void Test() + { + Delegate lambda = ($$ int p) => p; + } +}"; + + await VerifyItemExistsAsync(code, "in"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadonlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task InWillPopUpAsParameterModifier_AnonymousMethods() + { + var code = @" +public delegate int Delegate(ref readonly int p); + +class Program +{ + public static void Test() + { + Delegate anonymousDelegate = delegate ($$ int p) { return p; }; + } +}"; + + await VerifyItemExistsAsync(code, "in"); + } } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs index c7ec5f5d6b5..5699c1dda7e 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs @@ -21,7 +21,10 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context IsValidContextInForEachClause(context) || IsValidContextInFromClause(context, cancellationToken) || IsValidContextInJoinClause(context, cancellationToken) || - context.TargetToken.IsTypeParameterVarianceContext(); + context.TargetToken.IsTypeParameterVarianceContext() || + context.SyntaxTree.IsParameterModifierContext(position, context.LeftToken, cancellationToken) || + context.SyntaxTree.IsAnonymousMethodParameterModifierContext(position, context.LeftToken, cancellationToken) || + context.SyntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken, cancellationToken); } private bool IsValidContextInForEachClause(CSharpSyntaxContext context) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs index 994e9413b53..3def52daab8 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders @@ -26,8 +27,11 @@ public ReadOnlyKeywordRecommender() protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { + var previousToken = context.LeftToken.GetPreviousTokenIfTouchingWord(position); + return context.IsGlobalStatementContext || + (previousToken.IsKind(SyntaxKind.RefKeyword) && previousToken.Parent.IsKind(SyntaxKind.Parameter, SyntaxKind.RefType)) || context.SyntaxTree.IsGlobalMemberDeclarationContext(context.Position, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) || context.IsMemberDeclarationContext( validModifiers: s_validMemberModifiers, diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs index 69af99f77d1..f832fd8cac1 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs @@ -18,6 +18,7 @@ public static bool IsDelegateOrConstructorOrMethodParameterList(this SyntaxNode return node.IsParentKind(SyntaxKind.MethodDeclaration) || + node.IsParentKind(SyntaxKind.LocalFunctionStatement) || node.IsParentKind(SyntaxKind.ConstructorDeclaration) || node.IsParentKind(SyntaxKind.DelegateDeclaration); } -- GitLab