public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var document = context.Document;
            var position = context.Position;
            var cancellationToken = context.CancellationToken;

            var workspace = document.Project.Solution.Workspace;
            var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, length: 0), cancellationToken).ConfigureAwait(false);
            var typeAndLocation = GetInitializedType(document, semanticModel, position, cancellationToken);

            if (typeAndLocation == null)
            {
                return;
            }

            var initializedType = typeAndLocation.Item1 as INamedTypeSymbol;
            var initializerLocation = typeAndLocation.Item2;
            if (initializedType == null)
            {
                return;
            }

            if (await IsExclusiveAsync(document, position, cancellationToken).ConfigureAwait(false))
            {
                context.IsExclusive = true;
            }

            var enclosing = semanticModel.GetEnclosingNamedType(position, cancellationToken);

            // Find the members that can be initialized. If we have a NamedTypeSymbol, also get the overridden members.
            IEnumerable<ISymbol> members = semanticModel.LookupSymbols(position, initializedType);
            members = members.Where(m => IsInitializable(m, enclosing) &&
                                         m.CanBeReferencedByName &&
                                         IsLegalFieldOrProperty(m, enclosing) &&
                                         !m.IsImplicitlyDeclared);

            // Filter out those members that have already been typed
            var alreadyTypedMembers = GetInitializedMembers(semanticModel.SyntaxTree, position, cancellationToken);
            var uninitializedMembers = members.Where(m => !alreadyTypedMembers.Contains(m.Name));

            uninitializedMembers = uninitializedMembers.Where(m => m.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation));

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

            foreach (var uninitializedMember in uninitializedMembers)
            {
                context.AddItem(SymbolCompletionItem.Create(
                    displayText: uninitializedMember.Name,
                    insertionText: null,
                    span: context.DefaultItemSpan,
                    symbol: uninitializedMember,
                    descriptionPosition: initializerLocation.SourceSpan.Start,
                    rules: s_rules
                    ));
            }
        }
        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));
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext completionContext)
        {
            var position          = completionContext.Position;
            var document          = completionContext.Document;
            var cancellationToken = completionContext.CancellationToken;
            var semanticModel     = await document.GetSemanticModelForSpanAsync(new Text.TextSpan(position, 0), cancellationToken).ConfigureAwait(false);

            var context = CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken);

            if (context.IsInNonUserCode)
            {
                return;
            }

            var nameInfo = await NameDeclarationInfo.GetDeclarationInfo(document, position, cancellationToken).ConfigureAwait(false);

            var baseNames = GetBaseNames(semanticModel, nameInfo);

            if (baseNames == default)
            {
                return;
            }

            var recommendedNames = await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, cancellationToken).ConfigureAwait(false);

            int 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, CompletionItemRules.Default);
        }
