From 447788e6a19a35455c42b287ce74dceca8412cb5 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Sun, 7 Jan 2018 11:14:11 -0800 Subject: [PATCH] Offer 'in' as completion in operator --- .../InKeywordRecommenderTests.cs | 24 +++++++++++++++++++ .../OutKeywordRecommenderTests.cs | 1 + .../InKeywordRecommender.cs | 2 +- .../ContextQuery/SyntaxNodeExtensions.cs | 24 ++++++++++++------- .../ContextQuery/SyntaxTreeExtensions.cs | 9 +++---- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs index 36e2d6518aba7..88771d960cbf8 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs @@ -488,6 +488,30 @@ class C { public C(object arg1) : this(arg1, $$"); } + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadOnlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(24079, "https://github.com/dotnet/roslyn/issues/24079")] + public async Task TestInAsParameterModifierInConversionOperators() + { + await VerifyKeywordAsync(@" +class Program +{ + public static explicit operator double($$) { } +}"); + } + + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadOnlyReferences)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(24079, "https://github.com/dotnet/roslyn/issues/24079")] + public async Task TestInAsParameterModifierInBinaryOperators() + { + await VerifyKeywordAsync(@" +class Program +{ + public static Program operator +($$) { } +}"); + } + [Test.Utilities.CompilerTrait(Test.Utilities.CompilerFeature.ReadOnlyReferences)] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestInConstructorCallFirstArgumentModifier() diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs index 31cf14e6b47c6..da4770b1c2c6b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs @@ -239,6 +239,7 @@ await VerifyKeywordAsync( } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + [WorkItem(24079, "https://github.com/dotnet/roslyn/issues/24079")] public async Task TestNotAfterOperator() { await VerifyAbsenceAsync( diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs index e86af0c7e1a47..40e082ff3ec91 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs @@ -24,7 +24,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context IsValidContextInForEachClause(context) || IsValidContextInFromClause(context, cancellationToken) || IsValidContextInJoinClause(context, cancellationToken) || - syntaxTree.IsParameterModifierContext(position, context.LeftToken, cancellationToken) || + syntaxTree.IsParameterModifierContext(position, context.LeftToken, cancellationToken, includeOperators: true) || syntaxTree.IsAnonymousMethodParameterModifierContext(position, context.LeftToken, cancellationToken) || syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken, cancellationToken) || context.TargetToken.IsConstructorOrMethodParameterArgumentContext() || diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs index 0bc08b90e8dfa..289f9e825282f 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxNodeExtensions.cs @@ -1,26 +1,32 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; - namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery { internal static class SyntaxNodeExtensions { - public static bool IsDelegateOrConstructorOrLocalFunctionOrMethodParameterList(this SyntaxNode node) + public static bool IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(this SyntaxNode node, bool includeOperators) { if (!node.IsKind(SyntaxKind.ParameterList)) { return false; } - return - node.IsParentKind(SyntaxKind.MethodDeclaration) || + if (node.IsParentKind(SyntaxKind.MethodDeclaration) || node.IsParentKind(SyntaxKind.LocalFunctionStatement) || node.IsParentKind(SyntaxKind.ConstructorDeclaration) || - node.IsParentKind(SyntaxKind.DelegateDeclaration); + node.IsParentKind(SyntaxKind.DelegateDeclaration)) + { + return true; + } + + if (includeOperators) + { + return + node.IsParentKind(SyntaxKind.OperatorDeclaration) || + node.IsParentKind(SyntaxKind.ConversionOperatorDeclaration); + } + + return false; } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs index 0dc4d6c222725..511d2ea48c1fd 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -978,6 +978,7 @@ public static bool IsParameterModifierContext( int position, SyntaxToken tokenOnLeftOfPosition, CancellationToken cancellationToken, + bool includeOperators = false, bool isThisKeyword = false) { // cases: @@ -988,13 +989,13 @@ public static bool IsParameterModifierContext( token = token.GetPreviousTokenIfTouchingWord(position); if (token.IsKind(SyntaxKind.OpenParenToken) && - token.Parent.IsDelegateOrConstructorOrLocalFunctionOrMethodParameterList()) + token.Parent.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) { return true; } if (token.IsKind(SyntaxKind.CommaToken) && - token.Parent.IsDelegateOrConstructorOrLocalFunctionOrMethodParameterList()) + token.Parent.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) { if (isThisKeyword) { @@ -1010,7 +1011,7 @@ public static bool IsParameterModifierContext( if (token.IsKind(SyntaxKind.CloseBracketToken) && token.Parent.IsKind(SyntaxKind.AttributeList) && token.Parent.IsParentKind(SyntaxKind.Parameter) && - token.Parent.GetParent().GetParent().IsDelegateOrConstructorOrLocalFunctionOrMethodParameterList()) + token.Parent.GetParent().GetParent().IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) { if (isThisKeyword) { @@ -1026,7 +1027,7 @@ public static bool IsParameterModifierContext( if (isThisKeyword && (token.IsKind(SyntaxKind.RefKeyword) || token.IsKind(SyntaxKind.InKeyword)) && - token.Parent.GetParent().IsDelegateOrConstructorOrLocalFunctionOrMethodParameterList()) + token.Parent.GetParent().IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) { var parameter = token.GetAncestor(); var parameterList = parameter.GetAncestorOrThis();