Ejemplo n.º 1
0
        private static void AddTypes(HashSet <CompletionItem> completionItems, int contextPosition, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            // We have to find the set of types that meet the criteria listed in
            // https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/function-pointers.md#mapping-the-calling_convention_specifier-to-a-callkind
            // We skip the check of an type being in the core assembly since that's not really necessary for our work.
            var compilerServicesNamespace = semanticModel.Compilation.GlobalNamespace.GetQualifiedNamespace("System.Runtime.CompilerServices");

            if (compilerServicesNamespace == null)
            {
                return;
            }

            foreach (var type in compilerServicesNamespace.GetTypeMembers())
            {
                cancellationToken.ThrowIfCancellationRequested();

                const string CallConvPrefix = "CallConv";

                if (type.DeclaredAccessibility == Accessibility.Public && type.Name.StartsWith(CallConvPrefix))
                {
                    var displayName = type.Name.Substring(CallConvPrefix.Length);
                    completionItems.Add(
                        SymbolCompletionItem.CreateWithSymbolId(
                            displayName,
                            ImmutableArray.Create(type),
                            rules: CompletionItemRules.Default,
                            contextPosition));
                }
            }
        }
Ejemplo n.º 2
0
 public static CompletionItem CreateSymbolCompletionItem(
     string displayText,
     IReadOnlyList <ISymbol> symbols,
     CompletionItemRules rules,
     int contextPosition,
     string?sortText      = null,
     string?insertionText = null,
     string?filterText    = null,
     SupportedPlatformData?supportedPlatforms        = null,
     ImmutableDictionary <string, string>?properties = null,
     ImmutableArray <string> tags = default
     ) =>
 SymbolCompletionItem.CreateWithSymbolId(
     displayText,
     displayTextSuffix: null,
     symbols,
     rules,
     contextPosition,
     sortText,
     insertionText,
     filterText,
     displayTextPrefix: null,
     inlineDescription: null,
     glyph: null,
     supportedPlatforms,
     properties,
     tags
     );
Ejemplo n.º 3
0
        private static void AddItems(
            ImmutableArray <INamedTypeSymbol> inferredTypes,
            int index,
            CompletionContext context,
            int spanStart
            )
        {
            foreach (var type in inferredTypes)
            {
                if (index >= type.TupleElements.Length)
                {
                    return;
                }

                // 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 field = type.TupleElements[index];

                context.AddItem(
                    SymbolCompletionItem.CreateWithSymbolId(
                        displayText: field.Name,
                        displayTextSuffix: ColonString,
                        symbols: ImmutableArray.Create(field),
                        rules: CompletionItemRules.Default,
                        contextPosition: spanStart,
                        filterText: field.Name
                        )
                    );
            }
        }
Ejemplo n.º 4
0
        private static async Task <IEnumerable <CompletionItem> > GetNameColonItemsAsync(
            CompletionContext context,
            SemanticModel semanticModel,
            SyntaxToken token,
            AttributeSyntax attributeSyntax,
            ISet <string> existingNamedParameters
            )
        {
            var parameterLists = GetParameterLists(
                semanticModel,
                context.Position,
                attributeSyntax,
                context.CancellationToken
                );

            parameterLists = parameterLists.Where(pl => IsValid(pl, existingNamedParameters));

            var text = await semanticModel.SyntaxTree
                       .GetTextAsync(context.CancellationToken)
                       .ConfigureAwait(false);

            return(from pl in parameterLists
                   from p in pl
                   where !existingNamedParameters.Contains(p.Name)
                   select SymbolCompletionItem.CreateWithSymbolId(
                       displayText : p.Name.ToIdentifierToken().ToString(),
                       displayTextSuffix : ColonString,
                       insertionText : null,
                       symbols : ImmutableArray.Create(p),
                       contextPosition : token.SpanStart,
                       sortText : p.Name,
                       rules : CompletionItemRules.Default
                       ));
        }
        private void AddConversion(
            CompletionContext context,
            SemanticModel semanticModel,
            int position,
            IMethodSymbol conversion
            )
        {
            var(symbols, properties) = GetConversionSymbolsAndProperties(context, conversion);

            var targetTypeName = conversion.ReturnType.ToMinimalDisplayString(
                semanticModel,
                position
                );

            context.AddItem(
                SymbolCompletionItem.CreateWithSymbolId(
                    displayTextPrefix: "(",
                    displayText: targetTypeName,
                    displayTextSuffix: ")",
                    filterText: targetTypeName,
                    sortText: SortText(ConversionSortingGroupIndex, targetTypeName),
                    glyph: Glyph.Operator,
                    symbols: symbols,
                    rules: CompletionItemRules.Default,
                    contextPosition: position,
                    properties: properties
                    )
                );
        }
