public override async Task ProvideCompletionsAsync(CompletionContext completionContext) { try { var document = completionContext.Document; var cancellationToken = completionContext.CancellationToken; var context = await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false) as CSharpSyntaxContext; Contract.ThrowIfNull(context); var semanticModel = context.SemanticModel; var index = GetElementIndex(context); if (index == null) { return; } var typeInferrer = document.GetRequiredLanguageService <ITypeInferenceService>(); var inferredTypes = typeInferrer.InferTypes(semanticModel, context.TargetToken.Parent !.SpanStart, cancellationToken) .Where(t => t.IsTupleType) .Cast <INamedTypeSymbol>() .ToImmutableArray(); AddItems(inferredTypes, index.Value, completionContext, context.TargetToken.Parent.SpanStart); } catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, ErrorSeverity.General)) { // nop } }
public override async Task ProvideCompletionsAsync(CompletionContext completionContext) { try { var position = completionContext.Position; var document = completionContext.Document; var cancellationToken = completionContext.CancellationToken; if (!completionContext.CompletionOptions.ShowNameSuggestions) { return; } var context = (CSharpSyntaxContext)await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); if (context.IsInNonUserCode) { return; } // 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) && context.SemanticModel.GetSymbolInfo(context.TargetToken).GetAnySymbol() is null) { return; } var nameInfo = await NameDeclarationInfo.GetDeclarationInfoAsync(document, position, cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder <(string name, SymbolKind kind)> .GetInstance(out var result); // Suggest names from existing overloads. if (nameInfo.PossibleSymbolKinds.Any(static k => k.SymbolKind == SymbolKind.Parameter))
public override async Task ProvideCompletionsAsync(CompletionContext context) { try { var document = context.Document; var position = context.Position; var cancellationToken = context.CancellationToken; var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return; } var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); var semanticModel = syntaxContext.SemanticModel; if (syntaxContext.IsInTaskLikeTypeContext) { return; } var token = syntaxContext.TargetToken; if (token.IsMandatoryNamedParameterPosition()) { return; } // Don't show up within member access // This previously worked because the type inferrer didn't work // in member access expressions. // The regular SymbolCompletionProvider will handle completion after . if (token.IsKind(SyntaxKind.DotToken)) { return; } var typeInferenceService = document.GetLanguageService <ITypeInferenceService>(); Contract.ThrowIfNull(typeInferenceService, nameof(typeInferenceService)); var types = typeInferenceService.InferTypes(semanticModel, position, cancellationToken); if (types.Length == 0) { types = ImmutableArray.Create <ITypeSymbol>(semanticModel.Compilation.ObjectType); } foreach (var type in types) { await HandleSingleTypeAsync(context, semanticModel, token, type, cancellationToken).ConfigureAwait(false); } } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, ErrorSeverity.General)) { throw ExceptionUtilities.Unreachable; } }
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)) { return(false); } // 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 context = await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); if (context.IsTaskLikeTypeContext) { return(false); } var spanStart = position; while (true) { var oldSpanStart = spanStart; spanStart = WalkOutOfGenericType(syntaxTree, spanStart, context.SemanticModel, cancellationToken); spanStart = WalkOutOfTupleType(syntaxTree, spanStart, cancellationToken); spanStart = WalkOutOfRefType(syntaxTree, spanStart, cancellationToken); if (spanStart == oldSpanStart) { break; } } return(IsStartOfSpeculativeTContext(syntaxTree, spanStart, cancellationToken)); }
public sealed override async Task ProvideCompletionsAsync(CompletionContext context) { var cancellationToken = context.CancellationToken; var originatingDocument = context.Document; var position = context.Position; var solution = originatingDocument.Project.Solution; var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(originatingDocument, cancellationToken).ConfigureAwait(false); if (!syntaxContext.IsPreProcessorExpressionContext) { return; } // Walk all the projects this document is linked in so that we get the full set of preprocessor symbols // defined across all of them. var syntaxFacts = originatingDocument.GetRequiredLanguageService <ISyntaxFactsService>(); var preprocessorNames = new HashSet <string>(syntaxFacts.StringComparer); foreach (var documentId in solution.GetRelatedDocumentIds(originatingDocument.Id)) { var document = solution.GetRequiredDocument(documentId); var currentSyntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); preprocessorNames.AddRange(currentSyntaxTree.Options.PreprocessorSymbolNames); } // Keep all the preprocessor symbol names together. We don't want to intermingle them with any keywords we // include (like `true/false`) foreach (var name in preprocessorNames.OrderBy(a => a)) { context.AddItem(CommonCompletionItem.Create( name, displayTextSuffix: "", CompletionItemRules.Default, glyph: Glyph.Keyword, sortText: "_0_" + name)); } }
private static async Task <ImmutableArray <CompletionItem> > GetSnippetsForDocumentAsync( 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>(); var root = syntaxTree.GetRoot(cancellationToken); var leftToken = root.FindTokenOnLeftOfPosition(position, includeDirectives: true); var targetToken = leftToken.GetPreviousTokenIfTouchingWord(position); if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken) || syntaxTree.IsRightOfDotOrArrowOrColonColon(position, targetToken, cancellationToken) || syntaxFacts.GetContainingTypeDeclaration(root, position) is EnumDeclarationSyntax || syntaxTree.IsPossibleTupleContext(leftToken, position)) { return(ImmutableArray <CompletionItem> .Empty); } var context = await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); var semanticModel = context.SemanticModel; if (context.IsInTaskLikeTypeContext) { return(ImmutableArray <CompletionItem> .Empty); } if (syntaxFacts.IsPreProcessorDirectiveContext(syntaxTree, position, cancellationToken)) { var directive = leftToken.GetAncestor <DirectiveTriviaSyntax>(); Contract.ThrowIfNull(directive); if (!directive.DirectiveNameToken.IsKind( SyntaxKind.IfKeyword, SyntaxKind.RegionKeyword, SyntaxKind.ElseKeyword, SyntaxKind.ElifKeyword, SyntaxKind.ErrorKeyword, SyntaxKind.LineKeyword, SyntaxKind.PragmaKeyword, SyntaxKind.EndIfKeyword, SyntaxKind.UndefKeyword, SyntaxKind.EndRegionKeyword, SyntaxKind.WarningKeyword)) { return(GetSnippetCompletionItems( document.Project.Solution.Workspace, semanticModel, isPreProcessorContext: true)); } } else { if (semanticFacts.IsGlobalStatementContext(semanticModel, position, cancellationToken) || semanticFacts.IsExpressionContext(semanticModel, position, cancellationToken) || semanticFacts.IsStatementContext(semanticModel, position, cancellationToken) || semanticFacts.IsTypeContext(semanticModel, position, cancellationToken) || semanticFacts.IsTypeDeclarationContext(semanticModel, position, cancellationToken) || semanticFacts.IsNamespaceContext(semanticModel, position, cancellationToken) || semanticFacts.IsNamespaceDeclarationNameContext(semanticModel, position, cancellationToken) || semanticFacts.IsMemberDeclarationContext(semanticModel, position, cancellationToken) || semanticFacts.IsLabelContext(semanticModel, position, cancellationToken)) { return(GetSnippetCompletionItems( document.Project.Solution.Workspace, semanticModel, isPreProcessorContext: false)); } } return(ImmutableArray <CompletionItem> .Empty); }
public override async Task ProvideCompletionsAsync(CompletionContext completionContext) { try { var position = completionContext.Position; var document = completionContext.Document; var cancellationToken = completionContext.CancellationToken; if (!completionContext.CompletionOptions.ShowNameSuggestions) { return; } var context = (CSharpSyntaxContext)await completionContext.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); if (context.IsInNonUserCode) { return; } // 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) && context.SemanticModel.GetSymbolInfo(context.TargetToken).GetAnySymbol() is null) { return; } var nameInfo = await NameDeclarationInfo.GetDeclarationInfoAsync(document, position, cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder <(string name, SymbolKind kind)> .GetInstance(out var result); // Suggest names from existing overloads. if (nameInfo.PossibleSymbolKinds.Any(k => k.SymbolKind == SymbolKind.Parameter)) { var(_, partialSemanticModel) = await document.GetPartialSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (partialSemanticModel is not null) { AddNamesFromExistingOverloads(context, partialSemanticModel, result, cancellationToken); } } var baseNames = GetBaseNames(context.SemanticModel, nameInfo); if (baseNames != default) { var namingStyleOptions = await document.GetNamingStylePreferencesAsync(completionContext.CompletionOptions.NamingStyleFallbackOptions, cancellationToken).ConfigureAwait(false); GetRecommendedNames(baseNames, nameInfo, context, result, namingStyleOptions, cancellationToken); } var recommendedNames = result.ToImmutable(); if (recommendedNames.IsEmpty) { return; } var sortValue = 0; foreach (var(name, kind) in recommendedNames) { // We've produced items in the desired order, add a sort text to each item to prevent alphabetization completionContext.AddItem(CreateCompletionItem(name, GetGlyph(kind, nameInfo.DeclaredAccessibility), sortValue.ToString("D8"))); sortValue++; } completionContext.SuggestionModeItem = CommonCompletionItem.Create( CSharpFeaturesResources.Name, displayTextSuffix: "", CompletionItemRules.Default); } catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, ErrorSeverity.General)) { // nop } }
public sealed override async Task ProvideCompletionsAsync(CompletionContext context) { var document = context.Document; var position = context.Position; var cancellationToken = context.CancellationToken; var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken)) { return; } var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); var isAwaitKeywordContext = IsAwaitKeywordContext(syntaxContext); var dotAwaitContext = GetDotAwaitKeywordContext(syntaxContext, cancellationToken); if (!isAwaitKeywordContext && dotAwaitContext == DotAwaitContext.None) { return; } var token = syntaxContext.TargetToken; var declaration = GetAsyncSupportingDeclaration(token); var properties = ImmutableDictionary <string, string> .Empty .Add(AwaitCompletionTargetTokenPosition, token.SpanStart.ToString()); var makeContainerAsync = declaration is not null && !SyntaxGenerator.GetGenerator(document).GetModifiers(declaration).IsAsync; if (makeContainerAsync) { properties = properties.Add(MakeContainerAsync, string.Empty); } if (isAwaitKeywordContext) { properties = properties.Add(AddAwaitAtCurrentPosition, string.Empty); context.AddItem(CreateCompletionItem( properties, _awaitKeyword, _awaitKeyword, FeaturesResources.Asynchronously_waits_for_the_task_to_finish, isComplexTextEdit: makeContainerAsync)); } else { Contract.ThrowIfTrue(dotAwaitContext == DotAwaitContext.None); // add the `await` option that will remove the dot and add `await` to the start of the expression. context.AddItem(CreateCompletionItem( properties, _awaitKeyword, _awaitKeyword, FeaturesResources.Await_the_preceding_expression, isComplexTextEdit: true)); if (dotAwaitContext == DotAwaitContext.AwaitAndConfigureAwait) { // add the `awaitf` option to do the same, but also add .ConfigureAwait(false); properties = properties.Add(AppendConfigureAwait, string.Empty); context.AddItem(CreateCompletionItem( properties, _awaitfDisplayText, _awaitfFilterText, string.Format(FeaturesResources.Await_the_preceding_expression_and_add_ConfigureAwait_0, _falseKeyword), isComplexTextEdit: true)); } } return;