Пример #4
0
        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),
                    cancellationToken).ConfigureAwait(false);

                if (showSpeculativeT)
                {
                    const string T = nameof(T);
                    context.AddItem(CommonCompletionItem.Create(
                                        T, displayTextSuffix: "", CompletionItemRules.Default, glyph: Glyph.TypeParameter));
                }
            }
            catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e))
            {
                // nop
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            // wrap it in try catch, because exception for some reason sometimes crash entire VisualStudio
            try
            {
                if (!context.Document.SupportsSemanticModel)
                {
                    return;
                }

                var syntaxRoot = await context.Document.GetSyntaxRootAsync();

                var semanticModel = await context.Document.GetSemanticModelAsync();

                var tokenAtCursor = Helpers.GetCurrentArgumentListSyntaxToken(syntaxRoot, context.Position);
                if (tokenAtCursor.Kind() == SyntaxKind.None)
                {
                    return;
                }
                var mockedMethodArgumentList = tokenAtCursor.Parent as ArgumentListSyntax;
                var mockedMethodInvocation   = mockedMethodArgumentList?.Parent as InvocationExpressionSyntax;
                var setupMethodLambda        = mockedMethodInvocation?.Parent as LambdaExpressionSyntax;
                var setupMethodArgument      = setupMethodLambda?.Parent as ArgumentSyntax;
                var setupMethodArgumentList  = setupMethodArgument?.Parent as ArgumentListSyntax;
                var setupMethodInvocation    = setupMethodArgumentList?.Parent as InvocationExpressionSyntax;

                if (Helpers.IsMoqSetupMethod(semanticModel, setupMethodInvocation))
                {
                    var matchingMockedMethods = Helpers.GetAllMatchingMockedMethodSymbolsFromSetupMethodInvocation(semanticModel, setupMethodInvocation);

                    // TODO Narrow the list of matching signatures if some arguments are already provided
                    foreach (IMethodSymbol matchingMockedMethodSymbol in matchingMockedMethods.Where(m => m.Parameters.Any()))
                    {
                        // We are at first argument
                        if (tokenAtCursor.IsKind(SyntaxKind.OpenParenToken))
                        {
                            // Generate It.IsAny<>() for the whole signature if we are within first argument
                            var fullMethodHelper = string.Join(", ", matchingMockedMethodSymbol.Parameters.Select(p => "It.IsAny<" + p.Type.ToMinimalDisplayString(semanticModel, mockedMethodArgumentList.SpanStart) + ">()"));
                            context.AddItem(CompletionItem.Create(fullMethodHelper, rules: _preselectCompletionRules));
                            // There are more than one argument so suggest completion for first argument only too
                            if (matchingMockedMethodSymbol.Parameters.Length > 1)
                            {
                                var oneArgumentHelper = "It.IsAny<" + matchingMockedMethodSymbol.Parameters[0].Type.ToMinimalDisplayString(semanticModel, mockedMethodArgumentList.SpanStart) + ">()";
                                context.AddItem(CompletionItem.Create(oneArgumentHelper, rules: _standardCompletionRules));
                            }
                        }
                        // We are at second+ argument
                        else
                        {
                            // Generate It.IsAny<>() for single argument
                            var allCommaTokens = mockedMethodArgumentList.ChildTokens().Where(t => t.IsKind(SyntaxKind.CommaToken)).ToList();
                            int paramIdx       = allCommaTokens.IndexOf(tokenAtCursor) + 1;
                            if (matchingMockedMethodSymbol.Parameters.Length > paramIdx)
                            {
                                var oneArgumentHelper = "It.IsAny<" + matchingMockedMethodSymbol.Parameters[paramIdx].Type.ToMinimalDisplayString(semanticModel, mockedMethodArgumentList.SpanStart) + ">()";
                                context.AddItem(CompletionItem.Create(oneArgumentHelper, rules: _standardCompletionRules));
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                // ignore
            }
        }
Пример #6
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            // wrap it in try catch, because exception for some reason sometimes crash entire VisualStudio
            try
            {
                if (!context.Document.SupportsSemanticModel)
                {
                    return;
                }

                var syntaxRoot = await context.Document.GetSyntaxRootAsync();

                var semanticModel = await context.Document.GetSemanticModelAsync();

                var tokenAtCursor = Helpers.GetCurrentArgumentListSyntaxToken(syntaxRoot, context.Position);
                if (!tokenAtCursor.IsKind(SyntaxKind.OpenParenToken) && !tokenAtCursor.IsKind(SyntaxKind.CommaToken))
                {
                    return;
                }
                var argumentList = tokenAtCursor.Parent as ArgumentListSyntax;

                var allCommaTokens             = argumentList.ChildTokens().Where(t => t.IsKind(SyntaxKind.CommaToken)).ToList();
                int argumentIdx                = tokenAtCursor.IsKind(SyntaxKind.CommaToken) ? allCommaTokens.IndexOf(tokenAtCursor) + 1 : 0;
                var constructorCall            = argumentList.Parent as ObjectCreationExpressionSyntax;
                var matchingConstructorSymbols = Helpers.GetAllMatchingSymbols <IMethodSymbol>(semanticModel, constructorCall);
                if (matchingConstructorSymbols == null)
                {
                    return;
                }

                var matchingSymbols = new HashSet <ISymbol>();

                var symbols = semanticModel.LookupSymbols(context.Position);
                foreach (var symbol in symbols)
                {
                    INamedTypeSymbol symbolType;
                    if (symbol is IFieldSymbol)
                    {
                        var fieldSymbol = symbol as IFieldSymbol;
                        symbolType = fieldSymbol?.Type as INamedTypeSymbol;
                    }
                    else if (symbol is ILocalSymbol)
                    {
                        var localSymbol = symbol as ILocalSymbol;
                        symbolType = localSymbol.Type as INamedTypeSymbol;
                    }
                    else
                    {
                        continue;
                    }

                    if (symbolType == null || symbolType.ConstructedFrom == null)
                    {
                        continue;
                    }
                    if (symbolType.ConstructedFrom.ToString() != "Moq.Mock<T>" || symbolType.TypeArguments.Length != 1)
                    {
                        continue;
                    }
                    var typeArgument = symbolType.TypeArguments[0];
                    foreach (var methodSymbol in matchingConstructorSymbols.Where(m => m.Parameters.Length > argumentIdx))
                    {
                        if (methodSymbol.Parameters[argumentIdx].Type.ToString() == typeArgument.ToString())
                        {
                            matchingSymbols.Add(symbol);
                        }
                    }
                }

                foreach (var symbol in matchingSymbols)
                {
                    context.AddItem(CompletionItem.Create(symbol.Name + ".Object", rules: _preselectCompletionRules));
                }
            }
            catch (Exception)
            {
                // ignore
            }
        }
        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.Create(
                                    displayText: escapedName + ColonString,
                                    insertionText: null,
                                    span: context.DefaultItemSpan,
                                    symbol: parameter,
                                    descriptionPosition: token.SpanStart,
                                    filterText: escapedName,
                                    rules: CompletionItemRules.Default));
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext completionContext)
        {
            try
            {
                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);
                if (context.IsInNonUserCode)
                {
                    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(semanticModel, nameInfo);
                if (baseNames != default)
                {
                    await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, result, cancellationToken).ConfigureAwait(false);
                }

                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
            }
        }
        void AddDelegateHandlers(CompletionContext context, SyntaxNode parent, SemanticModel semanticModel, ITypeSymbol delegateType, int position, string optDelegateName, CancellationToken cancellationToken)
        {
            var delegateMethod = delegateType.GetDelegateInvokeMethod();

            string thisLineIndent;
            string oneIndent;
            var    editor = IdeApp.Workbench?.ActiveDocument?.Editor;

            if (editor != null)
            {
                thisLineIndent = editor.IndentationTracker.GetIndentationString(editor.OffsetToLineNumber(position));
                oneIndent      = editor.Options.TabsToSpaces ? new string (' ', editor.Options.TabSize) : "\t";
            }
            else
            {
                thisLineIndent = oneIndent = "\t";
            }

            string EolMarker    = "\n";
            bool   addSemicolon = true;
            bool   addDefault   = true;

            string         delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : "");
            CompletionItem item;

            if (addDefault)
            {
                item = CreateCompletionItem(
                    "delegate",
                    "Creates anonymous delegate.",
                    "delegate {" + EolMarker + thisLineIndent + oneIndent,
                    delegateEndString
                    );

                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }

                //if (LanguageVersion.Major >= 5)

                item = CreateCompletionItem(
                    "async delegate",
                    "Creates anonymous async delegate.",
                    "async delegate {" + EolMarker + thisLineIndent + oneIndent,
                    delegateEndString
                    );
                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }
            }

            var sb             = new StringBuilder("(");
            var sbWithoutTypes = new StringBuilder("(");

            for (int k = 0; k < delegateMethod.Parameters.Length; k++)
            {
                if (k > 0)
                {
                    sb.Append(", ");
                    sbWithoutTypes.Append(", ");
                }
                sb.Append(CSharpAmbience.SafeMinimalDisplayString(delegateMethod.Parameters [k], semanticModel, position, overrideNameFormat));
                sbWithoutTypes.Append(delegateMethod.Parameters [k].Name);
            }

            sb.Append(")");
            sbWithoutTypes.Append(")");
            var signature = sb.ToString()
                            .Replace(", params ", ", ")
                            .Replace("(params ", "(");

            if (context.Items.All(data => data.DisplayText != signature))
            {
                item = CreateCompletionItem(
                    signature + " =>",
                    "Creates typed lambda expression.",
                    signature + " => ",
                    (addSemicolon ? ";" : "")
                    );
                //item.CompletionCategory = category;
                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }

                // if (LanguageVersion.Major >= 5) {

                item = CreateCompletionItem(
                    "async " + signature + " =>",
                    "Creates typed async lambda expression.",
                    "async " + signature + " => ",
                    (addSemicolon ? ";" : "")
                    );
                //item.CompletionCategory = category;
                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }

                var signatureWithoutTypes = sbWithoutTypes.ToString();
                if (!delegateMethod.Parameters.Any(p => p.RefKind != RefKind.None) && context.Items.All(data => data.DisplayText != signatureWithoutTypes))
                {
                    item = CreateCompletionItem(
                        signatureWithoutTypes + " =>",
                        "Creates typed lambda expression.",
                        signatureWithoutTypes + " => ",
                        (addSemicolon ? ";" : "")
                        );
                    //item.CompletionCategory = category;
                    if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                    {
                        context.AddItem(item);
                        context.SuggestionModeItem = item;
                    }

                    //if (LanguageVersion.Major >= 5) {
                    item = CreateCompletionItem(
                        "async " + signatureWithoutTypes + " =>",
                        "Creates typed async lambda expression.",
                        "async " + signatureWithoutTypes + " => ",
                        (addSemicolon ? ";" : "")
                        );
                    //item.CompletionCategory = category;
                    if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                    {
                        context.AddItem(item);
                    }

                    //}
                }
            }
            item = CreateNewMethodCreationItem(parent, semanticModel, delegateType, position, optDelegateName, delegateMethod, cancellationToken);
            // item.CompletionCategory = category;
            if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
            {
                context.AddItem(item);
                context.SuggestionModeItem = item;
            }
        }
        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));
            }
        }