Ejemplo n.º 6
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var document          = context.Document;
            var position          = context.Position;
            var cancellationToken = context.CancellationToken;
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            // For `is { Property.Property2.$$`, we get:
            // - the property pattern clause `{ ... }` and
            // - the member access before the last dot `Property.Property2` (or null)
            var(propertyPatternClause, memberAccess) = TryGetPropertyPatternClause(tree, position, cancellationToken);
            if (propertyPatternClause is null)
            {
                return;
            }

            var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);

            var propertyPatternType = semanticModel.GetTypeInfo((PatternSyntax)propertyPatternClause.Parent, cancellationToken).ConvertedType;
            // For simple property patterns, the type we want is the "input type" of the property pattern, ie the type of `c` in `c is { $$ }`.
            // For extended property patterns, we get the type by following the chain of members that we have so far, ie
            // the type of `c.Property` for `c is { Property.$$ }` and the type of `c.Property1.Property2` for `c is { Property1.Property2.$$ }`.
            var type = GetMemberAccessType(propertyPatternType, memberAccess, document, semanticModel, position);

            if (type is null)
            {
                return;
            }

            // Find the members that can be tested.
            var members = GetCandidatePropertiesAndFields(document, semanticModel, position, type);

            members = members.WhereAsArray(m => m.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation));

            if (memberAccess is null)
            {
                // Filter out those members that have already been typed as simple (not extended) properties
                var alreadyTestedMembers = new HashSet <string>(propertyPatternClause.Subpatterns.Select(
                                                                    p => p.NameColon?.Name.Identifier.ValueText).Where(s => !string.IsNullOrEmpty(s)));

                members = members.WhereAsArray(m => !alreadyTestedMembers.Contains(m.Name));
            }

            foreach (var member in members)
            {
                const string ColonString = ":";
                context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                    displayText: member.Name.EscapeIdentifier(),
                                    displayTextSuffix: ColonString,
                                    insertionText: null,
                                    symbols: ImmutableArray.Create(member),
                                    contextPosition: context.Position,
                                    rules: s_rules));
            }

            return;
Ejemplo n.º 7
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var document          = context.Document;
            var position          = context.Position;
            var cancellationToken = context.CancellationToken;
            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var token = TryGetOpenBraceOrCommaInPropertyPatternClause(tree, position, cancellationToken);

            if (token == default || !(token.Parent.Parent is PatternSyntax))
            {
                return;
            }

            var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, length : 0), cancellationToken).ConfigureAwait(false);

            var pattern = (PatternSyntax)token.Parent.Parent;
            var type    = semanticModel.GetTypeInfo(pattern, cancellationToken).ConvertedType;

            if (type == null)
            {
                return;
            }

            // Find the members that can be tested.
            IEnumerable <ISymbol> members = semanticModel.LookupSymbols(position, type);

            members = members.Where(m => m.CanBeReferencedByName &&
                                    IsFieldOrReadableProperty(m) &&
                                    !m.IsImplicitlyDeclared &&
                                    !m.IsStatic);

            // Filter out those members that have already been typed
            var propertyPatternClause = (PropertyPatternClauseSyntax)token.Parent;

            // List the members that are already tested in this property sub-pattern
            var alreadyTestedMembers = new HashSet <string>(propertyPatternClause.Subpatterns.Select(
                                                                p => p.NameColon?.Name.Identifier.ValueText).Where(s => !string.IsNullOrEmpty(s)));

            var untestedMembers = members.Where(m => !alreadyTestedMembers.Contains(m.Name) &&
                                                m.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation));

            foreach (var untestedMember in untestedMembers)
            {
                const string ColonString = ":";
                context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                    displayText: untestedMember.Name.EscapeIdentifier(),
                                    displayTextSuffix: ColonString,
                                    insertionText: null,
                                    symbols: ImmutableArray.Create(untestedMember),
                                    contextPosition: token.GetLocation().SourceSpan.Start,
                                    rules: s_rules));
            }
        }
