private async Task <IEnumerable <CompletionItem> > GetSnippetCompletionItemsAsync(Workspace workspace, SemanticModel semanticModel, int position, bool isPreProcessorContext, CancellationToken cancellationToken) { var service = _snippetInfoService ?? workspace.Services.GetLanguageServices(semanticModel.Language).GetService <ISnippetInfoService>(); if (service == null) { return(SpecializedCollections.EmptyEnumerable <CompletionItem>()); } var snippets = service.GetSnippetsIfAvailable(); if (isPreProcessorContext) { snippets = snippets.Where(snippet => snippet.Shortcut.StartsWith("#")); } var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); return(snippets.Select(snippet => new CompletionItem( this, displayText: isPreProcessorContext?snippet.Shortcut.Substring(1) : snippet.Shortcut, sortText: isPreProcessorContext ? snippet.Shortcut.Substring(1) : snippet.Shortcut, description: (snippet.Title + Environment.NewLine + snippet.Description).ToSymbolDisplayParts(), filterSpan: CompletionUtilities.GetTextChangeSpan(text, position), glyph: Glyph.Snippet, shouldFormatOnCommit: service.ShouldFormatSnippet(snippet)))); }
protected override async Task <IEnumerable <CompletionItem> > GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return(null); } var targetToken = tree.FindTokenOnLeftOfPosition(position, cancellationToken).GetPreviousTokenIfTouchingWord(position); if (targetToken.IsKind(SyntaxKind.AliasKeyword) && targetToken.Parent.IsKind(SyntaxKind.ExternAliasDirective)) { var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var aliases = compilation.ExternalReferences.SelectMany(r => r.Properties.Aliases).ToSet(); if (aliases.Any()) { var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var usedAliases = root.ChildNodes().OfType <ExternAliasDirectiveSyntax>().Where(e => !e.Identifier.IsMissing).Select(e => e.Identifier.ValueText); aliases.RemoveRange(usedAliases); aliases.Remove(MetadataReferenceProperties.GlobalAlias); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(await document.GetTextAsync(cancellationToken).ConfigureAwait(false), position); return(aliases.Select(e => new CompletionItem(this, e, textChangeSpan, glyph: Glyph.Namespace))); } } return(SpecializedCollections.EmptyEnumerable <CompletionItem>()); }
public override async Task ProduceCompletionListAsync(CompletionListContext context) { var document = context.Document; var position = context.Position; var cancellationToken = context.CancellationToken; var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return; } var targetToken = tree .FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position); if (targetToken.IsKind(SyntaxKind.AliasKeyword) && targetToken.Parent.IsKind(SyntaxKind.ExternAliasDirective)) { var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var aliases = compilation.ExternalReferences.SelectMany(r => r.Properties.Aliases).ToSet(); if (aliases.Any()) { var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var usedAliases = root.ChildNodes().OfType <ExternAliasDirectiveSyntax>() .Where(e => !e.Identifier.IsMissing) .Select(e => e.Identifier.ValueText); aliases.RemoveRange(usedAliases); aliases.Remove(MetadataReferenceProperties.GlobalAlias); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var filterSpan = CompletionUtilities.GetTextChangeSpan(text, position); foreach (var alias in aliases) { context.AddItem(new CompletionItem(this, alias, filterSpan, glyph: Glyph.Namespace)); } } } }
private async Task <IEnumerable <CompletionItem> > GetNameEqualsItemsAsync(Workspace workspace, SemanticModel semanticModel, int position, SyntaxToken token, AttributeSyntax attributeSyntax, ISet <string> existingNamedParameters, CancellationToken cancellationToken) { var attributeNamedParameters = GetAttributeNamedParameters(semanticModel, position, attributeSyntax, cancellationToken); var unspecifiedNamedParameters = attributeNamedParameters.Where(p => !existingNamedParameters.Contains(p.Name)); var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); return(from p in attributeNamedParameters where !existingNamedParameters.Contains(p.Name) select new CompletionItem( this, p.Name.ToIdentifierToken().ToString() + SpaceEqualsString, CompletionUtilities.GetTextChangeSpan(text, position), CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, token.SpanStart, p), p.GetGlyph(), sortText: p.Name, rules: ItemRules.Instance)); }
private async Task <IEnumerable <CompletionItem> > GetNameColonItemsAsync( Workspace workspace, SemanticModel semanticModel, int position, SyntaxToken token, AttributeSyntax attributeSyntax, ISet <string> existingNamedParameters, CancellationToken cancellationToken) { var parameterLists = GetParameterLists(semanticModel, position, attributeSyntax, cancellationToken); parameterLists = parameterLists.Where(pl => IsValid(pl, existingNamedParameters)); var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); return (from pl in parameterLists from p in pl where !existingNamedParameters.Contains(p.Name) select new CSharpCompletionItem( workspace, this, p.Name.ToIdentifierToken().ToString() + ColonString, CompletionUtilities.GetTextChangeSpan(text, position), CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, token.SpanStart, p), p.GetGlyph(), sortText: p.Name)); }
private TextSpan GetTextChangeSpan(SourceText text, int position) { return(CompletionUtilities.GetTextChangeSpan(text, position)); }
protected override TextSpan GetTextChangeSpan(SourceText text, int position) { return(CompletionUtilities.GetTextChangeSpan(text, position)); }
private async Task <CompletionItem> GetBuilderAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken)) { if (triggerInfo.TriggerReason == CompletionTriggerReason.TypeCharCommand) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); if (triggerInfo.IsDebugger) { // Aggressive Intellisense in the debugger: always show the builder return(new CompletionItem(this, "", CompletionUtilities.GetTextChangeSpan(text, position), isBuilder: true)); } var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); token = token.GetPreviousTokenIfTouchingWord(position); if (token.Kind() == SyntaxKind.None) { return(null); } var semanticModel = await document.GetCSharpSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false); var typeInferrer = document.GetLanguageService <ITypeInferenceService>(); if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken)) { return(new CompletionItem(this, CSharpFeaturesResources.LambdaExpression, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration.ToSymbolDisplayParts(), isBuilder: true)); } else if (IsAnonymousObjectCreation(token)) { return(new CompletionItem(this, CSharpFeaturesResources.MemberName, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation.ToSymbolDisplayParts(), isBuilder: true)); } else if (token.IsPreProcessorExpressionContext()) { return(new CompletionItem(this, "", CompletionUtilities.GetTextChangeSpan(text, position), isBuilder: true)); } else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken)) { return(new CompletionItem(this, CSharpFeaturesResources.ImplicitArrayCreation, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray.ToSymbolDisplayParts(), isBuilder: true)); } else { return(token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword) ? new CompletionItem(this, CSharpFeaturesResources.RangeVariable, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl.ToSymbolDisplayParts(), isBuilder: true) : null); } } return(null); }
protected override async Task <IEnumerable <CompletionItem> > GetItemsWorkerAsync( Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return(null); } var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); if (token.IsMandatoryNamedParameterPosition()) { return(null); } var typeInferenceService = document.GetLanguageService <ITypeInferenceService>(); var span = new TextSpan(position, 0); var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); var type = typeInferenceService.InferType(semanticModel, position, objectAsDefault: true, cancellationToken: cancellationToken); // If we have a Nullable<T>, unwrap it. if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { type = type.GetTypeArguments().FirstOrDefault(); if (type == null) { return(null); } } if (type.TypeKind != TypeKind.Enum) { type = GetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation); if (type == null) { return(null); } } if (!type.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)) { return(null); } // Does type have any aliases? ISymbol alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false); var displayService = document.GetLanguageService <ISymbolDisplayService>(); var displayText = alias != null ? alias.Name : displayService.ToMinimalDisplayString(semanticModel, position, type); var workspace = document.Project.Solution.Workspace; var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position); var item = new CSharpCompletionItem( workspace, this, displayText: displayText, filterSpan: textChangeSpan, descriptionFactory: CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, position, alias ?? type), glyph: (alias ?? type).GetGlyph(), preselect: true); return(SpecializedCollections.SingletonEnumerable(item)); }
private async Task <IEnumerable <CompletionItem> > GetCompletionsOffOfExplicitInterfaceAsync( Document document, SemanticModel semanticModel, int position, NameSyntax name, CancellationToken cancellationToken) { // Bind the interface name which is to the left of the dot var syntaxTree = semanticModel.SyntaxTree; var nameBinding = semanticModel.GetSymbolInfo(name, cancellationToken); var context = CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken); var symbol = nameBinding.Symbol as ITypeSymbol; if (symbol == null || symbol.TypeKind != TypeKind.Interface) { return(SpecializedCollections.EmptyEnumerable <CompletionItem>()); } var members = semanticModel.LookupSymbols( position: name.SpanStart, container: symbol) .Where(s => !s.IsStatic) .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation); // We're going to create a entry for each one, including the signature var completions = new List <CompletionItem>(); var signatureDisplayFormat = new SymbolDisplayFormat( genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, memberOptions: SymbolDisplayMemberOptions.IncludeParameters, parameterOptions: SymbolDisplayParameterOptions.IncludeName | SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes); var namePosition = name.SpanStart; var text = await context.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, context.Position); foreach (var member in members) { var displayString = member.ToMinimalDisplayString(semanticModel, namePosition, signatureDisplayFormat); var memberCopied = member; var insertionText = displayString; completions.Add(new SymbolCompletionItem( this, displayString, insertionText: insertionText, filterSpan: textChangeSpan, position: position, symbols: new List <ISymbol> { member }, context: context, rules: ItemRules.Instance)); } return(completions); }
protected override async Task <IEnumerable <CompletionItem> > GetItemsWorkerAsync( Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (syntaxTree.IsInNonUserCode(position, cancellationToken)) { return(null); } var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); token = token.GetPreviousTokenIfTouchingWord(position); if (token.Kind() != SyntaxKind.OpenParenToken && token.Kind() != SyntaxKind.OpenBracketToken && token.Kind() != SyntaxKind.CommaToken) { return(null); } var argumentList = token.Parent as BaseArgumentListSyntax; if (argumentList == null) { return(null); } var semanticModel = await document.GetSemanticModelForNodeAsync(argumentList, cancellationToken).ConfigureAwait(false); var parameterLists = GetParameterLists(semanticModel, position, argumentList.Parent, cancellationToken); if (parameterLists == null) { return(null); } var existingNamedParameters = GetExistingNamedParameters(argumentList, position); parameterLists = parameterLists.Where(pl => IsValid(pl, existingNamedParameters)); var unspecifiedParameters = parameterLists.SelectMany(pl => pl) .Where(p => !existingNamedParameters.Contains(p.Name)) .Distinct(this); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return(unspecifiedParameters.Select( p => { // Note: the filter text does not include the ':'. We want to ensure that if // the user types the name exactly (up to the colon) that it is selected as an // exact match. var workspace = document.Project.Solution.Workspace; var escaped = p.Name.ToIdentifierToken().ToString(); return new CompletionItem( this, escaped + ColonString, CompletionUtilities.GetTextChangeSpan(text, position), CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, token.SpanStart, p), p.GetGlyph(), sortText: p.Name, filterText: escaped, rules: ItemRules.Instance); })); }
public override async Task ProduceCompletionListAsync(CompletionListContext context) { try { var document = context.Document; var position = context.Position; var options = context.Options; var cancellationToken = context.CancellationToken; var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return; } var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); if (token.IsMandatoryNamedParameterPosition()) { return; } var typeInferenceService = document.GetLanguageService <ITypeInferenceService>(); var span = new TextSpan(position, 0); var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); var type = typeInferenceService.InferType(semanticModel, position, objectAsDefault: true, cancellationToken: cancellationToken); // If we have a Nullable<T>, unwrap it. if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { type = type.GetTypeArguments().FirstOrDefault(); if (type == null) { return; } } if (type.TypeKind != TypeKind.Enum) { type = GetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation); if (type == null) { return; } } if (!type.IsEditorBrowsable(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation)) { return; } // Does type have any aliases? ISymbol alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false); var displayService = document.GetLanguageService <ISymbolDisplayService>(); var displayText = alias != null ? alias.Name : displayService.ToMinimalDisplayString(semanticModel, position, type); var workspace = document.Project.Solution.Workspace; var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position); var item = new CompletionItem( this, displayText: displayText, filterSpan: textChangeSpan, descriptionFactory: CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, position, alias ?? type), glyph: (alias ?? type).GetGlyph(), preselect: true, rules: ItemRules.Instance); context.AddItem(item); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
protected override TextSpan GetTextChangeSpan(SourceText text, int position) { // We can just defer to the standard text span algorithm. return(CompletionUtilities.GetTextChangeSpan(text, position)); }
public override async Task ProduceCompletionListAsync(CompletionListContext context) { var document = context.Document; var position = context.Position; var cancellationToken = context.CancellationToken; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (syntaxTree.IsInNonUserCode(position, cancellationToken)) { return; } var token = syntaxTree .FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position); if (!token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.CommaToken)) { return; } var argumentList = token.Parent as BaseArgumentListSyntax; if (argumentList == null) { return; } var semanticModel = await document.GetSemanticModelForNodeAsync(argumentList, cancellationToken).ConfigureAwait(false); var parameterLists = GetParameterLists(semanticModel, position, argumentList.Parent, cancellationToken); if (parameterLists == null) { return; } var existingNamedParameters = GetExistingNamedParameters(argumentList, position); parameterLists = parameterLists.Where(pl => IsValid(pl, existingNamedParameters)); var unspecifiedParameters = parameterLists.SelectMany(pl => pl) .Where(p => !existingNamedParameters.Contains(p.Name)) .Distinct(this); if (!unspecifiedParameters.Any()) { return; } if (token.IsMandatoryNamedParameterPosition()) { context.MakeExclusive(true); } var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var filterSpan = CompletionUtilities.GetTextChangeSpan(text, position); var workspace = document.Project.Solution.Workspace; foreach (var parameter in unspecifiedParameters) { // Note: the filter text does not include the ':'. We want to ensure that if // the user types the name exactly (up to the colon) that it is selected as an // exact match. var escapedName = parameter.Name.ToIdentifierToken().ToString(); context.AddItem(new CompletionItem( this, escapedName + ColonString, filterSpan, CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, token.SpanStart, parameter), parameter.GetGlyph(), sortText: parameter.Name, filterText: escapedName, rules: ItemRules.Instance)); } }
public override async Task ProduceCompletionListAsync(CompletionListContext context) { var document = context.Document; var position = context.Position; var options = context.Options; var cancellationToken = context.CancellationToken; var span = new TextSpan(position, length: 0); var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); var syntaxTree = semanticModel.SyntaxTree; var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var semanticFacts = document.GetLanguageService <ISemanticFactsService>(); if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken) || semanticFacts.IsPreProcessorDirectiveContext(semanticModel, position, cancellationToken)) { return; } if (!syntaxTree.IsRightOfDotOrArrowOrColonColon(position, cancellationToken)) { return; } var node = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position) .Parent; if (node.Kind() != SyntaxKind.ExplicitInterfaceSpecifier) { return; } // Bind the interface name which is to the left of the dot var name = ((ExplicitInterfaceSpecifierSyntax)node).Name; var symbol = semanticModel.GetSymbolInfo(name, cancellationToken).Symbol as ITypeSymbol; if (symbol?.TypeKind != TypeKind.Interface) { return; } var members = semanticModel.LookupSymbols( position: name.SpanStart, container: symbol) .Where(s => !s.IsStatic) .FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); // We're going to create a entry for each one, including the signature var namePosition = name.SpanStart; var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position); foreach (var member in members) { var displayText = member.ToMinimalDisplayString(semanticModel, namePosition, s_signatureDisplayFormat); var insertionText = displayText; context.AddItem(new SymbolCompletionItem( this, displayText, insertionText: insertionText, filterSpan: textChangeSpan, position: position, symbols: new List <ISymbol> { member }, context: CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken), rules: ItemRules.Instance)); } }