Пример #11
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            if (!context.Options.GetOption(RegularExpressionsOptions.ProvideRegexCompletions, context.Document.Project.Language))
            {
                return;
            }

            if (context.Trigger.Kind != CompletionTriggerKind.Invoke &&
                context.Trigger.Kind != CompletionTriggerKind.InvokeAndCommitIfUnique &&
                context.Trigger.Kind != CompletionTriggerKind.Insertion)
            {
                return;
            }

            var position = context.Position;

            var(tree, stringToken) = await _language.TryGetTreeAndTokenAtPositionAsync(
                context.Document, position, context.CancellationToken).ConfigureAwait(false);

            if (tree == null ||
                position <= stringToken.SpanStart ||
                position >= stringToken.Span.End)
            {
                return;
            }

            var embeddedContext = new EmbeddedCompletionContext(_language, context, tree, stringToken);

            ProvideCompletions(embeddedContext);

            if (embeddedContext.Items.Count == 0)
            {
                return;
            }

            foreach (var embeddedItem in embeddedContext.Items)
            {
                var change     = embeddedItem.Change;
                var textChange = change.TextChange;

                var properties = ImmutableDictionary.CreateBuilder <string, string>();
                properties.Add(StartKey, textChange.Span.Start.ToString());
                properties.Add(LengthKey, textChange.Span.Length.ToString());
                properties.Add(NewTextKey, textChange.NewText);
                properties.Add(DescriptionKey, embeddedItem.FullDescription);
                properties.Add(EmbeddedLanguageCompletionProvider.EmbeddedProviderName, Name);

                if (change.NewPosition != null)
                {
                    properties.Add(NewPositionKey, change.NewPosition.ToString());
                }

                // Keep everything sorted in the order we just produced the items in.
                var sortText = context.Items.Count.ToString("0000");
                context.AddItem(CompletionItem.Create(
                                    displayText: embeddedItem.DisplayText,
                                    inlineDescription: embeddedItem.InlineDescription,
                                    sortText: sortText,
                                    properties: properties.ToImmutable(),
                                    rules: s_rules));
            }

            context.IsExclusive = true;
        }
Пример #12
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);
                if (token.IsMandatoryNamedParameterPosition())
                {
                    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 = 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 item = SymbolCompletionItem.Create(
                    displayText: displayText,
                    insertionText: null,
                    span: context.DefaultItemSpan,
                    symbol: alias ?? type,
                    descriptionPosition: position,
                    preselect: true,
                    rules: s_rules);

                context.AddItem(item);
            }
            catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
