Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More SyntaxContext sharing among CompletionProviders #61221

Merged
merged 5 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC
var position = completionContext.Position;
var document = completionContext.Document;
var cancellationToken = completionContext.CancellationToken;
var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);

if (!completionContext.CompletionOptions.ShowNameSuggestions)
{
return;
}

var context = CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);
var context = (CSharpSyntaxContext)await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);
if (context.IsInNonUserCode)
{
return;
Expand All @@ -69,7 +68,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC
// Do not show name suggestions for unbound "async" identifier.
// Most likely user is writing an async method, so name suggestion will just interfere him
if (context.TargetToken.IsKindOrHasMatchingText(SyntaxKind.AsyncKeyword) &&
semanticModel.GetSymbolInfo(context.TargetToken).GetAnySymbol() is null)
context.SemanticModel.GetSymbolInfo(context.TargetToken).GetAnySymbol() is null)
{
return;
}
Expand All @@ -85,7 +84,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC
AddNamesFromExistingOverloads(context, partialSemanticModel, result, cancellationToken);
}

var baseNames = GetBaseNames(semanticModel, nameInfo);
var baseNames = GetBaseNames(context.SemanticModel, nameInfo);
if (baseNames != default)
{
await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, result, cancellationToken).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
if (tree.IsInNonUserCode(position, cancellationToken))
return;

var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
var syntaxContext = CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);
var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);
var semanticModel = syntaxContext.SemanticModel;

if (syntaxContext.IsInTaskLikeTypeContext)
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
return;

var recommender = document.GetRequiredLanguageService<IRecommendationService>();

var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);
var semanticModel = syntaxContext.SemanticModel;

var options = context.CompletionOptions.ToRecommendationServiceOptions();
var recommendedSymbols = recommender.GetRecommendedSymbolsAtPosition(document, semanticModel, position, options, cancellationToken);
var recommendedSymbols = recommender.GetRecommendedSymbolsInContext(syntaxContext, options, cancellationToken);

AddUnnamedSymbols(context, position, semanticModel, recommendedSymbols.UnnamedSymbols, cancellationToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)

context.AddItems(await document.GetUnionItemsFromDocumentAndLinkedDocumentsAsync(
UnionCompletionItemComparer.Instance,
d => GetSnippetsForDocumentAsync(d, position, cancellationToken)).ConfigureAwait(false));
d => GetSnippetsForDocumentAsync(d, context, cancellationToken)).ConfigureAwait(false));
}
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, ErrorSeverity.General))
Expand All @@ -75,8 +75,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
}

private static async Task<ImmutableArray<CompletionItem>> GetSnippetsForDocumentAsync(
Document document, int position, CancellationToken cancellationToken)
Document document, CompletionContext completionContext, CancellationToken cancellationToken)
{
var position = completionContext.Position;
var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
var semanticFacts = document.GetRequiredLanguageService<ISemanticFactsService>();
Expand All @@ -93,8 +94,9 @@ private static async Task<ImmutableArray<CompletionItem>> GetSnippetsForDocument
return ImmutableArray<CompletionItem>.Empty;
}

var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
var context = CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);
var context = await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);
var semanticModel = context.SemanticModel;

if (context.IsInTaskLikeTypeContext)
return ImmutableArray<CompletionItem>.Empty;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
Expand All @@ -43,11 +44,10 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
try
{
var document = context.Document;
var position = context.Position;
var cancellationToken = context.CancellationToken;

var showSpeculativeT = await document.IsValidContextForDocumentOrLinkedDocumentsAsync(
(doc, ct) => ShouldShowSpeculativeTCompletionItemAsync(doc, position, ct),
(doc, ct) => ShouldShowSpeculativeTCompletionItemAsync(doc, context, ct),
cancellationToken).ConfigureAwait(false);

if (showSpeculativeT)
Expand All @@ -63,8 +63,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
}
}

private static async Task<bool> ShouldShowSpeculativeTCompletionItemAsync(Document document, int position, CancellationToken cancellationToken)
private static async Task<bool> ShouldShowSpeculativeTCompletionItemAsync(Document document, CompletionContext completionContext, CancellationToken cancellationToken)
{
var position = completionContext.Position;
var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
if (syntaxTree.IsInNonUserCode(position, cancellationToken) ||
syntaxTree.IsPreProcessorDirectiveContext(position, cancellationToken))
Expand All @@ -75,10 +76,8 @@ private static async Task<bool> ShouldShowSpeculativeTCompletionItemAsync(Docume
// We could be in the middle of a ref/generic/tuple type, instead of a simple T case.
// If we managed to walk out and get a different SpanStart, we treat it as a simple $$T case.

var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
var semanticModel = await document.ReuseExistingSpeculativeModelAsync(token.Parent, cancellationToken).ConfigureAwait(false);
var context = await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);

var context = CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);
if (context.IsInTaskLikeTypeContext)
return false;