Ejemplo n.º 8
0
        void Analyze(CompletionContext context, SemanticModel model, SyntaxNode node, ISymbol within, ParameterListSyntax parameterList, ISymbol symbol, HashSet <string> addedSymbols, CancellationToken cancellationToken)
        {
            var type = CheckParameterList(model, parameterList, symbol, cancellationToken);

            if (type == null)
            {
                return;
            }
            var startType = type;

            var typeString = CSharpAmbience.SafeMinimalDisplayString(type, model, context.CompletionListSpan.Start, Ambience.LabelFormat);
            var pDict      = ImmutableDictionary <string, string> .Empty;

            if (typeString != null)
            {
                pDict = pDict.Add("CastTypeString", typeString);
            }
            pDict = pDict.Add("DescriptionMarkup", "- <span foreground=\"darkgray\" size='small'>" + GettextCatalog.GetString("Cast to '{0}'", type.Name) + "</span>");
            pDict = pDict.Add("NodeString", node.ToString());

            while (type.SpecialType != SpecialType.System_Object)
            {
                foreach (var member in type.GetMembers())
                {
                    if (member.IsImplicitlyDeclared || member.IsStatic)
                    {
                        continue;
                    }
                    if (member.IsOrdinaryMethod() || member.Kind == SymbolKind.Field || member.Kind == SymbolKind.Property)
                    {
                        if (member.IsAccessibleWithin(within))
                        {
                            var completionData = SymbolCompletionItem.CreateWithSymbolId(
                                member.Name,
                                new [] { member },
                                CompletionItemRules.Default,
                                context.Position,
                                properties: pDict
                                );

                            if (addedSymbols.Contains(completionData.DisplayText))
                            {
                                continue;
                            }
                            addedSymbols.Add(completionData.DisplayText);
                            context.AddItem(completionData);
                        }
                    }
                }

                type = type.BaseType;
            }
        }
        private void AddIndexers(CompletionContext context, ImmutableArray <ISymbol> indexers)
        {
            if (indexers.Length == 0)
            {
                return;
            }

            context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                displayText: "this",
                                displayTextSuffix: "[]",
                                filterText: "this",
                                sortText: "this",
                                symbols: indexers,
                                rules: CompletionItemRules.Default,
                                contextPosition: context.Position,
                                properties: IndexerProperties));
        }
        private async Task <ImmutableArray <CompletionItem> > GetNameEqualsItemsAsync(
            CompletionContext context, SemanticModel semanticModel,
            SyntaxToken token, AttributeSyntax attributeSyntax, ISet <string> existingNamedParameters)
        {
            var attributeNamedParameters   = GetAttributeNamedParameters(semanticModel, context.Position, attributeSyntax, context.CancellationToken);
            var unspecifiedNamedParameters = attributeNamedParameters.Where(p => !existingNamedParameters.Contains(p.Name));

            var text = await semanticModel.SyntaxTree.GetTextAsync(context.CancellationToken).ConfigureAwait(false);

            var q = from p in attributeNamedParameters
                    where !existingNamedParameters.Contains(p.Name)
                    select SymbolCompletionItem.CreateWithSymbolId(
                displayText : p.Name.ToIdentifierToken().ToString() + SpaceEqualsString,
                insertionText : null,
                symbols : ImmutableArray.Create(p),
                contextPosition : token.SpanStart,
                sortText : p.Name,
                rules : _spaceItemFilterRule);

            return(q.ToImmutableArray());
        }
        public override async Task ProvideCompletionsAsync(CompletionContext 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;
            }

            // Consider refining this logic to mandate completion with an argument name, if preceded by an out-of-position name
            // See https://github.com/dotnet/roslyn/issues/20657
            var languageVersion = ((CSharpParseOptions)document.Project.ParseOptions).LanguageVersion;

            if (languageVersion < LanguageVersion.CSharp7_2 && token.IsMandatoryNamedParameterPosition())
            {
                context.IsExclusive = true;
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            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(SymbolCompletionItem.CreateWithSymbolId(
                                    displayText: escapedName + ColonString,
                                    symbols: ImmutableArray.Create(parameter),
                                    rules: s_rules.WithMatchPriority(SymbolMatchPriority.PreferNamedArgument),
                                    contextPosition: token.SpanStart,
                                    filterText: escapedName));
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            try
            {
                var document          = context.Document;
                var position          = context.Position;
                var cancellationToken = context.CancellationToken;

                var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                var syntaxFacts   = document.GetRequiredLanguageService <ISyntaxFactsService>();
                var semanticFacts = document.GetRequiredLanguageService <ISemanticFactsService>();

                if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken) ||
                    syntaxFacts.IsPreProcessorDirectiveContext(syntaxTree, position, cancellationToken))
                {
                    return;
                }

                var targetToken = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken)
                                  .GetPreviousTokenIfTouchingWord(position);

                if (!syntaxTree.IsRightOfDotOrArrowOrColonColon(position, targetToken, cancellationToken))
                {
                    return;
                }

                var node = targetToken.Parent;
                if (!node.IsKind(SyntaxKind.ExplicitInterfaceSpecifier, out ExplicitInterfaceSpecifierSyntax? specifierNode))
                {
                    return;
                }

                // Bind the interface name which is to the left of the dot
                var name = specifierNode.Name;

                var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);

                var symbol = semanticModel.GetSymbolInfo(name, cancellationToken).Symbol as ITypeSymbol;
                if (symbol?.TypeKind != TypeKind.Interface)
                {
                    return;
                }

                // We're going to create a entry for each one, including the signature
                var namePosition = name.SpanStart;
                foreach (var member in symbol.GetMembers())
                {
                    if (!member.IsAbstract && !member.IsVirtual)
                    {
                        continue;
                    }

                    if (member.IsAccessor() ||
                        member.Kind == SymbolKind.NamedType ||
                        !semanticModel.IsAccessible(node.SpanStart, member))
                    {
                        continue;
                    }

                    var memberString = member.ToMinimalDisplayString(semanticModel, namePosition, s_signatureDisplayFormat);

                    // Split the member string into two parts (generally the name, and the signature portion). We want
                    // the split so that other features (like spell-checking), only look at the name portion.
                    var(displayText, displayTextSuffix) = SplitMemberName(memberString);

                    context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                        displayText,
                                        displayTextSuffix,
                                        insertionText: memberString,
                                        symbols: ImmutableArray.Create <ISymbol>(member),
                                        contextPosition: position,
                                        rules: CompletionItemRules.Default));
                }
            }
            catch (Exception e) when(FatalError.ReportWithoutCrashUnlessCanceled(e))
            {
                // nop
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext 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)
                          .WhereAsArray(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);

            foreach (var member in members)
            {
                var displayText = member.ToMinimalDisplayString(
                    semanticModel, namePosition, s_signatureDisplayFormat);
                var insertionText = displayText;

                var item = SymbolCompletionItem.CreateWithSymbolId(
                    displayText,
                    insertionText: insertionText,
                    symbol: member,
                    contextPosition: position,
                    rules: CompletionItemRules.Default);
                item = item.AddProperty(InsertionTextOnOpenParen, member.Name);

                context.AddItem(item);
            }
        }
        private static async Task HandleSingleTypeAsync(CompletionContext context, SemanticModel semanticModel, SyntaxToken token, ITypeSymbol type, CancellationToken cancellationToken)
        {
            // If we have a Nullable<T>, unwrap it.
            if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
            {
                var typeArg = type.GetTypeArguments().FirstOrDefault();
                if (typeArg == null)
                    return;

                type = typeArg;
            }

            var position = context.Position;
            if (type.TypeKind != TypeKind.Enum)
            {
                var enumType = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ??
                               TryGetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation);

                if (enumType == null)
                    return;

                type = enumType;
            }

            var options = context.Options;
            var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language);
            if (!type.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
                return;

            // Does type have any aliases?
            var alias = await type.FindApplicableAliasAsync(position, semanticModel, cancellationToken).ConfigureAwait(false);

            var displayText = alias != null
                ? alias.Name
                : type.ToMinimalDisplayString(semanticModel, position);

            // Add the enum itself.
            var symbol = alias ?? type;
            var sortText = symbol.Name;

            context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                displayText,
                displayTextSuffix: "",
                symbols: ImmutableArray.Create(symbol),
                rules: s_enumTypeRules,
                contextPosition: position,
                sortText: sortText));

            // And now all the accessible members of the enum.
            if (type.TypeKind == TypeKind.Enum)
            {
                // We'll want to build a list of the actual enum members and all accessible instances of that enum, too
                var index = 0;

                var fields = type.GetMembers().OfType<IFieldSymbol>().Where(f => f.IsConst).Where(f => f.HasConstantValue);
                foreach (var field in fields.OrderBy(f => IntegerUtilities.ToInt64(f.ConstantValue)))
                {
                    index++;
                    if (!field.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
                        continue;

                    var memberDisplayName = $"{displayText}.{field.Name}";
                    context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                        displayText: memberDisplayName,
                        displayTextSuffix: "",
                        symbols: ImmutableArray.Create<ISymbol>(field),
                        rules: CompletionItemRules.Default,
                        contextPosition: position,
                        sortText: $"{sortText}_{index:0000}",
                        filterText: memberDisplayName));
                }
            }
        }