Пример #13
0
        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;
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var document          = context.Document;
            var position          = context.Position;
            var cancellationToken = context.CancellationToken;

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

            if (
                !(
                    GetInitializedType(document, semanticModel, position, cancellationToken)
                    is var(type, initializerLocation)
                    )
                )
            {
                return;
            }

            if (type is ITypeParameterSymbol typeParameterSymbol)
            {
                type = typeParameterSymbol.GetNamedTypeSymbolConstraint();
            }

            if (!(type is INamedTypeSymbol initializedType))
            {
                return;
            }

            if (await IsExclusiveAsync(document, position, cancellationToken).ConfigureAwait(false))
            {
                context.IsExclusive = true;
            }

            var enclosing = semanticModel.GetEnclosingNamedType(position, cancellationToken);

            // Find the members that can be initialized. If we have a NamedTypeSymbol, also get the overridden members.
            IEnumerable <ISymbol> members = semanticModel.LookupSymbols(position, initializedType);

            members = members.Where(
                m =>
                IsInitializable(m, enclosing) &&
                m.CanBeReferencedByName &&
                IsLegalFieldOrProperty(m) &&
                !m.IsImplicitlyDeclared
                );

            // Filter out those members that have already been typed
            var alreadyTypedMembers = GetInitializedMembers(
                semanticModel.SyntaxTree,
                position,
                cancellationToken
                );
            var uninitializedMembers = members.Where(m => !alreadyTypedMembers.Contains(m.Name));

            uninitializedMembers = uninitializedMembers.Where(
                m =>
                m.IsEditorBrowsable(
                    document.ShouldHideAdvancedMembers(),
                    semanticModel.Compilation
                    )
                );

            foreach (var uninitializedMember in uninitializedMembers)
            {
                context.AddItem(
                    SymbolCompletionItem.CreateWithSymbolId(
                        displayText: EscapeIdentifier(uninitializedMember),
                        displayTextSuffix: "",
                        insertionText: null,
                        symbols: ImmutableArray.Create(uninitializedMember),
                        contextPosition: initializerLocation.SourceSpan.Start,
                        rules: s_rules
                        )
                    );
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            // wrap it in try catch, because exception for some reason sometimes crash entire VisualStudio
            try
            {
                if (!context.Document.SupportsSemanticModel)
                {
                    return;
                }

                var syntaxRoot = await context.Document.GetSyntaxRootAsync();

                var semanticModel = await context.Document.GetSemanticModelAsync();

                var tokenAtCursor = Helpers.GetCurrentTypeArgumentList(syntaxRoot, context.Position);
                if (!tokenAtCursor.IsKind(SyntaxKind.GreaterThanToken))
                {
                    return;
                }
                var typeArgumentList = tokenAtCursor.Parent as TypeArgumentListSyntax;
                // We are aiming Mock<T>, so can do shortcut exit here for mismatches
                if (typeArgumentList.Arguments.Count != 1)
                {
                    return;
                }
                var genericName = typeArgumentList?.Parent as GenericNameSyntax;
                // TODO: Yuk! Sometimes additional parent appears.
                var memberSyntax     = genericName?.Parent as IncompleteMemberSyntax ?? genericName?.Parent?.Parent as IncompleteMemberSyntax;
                var classDeclaration = memberSyntax?.Parent as ClassDeclarationSyntax;
                // Ignore if not a field/method declaration
                if (classDeclaration == null)
                {
                    return;
                }

                var typeInfo = semanticModel.GetTypeInfo(genericName);
                var type     = typeInfo.Type as INamedTypeSymbol;
                if (type == null || type.ConstructedFrom == null)
                {
                    return;
                }
                if (type.ConstructedFrom.ToString() != "Moq.Mock<T>")
                {
                    return;
                }

                var mockedType     = typeArgumentList.Arguments[0];
                var mockedTypeInfo = semanticModel.GetTypeInfo(mockedType);
                if (mockedTypeInfo.Type == null)
                {
                    return;
                }
                var mockedTypeName = mockedTypeInfo.Type.Name;
                if (mockedTypeName.Length > 1 && mockedTypeName[0] == 'I' && Char.IsUpper(mockedTypeName[1])) // ISomething
                {
                    mockedTypeName = mockedTypeName.Substring(1);
                }
                context.AddItem(CompletionItem.Create(mockedTypeName.Substring(0, 1).ToLower() + mockedTypeName.Substring(1) + "Mock", rules: _preselectCompletionRules));
            }
            catch (Exception)
            {
                // ignore
            }
        }
        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));
                }
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var cancellationToken = context.CancellationToken;
            var syntaxRoot        = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var node          = syntaxRoot.FindNode(context.CompletionListSpan);
            var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // Check that we're inside a string literal which is a method argument
            if (!(node is ArgumentSyntax argNode) || !(argNode.Expression is LiteralExpressionSyntax literalNode) ||
                !(argNode.Parent.Parent is InvocationExpressionSyntax invNode))
            {
                return;
            }

            // Check that is is a method call
            if (!(semanticModel.GetSymbolInfo(invNode, cancellationToken).Symbol is IMethodSymbol methodSymbol))
            {
                return;
            }

            // Check that it is a Dapper extension method call
            var sqlMapperSymbol = semanticModel.Compilation.GetTypeByMetadataName("Dapper.SqlMapper");

            if (sqlMapperSymbol == null || !methodSymbol.ContainingType.Equals(sqlMapperSymbol) ||
                methodSymbol.Name != "Query" || !methodSymbol.IsGenericMethod)
            {
                return;
            }

            // We don't want to show any other IntelliSense items except ours
            context.IsExclusive = true;
            // Get the string literal's value, considering the current position
            string text = literalNode.Token.ValueText;

            text = text.Substring(0, context.Position - literalNode.Token.SpanStart - 1);

            if (String.IsNullOrEmpty(text))
            {
                context.AddItem(CompletionItem.Create("SELECT",
                                                      tags: ImmutableArray.Create(WellKnownTags.Keyword)));
            }
            else
            {
                var parseResult = Parser.Parse(text);

                if (parseResult.Script.Batches.Count == 0 || parseResult.Script.Batches[0].Statements.Count == 0)
                {
                    return;
                }

                var statement = parseResult.Script.Batches[0].Statements[0];
                if (!(statement is SqlSelectStatement selectStatement))
                {
                    return;
                }

                if (!(selectStatement.SelectSpecification?.QueryExpression is SqlQuerySpecification query))
                {
                    return;
                }

                if (query.SelectClause.SelectExpressions.All(e => String.IsNullOrWhiteSpace(e.Sql)))
                {
                    context.AddItem(CompletionItem.Create("TOP", tags: ImmutableArray.Create(WellKnownTags.Keyword)));
                    context.AddItem(CompletionItem.Create("*", tags: ImmutableArray.Create(WellKnownTags.Keyword)));

                    bool singleTable = methodSymbol.TypeArguments.Length == 1;

                    foreach (var typePar in methodSymbol.TypeArguments)
                    {
                        foreach (var property in typePar.GetMembers()
                                 .OfType <IPropertySymbol>()
                                 .Where(p => p.DeclaredAccessibility.HasFlag(Accessibility.Public) && p.GetMethod != null))
                        {
                            string propText = singleTable ? property.Name : $"{typePar.Name}.{property.Name}";
                            context.AddItem(CompletionItem.Create(propText, tags: ImmutableArray.Create(WellKnownTags.Property)));
                        }
                    }
                }
            }
        }
        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)
                          .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);

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

                context.AddItem(SymbolCompletionItem.Create(
                                    displayText,
                                    insertionText: insertionText,
                                    span: context.DefaultItemSpan,
                                    symbol: member,
                                    contextPosition: position,
                                    descriptionPosition: position,
                                    rules: CompletionItemRules.Default));
            }
        }
        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
                                .ReuseExistingSpeculativeModelAsync(position, 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
                        )
                    );
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext completionContext)
        {
            if (!completionContext.Document.SupportsSemanticModel)
            {
                return;
            }

            var position          = completionContext.Position;
            var document          = completionContext.Document;
            var cancellationToken = completionContext.CancellationToken;

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span  = completionContext.CompletionListSpan;
            var token = root.FindToken(span.Start);
            var node  = token.Parent?.AncestorsAndSelf().FirstOrDefault(a => a.FullSpan.Contains(span));

            if (node is LiteralExpressionSyntax literal &&
                node?.Parent is AttributeArgumentSyntax argument &&
                // TODO: we support only property syntax for completion in attributes,
                // since that's what XA has right now anyway, and we need to lookup the
                // [Category] attribute on the property.
                argument.NameEquals != null &&
                node?.Parent?.Parent?.Parent is AttributeSyntax attribute)
            {
                var semanticModel = await document.GetSemanticModelAsync(cancellationToken);

                var projectPath = string.IsNullOrEmpty(document.Project.FilePath) ? null : Path.GetDirectoryName(document.Project.FilePath);
                // From the attribute syntax, we'll get the constructor for the attribute
                var symbol = (semanticModel.GetSymbolInfo(attribute, cancellationToken).Symbol as IMethodSymbol)?.ContainingType;
                if (symbol?.ContainingNamespace.ToDisplayString() == "Android.App")
                {
                    var name = argument.NameEquals.Name.ToString();
                    // First try explicit completion hint via Category
                    var propertyInfo = symbol.GetMembers(name).FirstOrDefault() as IPropertySymbol;
                    if (propertyInfo == null)
                    {
                        return;
                    }

                    string[] categories;
                    var      categoryAttr = propertyInfo.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == typeof(CategoryAttribute).FullName);
                    if (categoryAttr == null)
                    {
                        // Apply default heuristics based on member name
                        // Label/Description: @string
                        // Icon/RoundIcon: @drawable; @mipmap
                        // Theme: @style
                        if (name == "Label" || name == "Description")
                        {
                            categories = new[] { "string" }
                        }
                        ;
                        else if (name == "Icon" || name == "RoundIcon")
                        {
                            categories = new[] { "drawable", "mipmap" }
                        }
                        ;
                        else if (name == "Theme")
                        {
                            categories = new[] { "style" }
                        }
                        ;
                        else
                        {
                            return;
                        }
                    }
                    else if (!categoryAttr.ConstructorArguments.IsDefaultOrEmpty)
                    {
                        categories = ((string)categoryAttr.ConstructorArguments[0].Value)
                                     .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
                                     .Select(s => s.Trim().TrimStart('@'))
                                     .ToArray();
                    }
                    else
                    {
                        return;
                    }

                    var compilation = await document.Project.GetCompilationAsync(completionContext.CancellationToken);

                    var resourceDesignerAttribute = compilation.Assembly.GetAttributes().FirstOrDefault(attr
                                                                                                        => attr.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::Android.Runtime.ResourceDesignerAttribute");

                    if (resourceDesignerAttribute != null && resourceDesignerAttribute.ConstructorArguments.Any())
                    {
                        var resourceDesigner = compilation.GetTypeByMetadataName((string)resourceDesignerAttribute.ConstructorArguments.First().Value);
                        if (resourceDesigner != null)
                        {
                            foreach (var category in categories)
                            {
                                var resourceSymbol = resourceDesigner.GetTypeMembers().FirstOrDefault(x => x.Name.Equals(category, StringComparison.OrdinalIgnoreCase));
                                if (resourceSymbol != null)
                                {
                                    foreach (var member in resourceSymbol.GetMembers().Where(x => x.Kind == SymbolKind.Field))
                                    {
                                        completionContext.AddItem(CompletionItem.Create(
                                                                      displayText: member.Name,
                                                                      displayTextPrefix: $"@{category}/",
                                                                      sortText: $"@{category}/{member.Name}",
                                                                      properties: ImmutableDictionary.Create <string, string>()
                                                                      .Add("Summary", member.GetDocumentationCommentXml())
                                                                      // Add the starting quote char to start position
                                                                      .Add("Start", (node.Span.Start + 1).ToString())
                                                                      // Remove the two quote characters
                                                                      .Add("Length", (node.Span.Length - 2).ToString()),
                                                                      tags: ImmutableArray.Create(WellKnownTags.Constant, "Xamarin"),
                                                                      rules: CompletionItemRules.Default));
                                    }
                                }
                            }
                        }
                    }
                }
            }

            await Task.CompletedTask;
        }
        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
            }
        }
