From 0598b18cd819f2c2f6d496f88bcbfa66a3f36dd6 Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Mon, 5 Dec 2016 14:20:24 -0800 Subject: [PATCH 1/9] Don't use symbolid in symbl completion --- ...tributeNamedParameterCompletionProvider.cs | 4 +- .../CrefCompletionProvider.cs | 45 ++++++-- ...mAndCompletionListTagCompletionProvider.cs | 2 +- .../ExplicitInterfaceCompletionProvider.cs | 2 +- .../NamedParameterCompletionProvider.cs | 2 +- .../SymbolCompletionProvider.cs | 1 + ...bstractObjectCreationCompletionProvider.cs | 2 +- ...ractObjectInitializerCompletionProvider.cs | 2 +- .../AbstractPartialTypeCompletionProvider.cs | 2 +- ...mendationServiceBasedCompletionProvider.cs | 17 ++- .../AbstractSymbolCompletionProvider.cs | 8 +- .../MemberInsertingCompletionItem.cs | 2 +- .../Providers/SymbolCompletionItem.cs | 105 ++++++++++++++++-- .../Providers/SymbolCompletionItem2.cs | 69 ++++++++++++ src/Features/Core/Portable/Features.csproj | 1 + .../CompletionListTagCompletionProvider.vb | 2 +- .../CrefCompletionProvider.vb | 35 ++++-- .../EnumCompletionProvider.vb | 2 +- .../HandlesClauseCompletionProvider.vb | 2 +- .../NamedParameterCompletionProvider.vb | 2 +- 20 files changed, 265 insertions(+), 42 deletions(-) create mode 100644 src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs index 77cda7299defb..77ea3a9a0b88a 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs @@ -145,7 +145,7 @@ private async Task> GetNameEqualsItemsAsync( var text = await semanticModel.SyntaxTree.GetTextAsync(context.CancellationToken).ConfigureAwait(false); var q = from p in attributeNamedParameters where !existingNamedParameters.Contains(p.Name) - select SymbolCompletionItem.Create( + select SymbolCompletionItem.CreateWithSymbolId( displayText: p.Name.ToIdentifierToken().ToString() + SpaceEqualsString, insertionText: null, symbol: p, @@ -165,7 +165,7 @@ private async Task> GetNameColonItemsAsync( return from pl in parameterLists from p in pl where !existingNamedParameters.Contains(p.Name) - select SymbolCompletionItem.Create( + select SymbolCompletionItem.CreateWithSymbolId( displayText: p.Name.ToIdentifierToken().ToString() + ColonString, insertionText: null, symbol: p, diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs index 547fe28274c00..59ef5323418cc 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs @@ -95,7 +95,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var span = GetCompletionItemSpan(text, position); - var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, symbols, token, span); + var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, symbols, token, span, position); context.AddItems(items); } @@ -230,7 +230,7 @@ private static TextSpan GetCompletionItemSpan(SourceText text, int position) } private IEnumerable CreateCompletionItems( - Workspace workspace, SemanticModel semanticModel, IEnumerable symbols, SyntaxToken token, TextSpan itemSpan) + Workspace workspace, SemanticModel semanticModel, IEnumerable symbols, SyntaxToken token, TextSpan itemSpan, int position) { var builder = SharedPools.Default().Allocate(); try @@ -238,7 +238,7 @@ private IEnumerable CreateCompletionItems( foreach (var symbol in symbols) { builder.Clear(); - yield return CreateItem(workspace, semanticModel, symbol, token, builder); + yield return CreateItem(workspace, semanticModel, symbol, token, position, builder); } } finally @@ -248,10 +248,8 @@ private IEnumerable CreateCompletionItems( } private CompletionItem CreateItem( - Workspace workspace, SemanticModel semanticModel, ISymbol symbol, SyntaxToken token, StringBuilder builder) + Workspace workspace, SemanticModel semanticModel, ISymbol symbol, SyntaxToken token, int position, StringBuilder builder) { - int position = token.SpanStart; - if (symbol is INamespaceOrTypeSymbol && token.IsKind(SyntaxKind.DotToken)) { // Handle qualified namespace and type names. @@ -303,7 +301,7 @@ private CompletionItem CreateItem( .Replace('>', '}') .ToString(); - return SymbolCompletionItem.Create( + return SymbolCompletionItem.CreateWithNameAndKind( displayText: insertionText, insertionText: insertionText, symbol: symbol, @@ -312,8 +310,37 @@ private CompletionItem CreateItem( rules: GetRules(insertionText)); } - protected override Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) - => SymbolCompletionItem.GetDescriptionAsync(item, document, cancellationToken); + protected override async Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) + { + var position = SymbolCompletionItem.GetContextPosition(item); + var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + if (!tree.IsEntirelyWithinCrefSyntax(position, cancellationToken)) + { + return null; + } + + var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true) + .GetPreviousTokenIfTouchingWord(position); + + // To get a Speculative SemanticModel (which is much faster), we need to + // walk up to the node the DocumentationTrivia is attached to. + var parentNode = token.Parent.FirstAncestorOrSelf()?.ParentTrivia.Token.Parent; + _testSpeculativeNodeCallbackOpt?.Invoke(parentNode); + if (parentNode == null) + { + return null; + } + + var semanticModel = await document.GetSemanticModelForNodeAsync( + parentNode, cancellationToken).ConfigureAwait(false); + + var symbols = GetSymbols(token, semanticModel, cancellationToken); + + var name = SymbolCompletionItem.GetSymbolName(item); + var kind = SymbolCompletionItem.GetKind(item); + var bestSymbols = symbols.Where(s => s.Kind == kind && s.Name == name).ToImmutableArray(); + return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); + } private static readonly CharacterSetModificationRule s_WithoutOpenBrace = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '{'); private static readonly CharacterSetModificationRule s_WithoutOpenParen = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '('); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs index 6df94a6f6e53d..f358c28ba9bcd 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs @@ -111,7 +111,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var workspace = document.Project.Solution.Workspace; var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); - var item = SymbolCompletionItem.Create( + var item = SymbolCompletionItem.CreateWithSymbolId( displayText: displayText, insertionText: null, symbol: alias ?? type, diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceCompletionProvider.cs index 38d95f3f66d61..9cb8e79ba3d65 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceCompletionProvider.cs @@ -96,7 +96,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) semanticModel, namePosition, s_signatureDisplayFormat); var insertionText = displayText; - var item = SymbolCompletionItem.Create( + var item = SymbolCompletionItem.CreateWithSymbolId( displayText, insertionText: insertionText, symbol: member, diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs index 7518ab8e01fa8..9dc67c4462bf8 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs @@ -95,7 +95,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) // exact match. var escapedName = parameter.Name.ToIdentifierToken().ToString(); - context.AddItem(SymbolCompletionItem.Create( + context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: escapedName + ColonString, insertionText: null, symbol: parameter, diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/SymbolCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/SymbolCompletionProvider.cs index 1e2a182b9adc8..0191ac0b8ba37 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/SymbolCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/SymbolCompletionProvider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs index e5b897865dc62..b9800beae0ef5 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractObjectCreationCompletionProvider.cs @@ -30,7 +30,7 @@ protected override CompletionItem CreateItem( SyntaxContext context, bool preselect, SupportedPlatformData supportedPlatformData) { - return SymbolCompletionItem.Create( + return SymbolCompletionItem.CreateWithSymbolId( displayText: displayText, insertionText: insertionText, filterText: GetFilterText(symbols[0], displayText, context), diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs index 2a84fecbca0d3..c52bf2f4fef6c 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractObjectInitializerCompletionProvider.cs @@ -61,7 +61,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) foreach (var uninitializedMember in uninitializedMembers) { - context.AddItem(SymbolCompletionItem.Create( + context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: uninitializedMember.Name, insertionText: null, symbol: uninitializedMember, diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs index c1bc79786db8a..ca1b02c03239d 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs @@ -53,7 +53,7 @@ private CompletionItem CreateCompletionItem( { var displayAndInsertionText = GetDisplayAndInsertionText(symbol, context); - return SymbolCompletionItem.Create( + return SymbolCompletionItem.CreateWithSymbolId( displayText: displayAndInsertionText.Item1, insertionText: displayAndInsertionText.Item2, symbol: symbol, diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 7acf36d135827..9cf0faf8211c6 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Completion.Providers { @@ -64,7 +65,7 @@ protected override CompletionItem CreateItem(string displayText, string insertio rules = rules.WithSelectionBehavior(PreselectedItemSelectionBehavior); } - return SymbolCompletionItem.Create( + return SymbolCompletionItem.CreateWithNameAndKind( displayText: displayText, insertionText: insertionText, filterText: GetFilterText(symbols[0], displayText, context), @@ -100,5 +101,19 @@ private static int ComputeSymbolMatchPriority(ISymbol symbol) return SymbolMatchPriority.PreferType; } + + protected override async Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) + { + var position = SymbolCompletionItem.GetContextPosition(item); + var name = SymbolCompletionItem.GetSymbolName(item); + var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false); + var symbols = await Recommender.GetImmutableRecommendedSymbolsAtPositionAsync( + semanticModel, position, document.Project.Solution.Workspace, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); + + var kind = SymbolCompletionItem.GetKind(item); + + var bestSymbols = symbols.Where(s => (kind != null && s.Kind == kind) && s.Name == name).ToImmutableArray(); + return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); + } } } diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs index 946e3f70c6e7f..71ce0850fb208 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs @@ -118,7 +118,7 @@ protected virtual CompletionItem CreateItem( SyntaxContext context, bool preselect, SupportedPlatformData supportedPlatformData) { - return SymbolCompletionItem.Create( + return SymbolCompletionItem.CreateWithSymbolId( displayText: displayText, insertionText: insertionText, filterText: GetFilterText(symbols[0], displayText, context), @@ -129,9 +129,6 @@ protected virtual CompletionItem CreateItem( rules: GetCompletionItemRules(symbols, context)); } - protected override Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) - => SymbolCompletionItem.GetDescriptionAsync(item, document, cancellationToken); - protected virtual string GetFilterText(ISymbol symbol, string displayText, SyntaxContext context) { return (displayText == symbol.Name) || @@ -148,6 +145,9 @@ protected virtual Task> GetPreselectedSymbolsWorker(Synt return SpecializedTasks.EmptyImmutableArray(); } + protected override Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) + => SymbolCompletionItem.GetDescriptionAsync(item, document, cancellationToken); + public override async Task ProvideCompletionsAsync(CompletionContext context) { var document = context.Document; diff --git a/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs index 89460b53e79d0..9e40b54bbb508 100644 --- a/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs @@ -24,7 +24,7 @@ public static CompletionItem Create( .Add("Modifiers", modifiers.ToString()) .Add("TokenSpanEnd", token.Span.End.ToString()); - return SymbolCompletionItem.Create( + return SymbolCompletionItem.CreateWithSymbolId( displayText: displayText, symbol: symbol, glyph: glyph, diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index 5d30fbf147c7f..ae3d03e98445c 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -11,11 +11,12 @@ namespace Microsoft.CodeAnalysis.Completion.Providers { - internal static class SymbolCompletionItem + internal static partial class SymbolCompletionItem { - public static CompletionItem Create( + private static CompletionItem CreateWorker( string displayText, IReadOnlyList symbols, + Func, CompletionItem, CompletionItem> symbolEncoder, int contextPosition = -1, string sortText = null, string insertionText = null, @@ -29,8 +30,6 @@ public static CompletionItem Create( { var props = properties ?? ImmutableDictionary.Empty; - props = props.Add("Symbols", EncodeSymbols(symbols)); - if (insertionText != null) { props = props.Add("InsertionText", insertionText); @@ -52,12 +51,31 @@ public static CompletionItem Create( tags: tags, rules: rules); - return WithSupportedPlatforms(item, supportedPlatforms); + item = WithSupportedPlatforms(item, supportedPlatforms); + return symbolEncoder(symbols, item); } - public static CompletionItem Create( + public static CompletionItem AddSymbolEncoding(IReadOnlyList symbols, CompletionItem item) + { + return item.AddProperty("Symbol", EncodeSymbols(symbols)); + } + + public static CompletionItem AddSymbolEncoding(ISymbol symbol, CompletionItem item) + { + return item.AddProperty("Symbol", EncodeSymbol(symbol)); + } + + public static CompletionItem AddSymbolNameAndKind(IReadOnlyList symbols, CompletionItem item) + { + var symbol = symbols[0]; + return item.AddProperty("SymbolKind", ((int)symbol.Kind).ToString()) + .AddProperty("SymbolName", symbol.Name); + } + + private static CompletionItem CreateWorker( string displayText, ISymbol symbol, + Func, CompletionItem, CompletionItem> symbolEncoder, int contextPosition = -1, string sortText = null, string insertionText = null, @@ -68,9 +86,10 @@ public static CompletionItem Create( ImmutableDictionary properties = null, CompletionItemRules rules = null) { - return Create( + return CreateWorker( displayText: displayText, symbols: ImmutableArray.Create(symbol), + symbolEncoder: symbolEncoder, contextPosition: contextPosition, sortText: sortText, insertionText: insertionText, @@ -250,5 +269,75 @@ public static string GetInsertionText(CompletionItem item) item.Properties.TryGetValue("InsertionText", out var text); return text; } + + public static CompletionItem CreateWithSymbolId( + string displayText, + IReadOnlyList symbols, + int contextPosition = -1, + string sortText = null, + string insertionText = null, + Glyph? glyph = null, + string filterText = null, + int? matchPriority = null, + SupportedPlatformData supportedPlatforms = null, + ImmutableDictionary properties = null, + ImmutableArray tags = default(ImmutableArray), + CompletionItemRules rules = null) + { + return CreateWorker(displayText, symbols, AddSymbolEncoding, contextPosition, sortText, insertionText, glyph, + filterText, matchPriority, supportedPlatforms, properties, tags, rules); + } + + public static CompletionItem CreateWithSymbolId( + string displayText, + ISymbol symbol, + int contextPosition = -1, + string sortText = null, + string insertionText = null, + Glyph? glyph = null, + string filterText = null, + int? matchPriority = null, + SupportedPlatformData supportedPlatforms = null, + ImmutableDictionary properties = null, + CompletionItemRules rules = null) + { + return CreateWorker(displayText, symbol, AddSymbolEncoding, contextPosition, sortText, insertionText, glyph, + filterText, matchPriority, supportedPlatforms, properties, rules); + } + + public static CompletionItem CreateWithNameAndKind( + string displayText, + IReadOnlyList symbols, + int contextPosition = -1, + string sortText = null, + string insertionText = null, + Glyph? glyph = null, + string filterText = null, + int? matchPriority = null, + SupportedPlatformData supportedPlatforms = null, + ImmutableDictionary properties = null, + ImmutableArray tags = default(ImmutableArray), + CompletionItemRules rules = null) + { + return CreateWorker(displayText, symbols, AddSymbolNameAndKind, contextPosition, sortText, insertionText, glyph, + filterText, matchPriority, supportedPlatforms, properties, tags, rules); + } + + public static CompletionItem CreateWithNameAndKind( + string displayText, + ISymbol symbol, + int contextPosition = -1, + string sortText = null, + string insertionText = null, + Glyph? glyph = null, + string filterText = null, + int? matchPriority = null, + SupportedPlatformData supportedPlatforms = null, + ImmutableDictionary properties = null, + CompletionItemRules rules = null) + { + return CreateWorker(displayText, symbol, AddSymbolNameAndKind, contextPosition, sortText, insertionText, glyph, + filterText, matchPriority, supportedPlatforms, properties, rules: rules); + } } -} +} \ No newline at end of file diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs new file mode 100644 index 0000000000000..648914201e08f --- /dev/null +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Completion.Providers +{ + internal static partial class SymbolCompletionItem + { + internal static string GetSymbolName(CompletionItem item) + { + string name; + if (item.Properties.TryGetValue("SymbolName", out name)) + { + return name; + } + + return null; + } + + internal static SymbolKind? GetKind(CompletionItem item) + { + string kind; + if (item.Properties.TryGetValue("SymbolKind", out kind)) + { + return (SymbolKind)int.Parse(kind); + } + + return null; + } + + public static async Task GetDescriptionAsync(CompletionItem item, ImmutableArray symbols, Document document, CancellationToken cancellationToken) + { + var workspace = document.Project.Solution.Workspace; + + var position = SymbolCompletionItem.GetDescriptionPosition(item); + if (position == -1) + { + position = item.Span.Start; + } + + var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(item, workspace); + + // find appropriate document for descripton context + var contextDocument = document; + if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) + { + var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); + if (contextId != null) + { + contextDocument = document.Project.Solution.GetDocument(contextId); + } + } + + var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (symbols.Length != 0) + { + return await CommonCompletionUtilities.CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms, cancellationToken).ConfigureAwait(false); + } + else + { + return CompletionDescription.Empty; + } + } + } +} diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index eb0f68d8aa077..7879f89ee0365 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -104,6 +104,7 @@ + diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb index e0bc4fabf351b..dbef8a13f7396 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CompletionListTagCompletionProvider.vb @@ -67,7 +67,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers End Function Protected Overrides Function CreateItem(displayText As String, insertionText As String, symbols As List(Of ISymbol), context As SyntaxContext, preselect As Boolean, supportedPlatformData As SupportedPlatformData) As CompletionItem - Return SymbolCompletionItem.Create( + Return SymbolCompletionItem.CreateWithSymbolId( displayText:=displayText, insertionText:=insertionText, filterText:=GetFilterText(symbols(0), displayText, context), diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb index f7e3269fa8322..fb416172d3eec 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports System.Collections.Immutable Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Partial Friend Class CrefCompletionProvider @@ -62,7 +63,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Dim text = Await document.GetTextAsync(cancellationToken).ConfigureAwait(False) - Dim items = CreateCompletionItems(workspace, semanticModel, symbols, token.SpanStart) + Dim items = CreateCompletionItems(workspace, semanticModel, symbols, position) context.AddItems(items) If IsFirstCrefParameterContext(token) Then @@ -197,7 +198,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Dim displayString = builder.ToString() - Return SymbolCompletionItem.Create( + Return SymbolCompletionItem.CreateWithNameAndKind( displayText:=displayString, insertionText:=Nothing, symbol:=symbol, @@ -205,12 +206,32 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers rules:=GetRules(displayString)) End Function - Protected Overrides Function GetDescriptionWorkerAsync(document As Document, item As CompletionItem, cancellationToken As CancellationToken) As Task(Of CompletionDescription) - If CommonCompletionItem.HasDescription(item) Then - Return Task.FromResult(CommonCompletionItem.GetDescription(item)) - Else - Return SymbolCompletionItem.GetDescriptionAsync(item, document, cancellationToken) + Protected Overrides Async Function GetDescriptionWorkerAsync(document As Document, item As CompletionItem, cancellationToken As CancellationToken) As Task(Of CompletionDescription) + Dim position = SymbolCompletionItem.GetContextPosition(item) + Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) + Dim token = tree.GetTargetToken(position, cancellationToken) + + + If IsCrefTypeParameterContext(token) Then + Return Nothing End If + + ' To get a Speculative SemanticModel (which is much faster), we need to + ' walk up to the node the DocumentationTrivia is attached to. + Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent + _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) + If parentNode Is Nothing Then + Return Nothing + End If + + Dim semanticModel = Await document.GetSemanticModelForNodeAsync(parentNode, cancellationToken).ConfigureAwait(False) + Dim workspace = document.Project.Solution.Workspace + + Dim symbols = GetSymbols(token, semanticModel, cancellationToken) + Dim symbolName = SymbolCompletionItem.GetSymbolName(item) + Dim symbolKind = SymbolCompletionItem.GetKind(item).GetValueOrDefault() + Dim bestSymbols = symbols.Where(Function(s) s.Kind = symbolKind AndAlso s.Name = symbolName).ToImmutableArray() + Return Await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(False) End Function Private Function CreateOfCompletionItem() As CompletionItem diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb index 7264bd412dca4..46c1815111ed7 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/EnumCompletionProvider.vb @@ -123,7 +123,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers End Function Protected Overrides Function CreateItem(displayText As String, insertionText As String, symbols As List(Of ISymbol), context As SyntaxContext, preselect As Boolean, supportedPlatformData As SupportedPlatformData) As CompletionItem - Return SymbolCompletionItem.Create( + Return SymbolCompletionItem.CreateWithSymbolId( displayText:=displayText, insertionText:=insertionText, filterText:=GetFilterText(symbols(0), displayText, context), diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/HandlesClauseCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/HandlesClauseCompletionProvider.vb index cd65e273cdd46..460c837c43c41 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/HandlesClauseCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/HandlesClauseCompletionProvider.vb @@ -120,7 +120,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Dim displayAndInsertionText = CompletionUtilities.GetDisplayAndInsertionText(symbol, context) - Return SymbolCompletionItem.Create( + Return SymbolCompletionItem.CreateWithSymbolId( displayText:=displayAndInsertionText.Item1, insertionText:=displayAndInsertionText.Item2, symbol:=symbol, diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb index b203257879436..14c77360879a6 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.vb @@ -66,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Dim text = Await document.GetTextAsync(cancellationToken).ConfigureAwait(False) For Each parameter In unspecifiedParameters - context.AddItem(SymbolCompletionItem.Create( + context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText:=parameter.Name & s_colonEquals, insertionText:=parameter.Name.ToIdentifierToken().ToString() & s_colonEquals, symbol:=parameter, From 06cd97a6fa6d0b1fc15c17adc1a12da281a34bc9 Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Mon, 5 Dec 2016 15:38:42 -0800 Subject: [PATCH 2/9] CR feedback --- .../CrefCompletionProvider.cs | 71 ++++++++----------- src/Features/CSharp/Portable/project.json | 4 +- ...mendationServiceBasedCompletionProvider.cs | 22 +++--- .../Providers/SymbolCompletionItem.cs | 62 ++++++++++++++-- .../Providers/SymbolCompletionItem2.cs | 69 ------------------ src/Features/Core/Portable/Features.csproj | 1 - .../CrefCompletionProvider.vb | 23 ++++++ 7 files changed, 127 insertions(+), 125 deletions(-) delete mode 100644 src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs index 59ef5323418cc..0c02a3dee1674 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs @@ -21,6 +21,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { internal sealed class CrefCompletionProvider : CommonCompletionProvider { + private class CrefCompletionState + { + public SemanticModel SemanticModel { get; set; } + public SyntaxToken SyntaxToken {get; set;} + public ImmutableArray Symbols { get; set; } + } + public static readonly SymbolDisplayFormat QualifiedCrefFormat = new SymbolDisplayFormat( globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, @@ -60,10 +67,29 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var options = context.Options; var cancellationToken = context.CancellationToken; + var (token, semanticModel, symbols) = await GetSymbols(document, position, cancellationToken).ConfigureAwait(false); + var filteredSymbols = symbols.FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); + + if (!filteredSymbols.Any()) + { + return; + } + + context.IsExclusive = true; + + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var span = GetCompletionItemSpan(text, position); + + var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, filteredSymbols, token, span, position); + context.AddItems(items); + } + + private async Task<(SyntaxToken, SemanticModel, ImmutableArray)> GetSymbols(Document document, int position, CancellationToken cancellationToken) + { var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (!tree.IsEntirelyWithinCrefSyntax(position, cancellationToken)) { - return; + return (default(SyntaxToken), null, ImmutableArray.Empty); } var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true) @@ -75,28 +101,14 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) _testSpeculativeNodeCallbackOpt?.Invoke(parentNode); if (parentNode == null) { - return; + return (default(SyntaxToken), null, ImmutableArray.Empty); } var semanticModel = await document.GetSemanticModelForNodeAsync( parentNode, cancellationToken).ConfigureAwait(false); var symbols = GetSymbols(token, semanticModel, cancellationToken); - - symbols = symbols.FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); - - if (!symbols.Any()) - { - return; - } - - context.IsExclusive = true; - - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var span = GetCompletionItemSpan(text, position); - - var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, symbols, token, span, position); - context.AddItems(items); + return (token, semanticModel, symbols); } private static bool IsCrefStartContext(SyntaxToken token) @@ -313,32 +325,11 @@ private CompletionItem CreateItem( protected override async Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) { var position = SymbolCompletionItem.GetContextPosition(item); - var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - if (!tree.IsEntirelyWithinCrefSyntax(position, cancellationToken)) - { - return null; - } - - var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true) - .GetPreviousTokenIfTouchingWord(position); - - // To get a Speculative SemanticModel (which is much faster), we need to - // walk up to the node the DocumentationTrivia is attached to. - var parentNode = token.Parent.FirstAncestorOrSelf()?.ParentTrivia.Token.Parent; - _testSpeculativeNodeCallbackOpt?.Invoke(parentNode); - if (parentNode == null) - { - return null; - } - - var semanticModel = await document.GetSemanticModelForNodeAsync( - parentNode, cancellationToken).ConfigureAwait(false); - - var symbols = GetSymbols(token, semanticModel, cancellationToken); + var (token, semanticModel, symbols) = await GetSymbols(document, position, cancellationToken).ConfigureAwait(false); var name = SymbolCompletionItem.GetSymbolName(item); var kind = SymbolCompletionItem.GetKind(item); - var bestSymbols = symbols.Where(s => s.Kind == kind && s.Name == name).ToImmutableArray(); + var bestSymbols = symbols.WhereAsArray(s => s.Kind == kind && s.Name == name); return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/CSharp/Portable/project.json b/src/Features/CSharp/Portable/project.json index a5bfa3b918f93..e75a1bda99d17 100644 --- a/src/Features/CSharp/Portable/project.json +++ b/src/Features/CSharp/Portable/project.json @@ -1,5 +1,7 @@ { - "dependencies": { }, + "dependencies": { + "System.ValueTuple": "4.3.0" + }, "frameworks": { "netstandard1.3": { "imports": [ "portable-net45+win8", "dotnet" ] diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 9cf0faf8211c6..26e8b751cbd58 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -1,16 +1,16 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.Completion.Providers { @@ -106,13 +106,15 @@ protected override async Task GetDescriptionWorkerAsync(D { var position = SymbolCompletionItem.GetContextPosition(item); var name = SymbolCompletionItem.GetSymbolName(item); - var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken) + .ConfigureAwait(false); var symbols = await Recommender.GetImmutableRecommendedSymbolsAtPositionAsync( - semanticModel, position, document.Project.Solution.Workspace, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); + semanticModel, position, document.Project.Solution.Workspace, + document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); var kind = SymbolCompletionItem.GetKind(item); - var bestSymbols = symbols.Where(s => (kind != null && s.Kind == kind) && s.Name == name).ToImmutableArray(); + var bestSymbols = symbols.Where(s => kind != null && s.Kind == kind && s.Name == name).ToImmutableArray(); return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index ae3d03e98445c..eab7609ba0f95 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -273,7 +273,7 @@ public static string GetInsertionText(CompletionItem item) public static CompletionItem CreateWithSymbolId( string displayText, IReadOnlyList symbols, - int contextPosition = -1, + int contextPosition, string sortText = null, string insertionText = null, Glyph? glyph = null, @@ -291,7 +291,7 @@ public static CompletionItem CreateWithSymbolId( public static CompletionItem CreateWithSymbolId( string displayText, ISymbol symbol, - int contextPosition = -1, + int contextPosition, string sortText = null, string insertionText = null, Glyph? glyph = null, @@ -308,7 +308,7 @@ public static CompletionItem CreateWithSymbolId( public static CompletionItem CreateWithNameAndKind( string displayText, IReadOnlyList symbols, - int contextPosition = -1, + int contextPosition, string sortText = null, string insertionText = null, Glyph? glyph = null, @@ -326,7 +326,7 @@ public static CompletionItem CreateWithNameAndKind( public static CompletionItem CreateWithNameAndKind( string displayText, ISymbol symbol, - int contextPosition = -1, + int contextPosition, string sortText = null, string insertionText = null, Glyph? glyph = null, @@ -339,5 +339,59 @@ public static CompletionItem CreateWithNameAndKind( return CreateWorker(displayText, symbol, AddSymbolNameAndKind, contextPosition, sortText, insertionText, glyph, filterText, matchPriority, supportedPlatforms, properties, rules: rules); } + + internal static string GetSymbolName(CompletionItem item) + { + if (item.Properties.TryGetValue("SymbolName", out var name)) + { + return name; + } + + return null; + } + + internal static SymbolKind? GetKind(CompletionItem item) + { + if (item.Properties.TryGetValue("SymbolKind", out var kind)) + { + return (SymbolKind)int.Parse(kind); + } + + return null; + } + + public static async Task GetDescriptionAsync(CompletionItem item, ImmutableArray symbols, Document document, CancellationToken cancellationToken) + { + var workspace = document.Project.Solution.Workspace; + + var position = SymbolCompletionItem.GetDescriptionPosition(item); + if (position == -1) + { + position = item.Span.Start; + } + + var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(item, workspace); + + // find appropriate document for descripton context + var contextDocument = document; + if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) + { + var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); + if (contextId != null) + { + contextDocument = document.Project.Solution.GetDocument(contextId); + } + } + + var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (symbols.Length != 0) + { + return await CommonCompletionUtilities.CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms, cancellationToken).ConfigureAwait(false); + } + else + { + return CompletionDescription.Empty; + } + } } } \ No newline at end of file diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs deleted file mode 100644 index 648914201e08f..0000000000000 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem2.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.CodeAnalysis.Completion.Providers -{ - internal static partial class SymbolCompletionItem - { - internal static string GetSymbolName(CompletionItem item) - { - string name; - if (item.Properties.TryGetValue("SymbolName", out name)) - { - return name; - } - - return null; - } - - internal static SymbolKind? GetKind(CompletionItem item) - { - string kind; - if (item.Properties.TryGetValue("SymbolKind", out kind)) - { - return (SymbolKind)int.Parse(kind); - } - - return null; - } - - public static async Task GetDescriptionAsync(CompletionItem item, ImmutableArray symbols, Document document, CancellationToken cancellationToken) - { - var workspace = document.Project.Solution.Workspace; - - var position = SymbolCompletionItem.GetDescriptionPosition(item); - if (position == -1) - { - position = item.Span.Start; - } - - var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(item, workspace); - - // find appropriate document for descripton context - var contextDocument = document; - if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) - { - var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); - if (contextId != null) - { - contextDocument = document.Project.Solution.GetDocument(contextId); - } - } - - var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - if (symbols.Length != 0) - { - return await CommonCompletionUtilities.CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms, cancellationToken).ConfigureAwait(false); - } - else - { - return CompletionDescription.Empty; - } - } - } -} diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index 7879f89ee0365..eb0f68d8aa077 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -104,7 +104,6 @@ - diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb index fb416172d3eec..e05ec99eeeb49 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb @@ -74,6 +74,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers context.IsExclusive = True End Function + Private Async Function GetSymbols(position As Integer, document As Document, cancellationToken As CancellationToken) As Task(Of (SyntaxToken, SemanticModel, ImmutableArray(Of ISymbol))) + Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) + Dim token = tree.GetTargetToken(position, cancellationToken) + + If IsCrefTypeParameterContext(token) Then + Return (Nothing, Nothing, Nothing) + End If + + ' To get a Speculative SemanticModel (which is much faster), we need to + ' walk up to the node the DocumentationTrivia is attached to. + Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent + _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) + If parentNode Is Nothing Then + Return (Nothing, Nothing, Nothing) + End If + + Dim semanticModel = Await document.GetSemanticModelForNodeAsync(parentNode, cancellationToken).ConfigureAwait(False) + Dim workspace = document.Project.Solution.Workspace + + Dim symbols = GetSymbols(token, semanticModel, cancellationToken) + Return (token, semanticModel, symbols.ToImmutableArray()) + End Function + Private Shared Function IsCrefTypeParameterContext(token As SyntaxToken) As Boolean Return (token.IsChildToken(Function(t As TypeArgumentListSyntax) t.OfKeyword) OrElse token.IsChildSeparatorToken(Function(t As TypeArgumentListSyntax) t.Arguments)) AndAlso From 47400de4ac75b9d39b7cccf4ef722b4329de528d Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Mon, 5 Dec 2016 20:03:14 -0800 Subject: [PATCH 3/9] Various CR feedback: Use editorbrowsable options when computing cref descriptions Share cref description computation code between C#/VB Etc --- .../CrefCompletionProvider.cs | 44 +++++-------- .../AbstractCrefCompletionProvider.cs | 40 ++++++++++++ .../Providers/SymbolCompletionItem.cs | 63 ++++++------------- src/Features/Core/Portable/Features.csproj | 1 + .../CrefCompletionProvider.vb | 41 ++---------- 5 files changed, 83 insertions(+), 106 deletions(-) create mode 100644 src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs index 0c02a3dee1674..2c753e61ddd89 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs @@ -19,14 +19,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { - internal sealed class CrefCompletionProvider : CommonCompletionProvider + internal sealed class CrefCompletionProvider : AbstractCrefCompletionProvider { - private class CrefCompletionState - { - public SemanticModel SemanticModel { get; set; } - public SyntaxToken SyntaxToken {get; set;} - public ImmutableArray Symbols { get; set; } - } public static readonly SymbolDisplayFormat QualifiedCrefFormat = new SymbolDisplayFormat( @@ -67,10 +61,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var options = context.Options; var cancellationToken = context.CancellationToken; - var (token, semanticModel, symbols) = await GetSymbols(document, position, cancellationToken).ConfigureAwait(false); - var filteredSymbols = symbols.FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); + var (token, semanticModel, symbols) = await GetSymbolsAsync(document, position, options, cancellationToken).ConfigureAwait(false); - if (!filteredSymbols.Any()) + if (symbols.Length == 0) { return; } @@ -79,12 +72,15 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var span = GetCompletionItemSpan(text, position); + var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language); + var serializedOptions = ImmutableDictionary.Empty.Add(HideAdvancedMembers, hideAdvancedMembers.ToString()); - var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, filteredSymbols, token, span, position); + var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, symbols, token, span, position, serializedOptions); context.AddItems(items); } - private async Task<(SyntaxToken, SemanticModel, ImmutableArray)> GetSymbols(Document document, int position, CancellationToken cancellationToken) + protected override async Task<(SyntaxToken, SemanticModel, ImmutableArray)> GetSymbolsAsync( + Document document, int position, OptionSet options, CancellationToken cancellationToken) { var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (!tree.IsEntirelyWithinCrefSyntax(position, cancellationToken)) @@ -107,7 +103,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var semanticModel = await document.GetSemanticModelForNodeAsync( parentNode, cancellationToken).ConfigureAwait(false); - var symbols = GetSymbols(token, semanticModel, cancellationToken); + var symbols = GetSymbols(token, semanticModel, cancellationToken) + .FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); + return (token, semanticModel, symbols); } @@ -242,7 +240,7 @@ private static TextSpan GetCompletionItemSpan(SourceText text, int position) } private IEnumerable CreateCompletionItems( - Workspace workspace, SemanticModel semanticModel, IEnumerable symbols, SyntaxToken token, TextSpan itemSpan, int position) + Workspace workspace, SemanticModel semanticModel, IEnumerable symbols, SyntaxToken token, TextSpan itemSpan, int position, ImmutableDictionary options) { var builder = SharedPools.Default().Allocate(); try @@ -250,7 +248,7 @@ private IEnumerable CreateCompletionItems( foreach (var symbol in symbols) { builder.Clear(); - yield return CreateItem(workspace, semanticModel, symbol, token, position, builder); + yield return CreateItem(workspace, semanticModel, symbol, token, position, builder, options); } } finally @@ -260,7 +258,7 @@ private IEnumerable CreateCompletionItems( } private CompletionItem CreateItem( - Workspace workspace, SemanticModel semanticModel, ISymbol symbol, SyntaxToken token, int position, StringBuilder builder) + Workspace workspace, SemanticModel semanticModel, ISymbol symbol, SyntaxToken token, int position, StringBuilder builder, ImmutableDictionary options) { if (symbol is INamespaceOrTypeSymbol && token.IsKind(SyntaxKind.DotToken)) { @@ -316,22 +314,14 @@ private CompletionItem CreateItem( return SymbolCompletionItem.CreateWithNameAndKind( displayText: insertionText, insertionText: insertionText, - symbol: symbol, + symbols: ImmutableArray.Create(symbol), contextPosition: position, sortText: symbolText, + properties: options, rules: GetRules(insertionText)); } - protected override async Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) - { - var position = SymbolCompletionItem.GetContextPosition(item); - - var (token, semanticModel, symbols) = await GetSymbols(document, position, cancellationToken).ConfigureAwait(false); - var name = SymbolCompletionItem.GetSymbolName(item); - var kind = SymbolCompletionItem.GetKind(item); - var bestSymbols = symbols.WhereAsArray(s => s.Kind == kind && s.Name == name); - return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); - } + private static readonly CharacterSetModificationRule s_WithoutOpenBrace = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '{'); private static readonly CharacterSetModificationRule s_WithoutOpenParen = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '('); diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs new file mode 100644 index 0000000000000..4a2a407ab8901 --- /dev/null +++ b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs @@ -0,0 +1,40 @@ +using Microsoft.CodeAnalysis.Options; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Completion.Providers +{ + abstract class AbstractCrefCompletionProvider : CommonCompletionProvider + { + protected const string HideAdvancedMembers = nameof(HideAdvancedMembers); + + protected override async Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) + { + var position = SymbolCompletionItem.GetContextPosition(item); + + // What EditorBrowsable settings were we previously passed in (if it mattered)? + bool hideAdvancedMembers = false; + if (item.Properties.TryGetValue(HideAdvancedMembers, out var hideAdvancedMembersString)) + { + bool.TryParse(hideAdvancedMembersString, out hideAdvancedMembers); + } + + var options = document.Project.Solution.Workspace.Options + .WithChangedOption(new OptionKey(CompletionOptions.HideAdvancedMembers, document.Project.Language), hideAdvancedMembers); + + var (token, semanticModel, symbols) = await GetSymbolsAsync(document, position, options, cancellationToken).ConfigureAwait(false); + var name = SymbolCompletionItem.GetSymbolName(item); + var kind = SymbolCompletionItem.GetKind(item); + var bestSymbols = symbols.WhereAsArray(s => s.Kind == kind && s.Name == name); + return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); + } + + protected abstract Task<(SyntaxToken, SemanticModel, ImmutableArray)> GetSymbolsAsync( + Document document, int position, OptionSet options, CancellationToken cancellationToken); + } +} diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index eab7609ba0f95..b60a2ca5d2d45 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -195,16 +195,7 @@ public static async Task GetDescriptionAsync(CompletionIt var supportedPlatforms = GetSupportedPlatforms(item, workspace); - // find appropriate document for descripton context - var contextDocument = document; - if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) - { - var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); - if (contextId != null) - { - contextDocument = document.Project.Solution.GetDocument(contextId); - } - } + Document contextDocument = FindAppropriateDocumentForDescriptionContext(document, supportedPlatforms); var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var symbols = await GetSymbolsAsync(item, document, cancellationToken).ConfigureAwait(false); @@ -218,6 +209,21 @@ public static async Task GetDescriptionAsync(CompletionIt } } + private static Document FindAppropriateDocumentForDescriptionContext(Document document, SupportedPlatformData supportedPlatforms) + { + var contextDocument = document; + if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) + { + var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); + if (contextId != null) + { + contextDocument = document.Project.Solution.GetDocument(contextId); + } + } + + return contextDocument; + } + private static CompletionItem WithSupportedPlatforms(CompletionItem completionItem, SupportedPlatformData supportedPlatforms) { if (supportedPlatforms != null) @@ -235,7 +241,7 @@ private static CompletionItem WithSupportedPlatforms(CompletionItem completionIt private static readonly char[] projectSeperators = new[] { ';' }; public static SupportedPlatformData GetSupportedPlatforms(CompletionItem item, Workspace workspace) { - if (item.Properties.TryGetValue("InvalidProjects", out var invalidProjects) + if (item.Properties.TryGetValue("InvalidProjects", out var invalidProjects) && item.Properties.TryGetValue("CandidateProjects", out var candidateProjects)) { return new SupportedPlatformData( @@ -323,23 +329,6 @@ public static CompletionItem CreateWithNameAndKind( filterText, matchPriority, supportedPlatforms, properties, tags, rules); } - public static CompletionItem CreateWithNameAndKind( - string displayText, - ISymbol symbol, - int contextPosition, - string sortText = null, - string insertionText = null, - Glyph? glyph = null, - string filterText = null, - int? matchPriority = null, - SupportedPlatformData supportedPlatforms = null, - ImmutableDictionary properties = null, - CompletionItemRules rules = null) - { - return CreateWorker(displayText, symbol, AddSymbolNameAndKind, contextPosition, sortText, insertionText, glyph, - filterText, matchPriority, supportedPlatforms, properties, rules: rules); - } - internal static string GetSymbolName(CompletionItem item) { if (item.Properties.TryGetValue("SymbolName", out var name)) @@ -365,27 +354,13 @@ public static async Task GetDescriptionAsync(CompletionIt var workspace = document.Project.Solution.Workspace; var position = SymbolCompletionItem.GetDescriptionPosition(item); - if (position == -1) - { - position = item.Span.Start; - } - var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(item, workspace); - // find appropriate document for descripton context - var contextDocument = document; - if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) - { - var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); - if (contextId != null) - { - contextDocument = document.Project.Solution.GetDocument(contextId); - } - } + var contextDocument = FindAppropriateDocumentForDescriptionContext(document, supportedPlatforms); - var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (symbols.Length != 0) { + var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); return await CommonCompletionUtilities.CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms, cancellationToken).ConfigureAwait(false); } else diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index eb0f68d8aa077..20134d2ffc9e7 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -104,6 +104,7 @@ + diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb index e05ec99eeeb49..42d8d32037d56 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb @@ -13,7 +13,7 @@ Imports System.Collections.Immutable Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Partial Friend Class CrefCompletionProvider - Inherits CommonCompletionProvider + Inherits AbstractCrefCompletionProvider Private Shared ReadOnly s_crefFormat As SymbolDisplayFormat = New SymbolDisplayFormat( @@ -73,8 +73,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers context.IsExclusive = True End Function - - Private Async Function GetSymbols(position As Integer, document As Document, cancellationToken As CancellationToken) As Task(Of (SyntaxToken, SemanticModel, ImmutableArray(Of ISymbol))) + Protected Overrides Async Function GetSymbolsAsync(document As Document, position As Integer, options As OptionSet, cancellationToken As CancellationToken) As Task(Of (SyntaxToken, SemanticModel, ImmutableArray(Of ISymbol))) Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim token = tree.GetTargetToken(position, cancellationToken) @@ -85,8 +84,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers ' To get a Speculative SemanticModel (which is much faster), we need to ' walk up to the node the DocumentationTrivia is attached to. Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent - _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) - If parentNode Is Nothing Then + _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) + If parentNode Is Nothing Then Return (Nothing, Nothing, Nothing) End If @@ -138,7 +137,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return token.IsChildToken(Function(x As CrefSignatureSyntax) x.OpenParenToken) End Function - Private Shared Function GetSymbols(token As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken) As IEnumerable(Of ISymbol) + Private Overloads Shared Function GetSymbols(token As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken) As IEnumerable(Of ISymbol) If IsCrefStartContext(token) Then Return semanticModel.LookupSymbols(token.SpanStart) ElseIf IsCrefParameterListContext(token) Then @@ -224,39 +223,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return SymbolCompletionItem.CreateWithNameAndKind( displayText:=displayString, insertionText:=Nothing, - symbol:=symbol, + symbols:=ImmutableArray.Create(symbol), contextPosition:=position, rules:=GetRules(displayString)) End Function - Protected Overrides Async Function GetDescriptionWorkerAsync(document As Document, item As CompletionItem, cancellationToken As CancellationToken) As Task(Of CompletionDescription) - Dim position = SymbolCompletionItem.GetContextPosition(item) - Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) - Dim token = tree.GetTargetToken(position, cancellationToken) - - - If IsCrefTypeParameterContext(token) Then - Return Nothing - End If - - ' To get a Speculative SemanticModel (which is much faster), we need to - ' walk up to the node the DocumentationTrivia is attached to. - Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent - _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) - If parentNode Is Nothing Then - Return Nothing - End If - - Dim semanticModel = Await document.GetSemanticModelForNodeAsync(parentNode, cancellationToken).ConfigureAwait(False) - Dim workspace = document.Project.Solution.Workspace - - Dim symbols = GetSymbols(token, semanticModel, cancellationToken) - Dim symbolName = SymbolCompletionItem.GetSymbolName(item) - Dim symbolKind = SymbolCompletionItem.GetKind(item).GetValueOrDefault() - Dim bestSymbols = symbols.Where(Function(s) s.Kind = symbolKind AndAlso s.Name = symbolName).ToImmutableArray() - Return Await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(False) - End Function - Private Function CreateOfCompletionItem() As CompletionItem Return CommonCompletionItem.Create("Of", glyph:=Glyph.Keyword, description:=RecommendedKeyword.CreateDisplayParts("Of", VBFeaturesResources.Identifies_a_type_parameter_on_a_generic_class_structure_interface_delegate_or_procedure)) From 95eb04f689c5992ff183a693c57c61fce6970e8d Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Tue, 6 Dec 2016 11:03:54 -0800 Subject: [PATCH 4/9] Satisfy RepoUtil --- src/Features/CSharp/Portable/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/CSharp/Portable/project.json b/src/Features/CSharp/Portable/project.json index e75a1bda99d17..7b79d316698f6 100644 --- a/src/Features/CSharp/Portable/project.json +++ b/src/Features/CSharp/Portable/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "System.ValueTuple": "4.3.0" + "System.ValueTuple": "4.0.1-beta-24425-02" }, "frameworks": { "netstandard1.3": { From da54972b3e36423e4b7e0832d6dfb052d3af6177 Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Tue, 6 Dec 2016 12:58:11 -0800 Subject: [PATCH 5/9] Fix tests --- .../Portable/Completion/Providers/SymbolCompletionItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index b60a2ca5d2d45..8aee48681ba23 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -57,12 +57,12 @@ private static CompletionItem CreateWorker( public static CompletionItem AddSymbolEncoding(IReadOnlyList symbols, CompletionItem item) { - return item.AddProperty("Symbol", EncodeSymbols(symbols)); + return item.AddProperty("Symbols", EncodeSymbols(symbols)); } public static CompletionItem AddSymbolEncoding(ISymbol symbol, CompletionItem item) { - return item.AddProperty("Symbol", EncodeSymbol(symbol)); + return item.AddProperty("Symbols", EncodeSymbol(symbol)); } public static CompletionItem AddSymbolNameAndKind(IReadOnlyList symbols, CompletionItem item) From 0054e90931696dcace6e498f0638ea834e6d75de Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Tue, 6 Dec 2016 13:31:09 -0800 Subject: [PATCH 6/9] Line wrapping/copyright headers --- .../CompletionProviders/CrefCompletionProvider.cs | 11 ++++++----- .../Providers/AbstractCrefCompletionProvider.cs | 8 +++----- ...actRecommendationServiceBasedCompletionProvider.cs | 7 +++++-- .../Completion/Providers/SymbolCompletionItem.cs | 2 +- .../CompletionProviders/CrefCompletionProvider.vb | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs index 2c753e61ddd89..015f12a3d9486 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs @@ -75,7 +75,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language); var serializedOptions = ImmutableDictionary.Empty.Add(HideAdvancedMembers, hideAdvancedMembers.ToString()); - var items = CreateCompletionItems(document.Project.Solution.Workspace, semanticModel, symbols, token, span, position, serializedOptions); + var items = CreateCompletionItems(document.Project.Solution.Workspace, + semanticModel, symbols, token, span, position, serializedOptions); + context.AddItems(items); } @@ -104,7 +106,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) parentNode, cancellationToken).ConfigureAwait(false); var symbols = GetSymbols(token, semanticModel, cancellationToken) - .FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); + .FilterToVisibleAndBrowsableSymbols( + options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), + semanticModel.Compilation); return (token, semanticModel, symbols); } @@ -321,8 +325,6 @@ private CompletionItem CreateItem( rules: GetRules(insertionText)); } - - private static readonly CharacterSetModificationRule s_WithoutOpenBrace = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '{'); private static readonly CharacterSetModificationRule s_WithoutOpenParen = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '('); @@ -350,7 +352,6 @@ private CompletionItemRules GetRules(string displayText) } } - private static readonly string InsertionTextProperty = "insertionText"; protected override Task GetTextChangeAsync(CompletionItem selectedItem, char? ch, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs index 4a2a407ab8901..cee676f96517e 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs @@ -1,9 +1,7 @@ -using Microsoft.CodeAnalysis.Options; -using System; -using System.Collections.Generic; +// 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.Options; using System.Collections.Immutable; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 26e8b751cbd58..1b7edf3676690 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -1,4 +1,6 @@ -using Microsoft.CodeAnalysis.LanguageServices; +// 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.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Recommendations; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -102,7 +104,8 @@ private static int ComputeSymbolMatchPriority(ISymbol symbol) return SymbolMatchPriority.PreferType; } - protected override async Task GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken) + protected override async Task GetDescriptionWorkerAsync( + Document document, CompletionItem item, CancellationToken cancellationToken) { var position = SymbolCompletionItem.GetContextPosition(item); var name = SymbolCompletionItem.GetSymbolName(item); diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index 8aee48681ba23..6130cba8e6944 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -195,7 +195,7 @@ public static async Task GetDescriptionAsync(CompletionIt var supportedPlatforms = GetSupportedPlatforms(item, workspace); - Document contextDocument = FindAppropriateDocumentForDescriptionContext(document, supportedPlatforms); + var contextDocument = FindAppropriateDocumentForDescriptionContext(document, supportedPlatforms); var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var symbols = await GetSymbolsAsync(item, document, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb index 42d8d32037d56..faaa33614f1ab 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb @@ -78,7 +78,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Dim token = tree.GetTargetToken(position, cancellationToken) If IsCrefTypeParameterContext(token) Then - Return (Nothing, Nothing, Nothing) + Return Nothing End If ' To get a Speculative SemanticModel (which is much faster), we need to @@ -86,7 +86,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) If parentNode Is Nothing Then - Return (Nothing, Nothing, Nothing) + Return Nothing End If Dim semanticModel = Await document.GetSemanticModelForNodeAsync(parentNode, cancellationToken).ConfigureAwait(False) From 50bd970a1f11910515b1377ae1a9b0a571ecce1a Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Tue, 6 Dec 2016 15:25:40 -0800 Subject: [PATCH 7/9] Pass through correct SemanticModel --- .../Completion/Providers/AbstractCrefCompletionProvider.cs | 2 +- .../AbstractRecommendationServiceBasedCompletionProvider.cs | 4 ++-- .../Portable/Completion/Providers/SymbolCompletionItem.cs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs index cee676f96517e..48019b726c55e 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractCrefCompletionProvider.cs @@ -29,7 +29,7 @@ protected override async Task GetDescriptionWorkerAsync(D var name = SymbolCompletionItem.GetSymbolName(item); var kind = SymbolCompletionItem.GetKind(item); var bestSymbols = symbols.WhereAsArray(s => s.Kind == kind && s.Name == name); - return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); + return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, semanticModel, cancellationToken).ConfigureAwait(false); } protected abstract Task<(SyntaxToken, SemanticModel, ImmutableArray)> GetSymbolsAsync( diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 1b7edf3676690..4d4a8af218a93 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -40,7 +40,7 @@ protected override async Task> GetPreselectedSymbolsWork var symbols = await recommender.GetRecommendedSymbolsAtPositionAsync( context.Workspace, context.SemanticModel, - position, + context.LeftToken.SpanStart, options, cancellationToken).ConfigureAwait(false); @@ -118,7 +118,7 @@ protected override async Task GetDescriptionWorkerAsync( var kind = SymbolCompletionItem.GetKind(item); var bestSymbols = symbols.Where(s => kind != null && s.Kind == kind && s.Name == name).ToImmutableArray(); - return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, cancellationToken).ConfigureAwait(false); + return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, semanticModel, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index 6130cba8e6944..6ba7a2050ab99 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -349,7 +349,7 @@ internal static string GetSymbolName(CompletionItem item) return null; } - public static async Task GetDescriptionAsync(CompletionItem item, ImmutableArray symbols, Document document, CancellationToken cancellationToken) + public static async Task GetDescriptionAsync(CompletionItem item, ImmutableArray symbols, Document document, SemanticModel semanticModel, CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; @@ -360,7 +360,6 @@ public static async Task GetDescriptionAsync(CompletionIt if (symbols.Length != 0) { - var semanticModel = await contextDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); return await CommonCompletionUtilities.CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms, cancellationToken).ConfigureAwait(false); } else From df29fa858c5f2b2aed838417335d9d0c952315ec Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Tue, 6 Dec 2016 17:39:35 -0800 Subject: [PATCH 8/9] Make description computation work in linked files --- .../CrefCompletionProvider.cs | 2 +- ...mendationServiceBasedCompletionProvider.cs | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs index 015f12a3d9486..259bb80804a8a 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CrefCompletionProvider.cs @@ -274,7 +274,7 @@ private CompletionItem CreateItem( { // Handle unqualified namespace and type names, or member names. - builder.Append(symbol.ToMinimalDisplayString(semanticModel, position, CrefFormat)); + builder.Append(symbol.ToMinimalDisplayString(semanticModel, token.SpanStart, CrefFormat)); var parameters = symbol.GetParameters(); if (!parameters.IsDefaultOrEmpty) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs index 4d4a8af218a93..bdeff78e9bb2f 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractRecommendationServiceBasedCompletionProvider.cs @@ -38,10 +38,10 @@ protected override async Task> GetPreselectedSymbolsWork } var symbols = await recommender.GetRecommendedSymbolsAtPositionAsync( - context.Workspace, - context.SemanticModel, - context.LeftToken.SpanStart, - options, + context.Workspace, + context.SemanticModel, + context.Position, + options, cancellationToken).ConfigureAwait(false); // Don't preselect intrinsic type symbols so we can preselect their keywords instead. @@ -109,16 +109,20 @@ protected override async Task GetDescriptionWorkerAsync( { var position = SymbolCompletionItem.GetContextPosition(item); var name = SymbolCompletionItem.GetSymbolName(item); - var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken) - .ConfigureAwait(false); - var symbols = await Recommender.GetImmutableRecommendedSymbolsAtPositionAsync( - semanticModel, position, document.Project.Solution.Workspace, - document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); - var kind = SymbolCompletionItem.GetKind(item); + var relatedDocumentIds = document.Project.Solution.GetRelatedDocumentIds(document.Id).Concat(document.Id); + var options = document.Project.Solution.Workspace.Options; + var totalSymbols = await base.GetPerContextSymbols(document, position, options, relatedDocumentIds, preselect: false, cancellationToken: cancellationToken).ConfigureAwait(false); + foreach (var info in totalSymbols) + { + var bestSymbols = info.Item3.Where(s => kind != null && s.Kind == kind && s.Name == name).ToImmutableArray(); + if (bestSymbols.Any()) + { + return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, info.Item2.SemanticModel, cancellationToken).ConfigureAwait(false); + } + } - var bestSymbols = symbols.Where(s => kind != null && s.Kind == kind && s.Name == name).ToImmutableArray(); - return await SymbolCompletionItem.GetDescriptionAsync(item, bestSymbols, document, semanticModel, cancellationToken).ConfigureAwait(false); + return CompletionDescription.Empty; } } } From c1fe0af4d54f652d129b20abaf5c58d4f3114556 Mon Sep 17 00:00:00 2001 From: Ravi Chande Date: Wed, 4 Jan 2017 11:02:42 -0800 Subject: [PATCH 9/9] Use correct version of ValueTuple --- src/Features/CSharp/Portable/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/CSharp/Portable/project.json b/src/Features/CSharp/Portable/project.json index 7b79d316698f6..e75a1bda99d17 100644 --- a/src/Features/CSharp/Portable/project.json +++ b/src/Features/CSharp/Portable/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "System.ValueTuple": "4.0.1-beta-24425-02" + "System.ValueTuple": "4.3.0" }, "frameworks": { "netstandard1.3": {