Ejemplo n.º 15
0
        public override async Task ProvideCompletionsAsync(CompletionContext 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.IsExclusive = true;
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            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(SymbolCompletionItem.CreateWithSymbolId(
                                    displayText: escapedName + ColonString,
                                    insertionText: null,
                                    symbol: parameter,
                                    contextPosition: token.SpanStart,
                                    filterText: escapedName,
                                    rules: s_rules,
                                    matchPriority: SymbolMatchPriority.PreferNamedArgument));
            }
        }
Ejemplo n.º 16
0
        public override async Task ProvideCompletionsAsync(CompletionContext 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)
                            .GetPreviousTokenIfTouchingWord(position);

                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 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 = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ??
                           TryGetCompletionListType(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?
                var 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 item = SymbolCompletionItem.CreateWithSymbolId(
                    displayText: displayText,
                    symbols: ImmutableArray.Create(alias ?? type),
                    rules: s_rules.WithMatchPriority(MatchPriority.Preselect),
                    contextPosition: position);

                context.AddItem(item);
            }
            catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
Ejemplo n.º 17
0
        private static async Task HandleSingleTypeAsync(
            CompletionContext context,
            SemanticModel semanticModel,
            SyntaxToken token,
            ITypeSymbol type,
            CancellationToken cancellationToken
            )
        {
            // If we have a Nullable<T>, unwrap it.
            if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
            {
                var typeArg = type.GetTypeArguments().FirstOrDefault();
                if (typeArg == null)
                {
                    return;
                }

                type = typeArg;
            }

            // When true, this completion provider shows both the type (e.g. DayOfWeek) and its qualified members (e.g.
            // DayOfWeek.Friday). We set this to false for enum-like cases (static members of structs and classes) so we
            // only show the qualified members in these cases.
            var showType           = true;
            var position           = context.Position;
            var enclosingNamedType = semanticModel.GetEnclosingNamedType(
                position,
                cancellationToken
                );

            if (type.TypeKind != TypeKind.Enum)
            {
                var enumType =
                    TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken)
                    ?? TryGetCompletionListType(
                        type,
                        enclosingNamedType,
                        semanticModel.Compilation
                        );

                if (enumType == null)
                {
                    if (
                        context.Trigger.Kind == CompletionTriggerKind.Insertion &&
                        s_triggerCharacters.Contains(context.Trigger.Character)
                        )
                    {
                        // This completion provider understands static members of matching types, but doesn't
                        // proactively trigger completion for them to avoid interfering with common typing patterns.
                        return;
                    }

                    // If this isn't an enum or marked with completionlist, also check if it contains static members of
                    // a matching type. These 'enum-like' types have similar characteristics to enum completion, but do
                    // not show the containing type as a separate item in completion.
                    showType = false;
                    enumType = TryGetTypeWithStaticMembers(type);
                    if (enumType == null)
                    {
                        return;
                    }
                }

                type = enumType;
            }

            var options             = context.Options;
            var hideAdvancedMembers = options.GetOption(
                CompletionOptions.HideAdvancedMembers,
                semanticModel.Language
                );

            if (!type.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
            {
                return;
            }

            // Does type have any aliases?
            var alias = await type.FindApplicableAliasAsync(
                position,
                semanticModel,
                cancellationToken
                )
                        .ConfigureAwait(false);

            var displayText =
                alias != null ? alias.Name : type.ToMinimalDisplayString(semanticModel, position);

            // Add the enum itself.
            var symbol   = alias ?? type;
            var sortText = symbol.Name;

            if (showType)
            {
                context.AddItem(
                    SymbolCompletionItem.CreateWithSymbolId(
                        displayText,
                        displayTextSuffix: "",
                        symbols: ImmutableArray.Create(symbol),
                        rules: s_enumTypeRules,
                        contextPosition: position,
                        sortText: sortText
                        )
                    );
            }

            // And now all the accessible members of the enum.
            if (type.TypeKind == TypeKind.Enum)
            {
                // We'll want to build a list of the actual enum members and all accessible instances of that enum, too
                var index = 0;

                var fields = type.GetMembers()
                             .OfType <IFieldSymbol>()
                             .Where(f => f.IsConst)
                             .Where(f => f.HasConstantValue);
                foreach (
                    var field in fields.OrderBy(f => IntegerUtilities.ToInt64(f.ConstantValue))
                    )
                {
                    index++;
                    if (!field.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
                    {
                        continue;
                    }

                    var memberDisplayName = $"{displayText}.{field.Name}";
                    context.AddItem(
                        SymbolCompletionItem.CreateWithSymbolId(
                            displayText: memberDisplayName,
                            displayTextSuffix: "",
                            symbols: ImmutableArray.Create <ISymbol>(field),
                            rules: CompletionItemRules.Default,
                            contextPosition: position,
                            sortText: $"{sortText}_{index:0000}",
                            filterText: memberDisplayName
                            )
                        );
                }
            }
            else if (enclosingNamedType is not null)
            {
                // Build a list of the members with the same type as the target
                foreach (var member in type.GetMembers())
                {
                    ISymbol     staticSymbol;
                    ITypeSymbol symbolType;
                    if (member is IFieldSymbol {
                        IsStatic: true
                    } field)
                    {
                        staticSymbol = field;
                        symbolType   = field.Type;
                    }
                    else if (
                        member is IPropertySymbol {
                        IsStatic: true, IsIndexer: false
                    } property
                        )
                    {
                        staticSymbol = property;
                        symbolType   = property.Type;
                    }
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            try
            {
                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;
                }

                var targetToken = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken)
                                  .GetPreviousTokenIfTouchingWord(position);

                if (!syntaxTree.IsRightOfDotOrArrowOrColonColon(position, targetToken, cancellationToken))
                {
                    return;
                }

                var node = targetToken.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 = symbol.GetMembers();

                // 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);

                foreach (var member in members)
                {
                    if (member.IsAccessor() || member.Kind == SymbolKind.NamedType || !(member.IsAbstract || member.IsVirtual) ||
                        !semanticModel.IsAccessible(node.SpanStart, member))
                    {
                        continue;
                    }

                    var displayText = member.ToMinimalDisplayString(
                        semanticModel, namePosition, s_signatureDisplayFormat);
                    var insertionText = displayText;

                    var item = SymbolCompletionItem.CreateWithSymbolId(
                        displayText,
                        displayTextSuffix: "",
                        insertionText: insertionText,
                        symbols: ImmutableArray.Create(member),
                        contextPosition: position,
                        rules: CompletionItemRules.Default);
                    item = item.AddProperty(InsertionTextOnOpenParen, member.Name);

                    context.AddItem(item);
                }
            }
            catch (Exception e) when(FatalError.ReportWithoutCrashUnlessCanceled(e))
            {
                // nop
            }
        }