Пример #23
0
        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
            }
        }
Пример #24
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken);

            if (syntaxRoot == null)
            {
                return;
            }

            var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken);

            var node = syntaxRoot.FindNode(context.CompletionListSpan);

            var argumentSyntaxNode = node.AncestorsAndSelf().OfType <ArgumentSyntax>().FirstOrDefault();

            if (argumentSyntaxNode == null)
            {
                return;
            }

            var lambdaExpression = argumentSyntaxNode.Ancestors().OfType <LambdaExpressionSyntax>().FirstOrDefault();

            if (lambdaExpression == null)
            {
                return;
            }

            var mockMethod = lambdaExpression.Ancestors().FirstOrDefault(x => semanticModel.GetSymbolInfo(x, context.CancellationToken).CandidateSymbols.Any(s => s.ContainingType.Name == "Mock" && s.ContainingAssembly.Name == "Moq"));

            if (mockMethod == null)
            {
                return;
            }

            var typingMethod = argumentSyntaxNode.Ancestors().OfType <InvocationExpressionSyntax>().First();
            var calingMethod = semanticModel.GetSymbolInfo(typingMethod, context.CancellationToken);

            if (!(calingMethod.CandidateSymbols[0] is IMethodSymbol callingMethodSymbol))
            {
                return;
            }

            var index = argumentSyntaxNode.Parent.ChildNodes().ToList().FindIndex(x => x.Equals(argumentSyntaxNode));

            if (index < callingMethodSymbol.Parameters.Length)
            {
                context.AddItem(CompletionItem.Create(GetCompletionDisplayText(callingMethodSymbol.Parameters[index].Type),
                                                      null, null,
                                                      ImmutableDictionary.Create <string, string>(),
                                                      ImmutableArray.Create(WellKnownTags.Method),
                                                      CompletionItemRules.Create(formatOnCommit: true, matchPriority: MatchPriority.Preselect)));
            }

            if (index == 0)
            {
                context.AddItem(CompletionItem.Create(String.Join(", ", callingMethodSymbol.Parameters.Select(x => GetCompletionDisplayText(x.Type))),
                                                      null, null,
                                                      ImmutableDictionary.Create <string, string>(),
                                                      ImmutableArray.Create(WellKnownTags.Method),
                                                      CompletionItemRules.Create(formatOnCommit: true)));
            }
        }