Expand All @@ -87,7 +86,7 @@ private static async Task<bool> ShouldShowSpeculativeTCompletionItemAsync(Docume
{
var oldSpanStart = spanStart;

spanStart = WalkOutOfGenericType(syntaxTree, spanStart, semanticModel, cancellationToken);
spanStart = WalkOutOfGenericType(syntaxTree, spanStart, context.SemanticModel, cancellationToken);
spanStart = WalkOutOfTupleType(syntaxTree, spanStart, cancellationToken);
spanStart = WalkOutOfRefType(syntaxTree, spanStart, cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
Expand All @@ -41,12 +42,12 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC
try
{
var document = completionContext.Document;
var position = completionContext.Position;
var cancellationToken = completionContext.CancellationToken;

var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
var context = await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false) as CSharpSyntaxContext;
Contract.ThrowIfNull(context);

var context = CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);
var semanticModel = context.SemanticModel;

var index = GetElementIndex(context);
if (index == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Recommendations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
Expand Down Expand Up @@ -916,7 +917,9 @@ private async Task<SyntaxNode> GenerateInferredCallsiteExpressionAsync(
var recommender = document.GetRequiredLanguageService<IRecommendationService>();

var options = RecommendationServiceOptions.From(document.Project);
var recommendations = recommender.GetRecommendedSymbolsAtPosition(document, semanticModel, position, options, cancellationToken).NamedSymbols;

var context = document.GetRequiredLanguageService<ISyntaxContextService>().CreateContext(document, semanticModel, position, cancellationToken);
var recommendations = recommender.GetRecommendedSymbolsInContext(context, options, cancellationToken).NamedSymbols;

var sourceSymbols = recommendations.Where(r => r.IsNonImplicitAndFromSource());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ public sealed override async Task ProvideCompletionsAsync(CompletionContext cont
if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken))
return;

var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
var syntaxContext = document.GetRequiredLanguageService<ISyntaxContextService>().CreateContext(document, semanticModel, position, cancellationToken);
var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);

var isAwaitKeywordContext = IsAwaitKeywordContext(syntaxContext);
var dotAwaitContext = GetDotAwaitKeywordContext(syntaxContext, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,14 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
{
context.AddItems(await context.Document.GetUnionItemsFromDocumentAndLinkedDocumentsAsync(
s_comparer,
d => RecommendCompletionItemsAsync(d, context.Position, cancellationToken)).ConfigureAwait(false));
d => RecommendCompletionItemsAsync(d, context, cancellationToken)).ConfigureAwait(false));
}
}

private async Task<ImmutableArray<CompletionItem>> RecommendCompletionItemsAsync(Document document, int position, CancellationToken cancellationToken)
private async Task<ImmutableArray<CompletionItem>> RecommendCompletionItemsAsync(Document document, CompletionContext context, CancellationToken cancellationToken)
{
var syntaxContextService = document.GetRequiredLanguageService<ISyntaxContextService>();
var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
var syntaxContext = (TContext)syntaxContextService.CreateContext(document, semanticModel, position, cancellationToken);
var position = context.Position;
var syntaxContext = (TContext)await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false);
var keywords = await RecommendKeywordsAsync(document, position, syntaxContext, cancellationToken).ConfigureAwait(false);
return keywords.SelectAsArray(k => CreateItem(k, syntaxContext, cancellationToken));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ public sealed override async Task ProvideCompletionsAsync(CompletionContext cont
var cancellationToken = context.CancellationToken;
var originatingDocument = context.Document;
var position = context.Position;

var semanticModel = await originatingDocument.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
var service = originatingDocument.GetRequiredLanguageService<ISyntaxContextService>();
var solution = originatingDocument.Project.Solution;
var syntaxContext = service.CreateContext(originatingDocument, semanticModel, position, cancellationToken);
var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(originatingDocument, cancellationToken).ConfigureAwait(false);
if (!syntaxContext.IsPreProcessorExpressionContext)
return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal abstract class AbstractRecommendationServiceBasedCompletionProvider<TSy
{
var recommendationOptions = options.ToRecommendationServiceOptions();
var recommender = context.GetRequiredLanguageService<IRecommendationService>();
var recommendedSymbols = recommender.GetRecommendedSymbolsAtPosition(context.Document, context.SemanticModel, position, recommendationOptions, cancellationToken);
var recommendedSymbols = recommender.GetRecommendedSymbolsInContext(context, recommendationOptions, cancellationToken);

if (context.IsInTaskLikeTypeContext)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ public Task<SyntaxContext> GetSyntaxContextAsync(Document document, Cancellation
if (_document.Id != document.Id && !_lazyRelatedDocumentIds.Value.Contains(document.Id))
throw new ArgumentException("Don't support getting SyntaxContext for document unrelated to the original document");

lazyContext = GetLazySyntaxContextWithSpeculativeModel(document);
lazyContext = GetLazySyntaxContextWithSpeculativeModel(document, this);
}

return lazyContext.GetValueAsync(cancellationToken);

// Extract a local function to avoid creating a closure for code path of cache hit.
AsyncLazy<SyntaxContext> GetLazySyntaxContextWithSpeculativeModel(Document document)
static AsyncLazy<SyntaxContext> GetLazySyntaxContextWithSpeculativeModel(Document document, SharedSyntaxContextsWithSpeculativeModel self)
{
return _cache.GetOrAdd(document, d => AsyncLazy.Create(cancellationToken
=> CompletionHelper.CreateSyntaxContextWithExistingSpeculativeModelAsync(d, _position, cancellationToken), cacheResult: true));
return self._cache.GetOrAdd(document, d => AsyncLazy.Create(cancellationToken
=> CompletionHelper.CreateSyntaxContextWithExistingSpeculativeModelAsync(d, self._position, cancellationToken), cacheResult: true));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets
Return
End If

Dim semanticModel = Await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(False)
Dim syntaxContext = VisualBasicSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken)
Dim syntaxContext = Await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(False)
If syntaxContext.IsInTaskLikeTypeContext Then
Return
End If
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ public CSharpRecommendationService()
{
}

protected override CSharpSyntaxContext CreateContext(Document document, SemanticModel semanticModel, int position, CancellationToken cancellationToken)
=> CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken);

protected override AbstractRecommendationServiceRunner CreateRunner(CSharpSyntaxContext context, bool filterOutOfScopeLocals, CancellationToken cancellationToken)
=> new CSharpRecommendationServiceRunner(context, filterOutOfScopeLocals, cancellationToken);
}
Expand Down
Loading