Пример #25
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var cancellationToken = context.CancellationToken;
            // Получаем семантическую модель (она понадобится для работы с типами и методами)
            var semanticModel = await context.Document
                                .GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // Находим синтаксическую ноду, внутри который был вызван IntelliSense
            var syntaxRoot = await context.Document
                             .GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var node = syntaxRoot.FindNode(context.CompletionListSpan);

            // Проверяем, что мы внутри строкового литерала, который к тому же является аргументом вызова метода
            if (!(node is ArgumentSyntax argNode) ||
                !(argNode.Expression is LiteralExpressionSyntax literalNode) ||
                !(argNode.Parent.Parent is InvocationExpressionSyntax invNode))
            {
                return;
            }

            // Получаем семантическую информацию о вызываемом методе
            var symbolInfo   = semanticModel.GetSymbolInfo(invNode, cancellationToken);
            var methodSymbol = (symbolInfo.Symbol ?? symbolInfo.CandidateSymbols.FirstOrDefault()) as IMethodSymbol;

            if (methodSymbol == null)
            {
                return;
            }

            // Проверяем, что это действительно метод Dapper
            var sqlMapperSymbol = semanticModel.Compilation.GetTypeByMetadataName("Dapper.SqlMapper");

            if (sqlMapperSymbol == null || !methodSymbol.ContainingType.Equals(sqlMapperSymbol) ||
                methodSymbol.Name != "Query" || !methodSymbol.IsGenericMethod)
            {
                return;
            }

            // Даём системе понять, что мы хотим показывать только наши completion items, и никакие другие
            // (не использовать другие completion provider'ы, кроме текущего)
            context.IsExclusive = true;

            // Получаем строку от начала строкового литерала до курсора ввода
            string text           = literalNode.Token.ValueText;
            int    selectedLength = context.Position - literalNode.Token.SpanStart - 1;

            if (selectedLength < text.Length)
            {
                text = text.Substring(0, selectedLength);
            }

            // Собираем информацию о всех свойствах DTO-классов, используемых в запросе
            var properties = methodSymbol.TypeArguments.SelectMany(t => t
                                                                   .GetMembers()
                                                                   .OfType <IPropertySymbol>()
                                                                   .Where(p => p.DeclaredAccessibility.HasFlag(Accessibility.Public) &&
                                                                          p.GetMethod != null)).ToArray();

            // Определяем, в какой части SQL-запроса мы сейчас находимся, и что же нужно показывать пользователю
            if (String.IsNullOrEmpty(text))
            {
                // Добавляем новый пункт в IntelliSense...
                context.AddItem(CompletionItem.Create("SELECT")
                                // ...показывая его, как ключевое слово языка (соответствующая иконка)
                                .AddTag(WellKnownTags.Keyword));
            }
            else
            {
                if (text.StartsWith("SELECT ", StringComparison.OrdinalIgnoreCase) &&
                    !text.EndsWith(" FROM ", StringComparison.OrdinalIgnoreCase))
                {
                    if (text.Equals("SELECT ", StringComparison.OrdinalIgnoreCase))
                    {
                        context.AddItem(CompletionItem.Create("DISTINCT", sortText: "K DISTINCT")
                                        .AddTag(WellKnownTags.Keyword));
                        context.AddItem(CompletionItem.Create("TOP", sortText: "K TOP")
                                        .AddTag(WellKnownTags.Keyword));
                    }

                    if (!text.EndsWith(" TOP ", StringComparison.OrdinalIgnoreCase))
                    {
                        context.AddItem(CompletionItem.Create("*", sortText: "K *")
                                        .AddTag(WellKnownTags.Keyword));

                        bool singleTable = methodSymbol.TypeArguments.Length == 1;

                        foreach (var property in properties)
                        {
                            string propText = singleTable
                                                                ? property.Name
                                                                : $"{property.ContainingType.Name}.{property.Name}";
                            context.AddItem(CompletionItem.Create(propText, sortText: $"P {propText}")
                                            .AddTag(WellKnownTags.Property)
                                            // Добавляем XML-комментарий от свойства DTO-класса как метаинформацию
                                            .AddProperty("comment", property.GetDocumentationCommentXml()));
                        }
                    }

                    if (text.EndsWith(" * ", StringComparison.OrdinalIgnoreCase) ||
                        properties.Any(p => text.EndsWith(p.Name + " ")))
                    {
                        context.AddItem(CompletionItem.Create("FROM", sortText: "K FROM")
                                        .AddTag(WellKnownTags.Keyword));
                    }
                }
                else if (text.EndsWith(" FROM ", StringComparison.OrdinalIgnoreCase))
                {
                    foreach (var typePar in methodSymbol.TypeArguments)
                    {
                        context.AddItem(CompletionItem.Create(typePar.Name)
                                        .AddTag(WellKnownTags.Class)
                                        // Добавляем XML-комментарий от DTO-класса как метаинформацию
                                        .AddProperty("comment", typePar.GetDocumentationCommentXml()));
                    }
                }
            }
        }
Пример #26
0
        void AddDelegateHandlers(CompletionContext context, SyntaxNode parent, SemanticModel semanticModel, ITypeSymbol delegateType, int position, string optDelegateName, CancellationToken cancellationToken)
        {
            var delegateMethod = delegateType.GetDelegateInvokeMethod();

            string EolMarker    = "\n";
            bool   addSemicolon = true;
            bool   addDefault   = true;

            string         delegateEndString = EolMarker + thisLineIndentMarker + "}" + (addSemicolon ? ";" : "");
            CompletionItem item;

            if (addDefault)
            {
                item = CreateCompletionItem(
                    "delegate",
                    "Creates anonymous delegate.",
                    "delegate {" + EolMarker + thisLineIndentMarker + eolMarker,
                    delegateEndString,
                    position
                    );

                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }

                //if (LanguageVersion.Major >= 5)

                item = CreateCompletionItem(
                    "async delegate",
                    "Creates anonymous async delegate.",
                    "async delegate {" + EolMarker + thisLineIndentMarker + eolMarker,
                    delegateEndString,
                    position
                    );
                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }
            }

            var sb             = StringBuilderCache.Allocate("(");
            var sbWithoutTypes = StringBuilderCache.Allocate("(");

            for (int k = 0; k < delegateMethod.Parameters.Length; k++)
            {
                if (k > 0)
                {
                    sb.Append(", ");
                    sbWithoutTypes.Append(", ");
                }
                sb.Append(CSharpAmbience.SafeMinimalDisplayString(delegateMethod.Parameters [k], semanticModel, position, overrideNameFormat));
                sbWithoutTypes.Append(delegateMethod.Parameters [k].Name);
            }

            sb.Append(")");
            sbWithoutTypes.Append(")");
            var signature = StringBuilderCache.ReturnAndFree(sb)
                            .Replace(", params ", ", ")
                            .Replace("(params ", "(");

            if (context.Items.All(data => data.DisplayText != signature))
            {
                item = CreateCompletionItem(
                    signature + " =>",
                    "Creates typed lambda expression.",
                    signature + " => ",
                    (addSemicolon ? ";" : ""),
                    position
                    );
                //item.CompletionCategory = category;
                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }

                // if (LanguageVersion.Major >= 5) {

                item = CreateCompletionItem(
                    "async " + signature + " =>",
                    "Creates typed async lambda expression.",
                    "async " + signature + " => ",
                    (addSemicolon ? ";" : ""),
                    position
                    );
                //item.CompletionCategory = category;
                if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                {
                    context.AddItem(item);
                }

                var signatureWithoutTypes = sbWithoutTypes.ToString();
                if (!delegateMethod.Parameters.Any(p => p.RefKind != RefKind.None) && context.Items.All(data => data.DisplayText != signatureWithoutTypes))
                {
                    item = CreateCompletionItem(
                        signatureWithoutTypes + " =>",
                        "Creates typed lambda expression.",
                        signatureWithoutTypes + " => ",
                        (addSemicolon ? ";" : ""),
                        position
                        );
                    //item.CompletionCategory = category;
                    if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                    {
                        context.AddItem(item.WithRules(item.Rules.WithMatchPriority(int.MaxValue)));
                    }

                    //if (LanguageVersion.Major >= 5) {
                    item = CreateCompletionItem(
                        "async " + signatureWithoutTypes + " =>",
                        "Creates typed async lambda expression.",
                        "async " + signatureWithoutTypes + " => ",
                        (addSemicolon ? ";" : ""),
                        position
                        );
                    //item.CompletionCategory = category;
                    if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
                    {
                        context.AddItem(item);
                    }

                    //}
                }
            }

            StringBuilderCache.Free(sbWithoutTypes);
            item = CreateNewMethodCreationItem(parent, semanticModel, delegateType, position, optDelegateName, delegateMethod, cancellationToken);
            // item.CompletionCategory = category;
            if (!context.Items.Any(i => i.DisplayText == item.DisplayText))
            {
                context.AddItem(item.WithRules(item.Rules.WithMatchPriority(int.MaxValue)));
            }
        }
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            var document          = context.Document;
            var position          = context.Position;
            var cancellationToken = context.CancellationToken;

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

            if (GetInitializedType(document, semanticModel, position, cancellationToken) is not var(type, initializerLocation))
            {
                return;
            }

            if (type is ITypeParameterSymbol typeParameterSymbol)
            {
                type = typeParameterSymbol.GetNamedTypeSymbolConstraint();
            }

            if (type is not INamedTypeSymbol initializedType)
            {
                return;
            }

            if (await IsExclusiveAsync(document, position, cancellationToken).ConfigureAwait(false))
            {
                context.IsExclusive = true;
            }

            var enclosing = semanticModel.GetEnclosingNamedType(position, cancellationToken);

            Contract.ThrowIfNull(enclosing);

            // Find the members that can be initialized. If we have a NamedTypeSymbol, also get the overridden members.
            IEnumerable <ISymbol> members = semanticModel.LookupSymbols(position, initializedType);

            members = members.Where(m => IsInitializable(m, enclosing) &&
                                    m.CanBeReferencedByName &&
                                    IsLegalFieldOrProperty(m) &&
                                    !m.IsImplicitlyDeclared);

            // Filter out those members that have already been typed
            var alreadyTypedMembers  = GetInitializedMembers(semanticModel.SyntaxTree, position, cancellationToken);
            var uninitializedMembers = members.Where(m => !alreadyTypedMembers.Contains(m.Name));

            // Sort the members by name so if we preselect one, it'll be stable
            uninitializedMembers = uninitializedMembers.Where(m => m.IsEditorBrowsable(context.CompletionOptions.HideAdvancedMembers, semanticModel.Compilation))
                                   .OrderBy(m => m.Name);

            var firstUnitializedRequiredMember = true;

            foreach (var uninitializedMember in uninitializedMembers)
            {
                var rules = s_rules;

                // We'll hard select the first required member to make it a bit easier to type out an object initializer
                // with a bunch of members.
                if (firstUnitializedRequiredMember && uninitializedMember.IsRequired())
                {
                    rules = rules.WithSelectionBehavior(CompletionItemSelectionBehavior.HardSelection).WithMatchPriority(MatchPriority.Preselect);
                    firstUnitializedRequiredMember = false;
                }

                context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                    displayText: EscapeIdentifier(uninitializedMember),
                                    displayTextSuffix: "",
                                    insertionText: null,
                                    symbols: ImmutableArray.Create(uninitializedMember),
                                    contextPosition: initializerLocation.SourceSpan.Start,
                                    inlineDescription: uninitializedMember.IsRequired() ? FeaturesResources.Required : null,
                                    rules: rules));
            }
        }
Пример #28
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;
            }
        }
Пример #29
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            // This provider is exported for all workspaces - so limit it to just our workspace & the debugger's intellisense workspace
            if (context.Document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace &&
                context.Document.Project.Solution.Workspace.Kind != StringConstants.DebuggerIntellisenseWorkspaceKind)
            {
                return;
            }

            var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;

            if (lspClient == null)
            {
                return;
            }

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

            var completionParams = new LSP.CompletionParams
            {
                TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(context.Document),
                Position     = ProtocolConversions.LinePositionToPosition(text.Lines.GetLinePosition(context.Position)),
                Context      = new LSP.CompletionContext {
                    TriggerCharacter = context.Trigger.Character.ToString(), TriggerKind = GetTriggerKind(context.Trigger)
                }
            };

            var completionObject = await lspClient.RequestAsync(LSP.Methods.TextDocumentCompletion.ToLSRequest(), completionParams, context.CancellationToken).ConfigureAwait(false);

            if (completionObject == null)
            {
                return;
            }

            var completionList = ((JToken)completionObject).ToObject <RoslynCompletionItem[]>();

            foreach (var item in completionList)
            {
                ImmutableArray <string> tags;
                if (item.Tags != null)
                {
                    tags = item.Tags.AsImmutable();
                }
                else
                {
                    var glyph = ProtocolConversions.CompletionItemKindToGlyph(item.Kind);
                    tags = GlyphTags.GetTags(glyph);
                }

                var properties = ImmutableDictionary.CreateBuilder <string, string>();
                if (!string.IsNullOrEmpty(item.Detail))
                {
                    // The display text is encoded as TaggedText | value
                    properties.Add("Description", $"Text|{item.Detail}");
                }

                properties.Add("InsertionText", item.InsertText);
                properties.Add("ResolveData", JToken.FromObject(item).ToString());
                var completionItem = CompletionItem.Create(item.Label, item.FilterText, item.SortText, properties: properties.ToImmutable(), tags: tags);
                context.AddItem(completionItem);
            }
        }
Пример #30
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;
                    }
Пример #31
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            try
            {
                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.IsKind(SyntaxKind.IdentifierToken) &&
                        targetToken.HasMatchingText(SyntaxKind.AliasKeyword)
                        )
                    )
                {
                    return;
                }

                if (
                    targetToken.Parent.IsKind(SyntaxKind.ExternAliasDirective) ||
                    (
                        targetToken.Parent.IsKind(SyntaxKind.IdentifierName) &&
                        targetToken.Parent.IsParentKind(SyntaxKind.IncompleteMember)
                    )
                    )
                {
                    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);

                        foreach (var alias in aliases)
                        {
                            context.AddItem(
                                CommonCompletionItem.Create(
                                    alias,
                                    displayTextSuffix: "",
                                    CompletionItemRules.Default,
                                    glyph: Glyph.Namespace
                                    )
                                );
                        }
                    }
                }
            }
            catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e))
            {
                // nop
            }
        }