Beispiel #1
0
        private async Task CreateSpellCheckCodeIssueAsync(
            CodeFixContext context, SyntaxToken nameToken, bool isGeneric, CancellationToken cancellationToken)
        {
            var document = context.Document;
            var service  = CompletionService.GetService(document);

            // Disable snippets and unimported types from ever appearing in the completion items.
            // -    It's very unlikely the user would ever misspell a snippet, then use spell-checking to fix it,
            //      then try to invoke the snippet.
            // -    We believe spell-check should only compare what you have typed to what symbol would be offered here.
            var originalOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var options = originalOptions
                          .WithChangedOption(CompletionOptions.SnippetsBehavior, document.Project.Language, SnippetsRule.NeverInclude)
                          .WithChangedOption(CompletionOptions.ShowItemsFromUnimportedNamespaces, document.Project.Language, false);

            var completionList = await service.GetCompletionsAsync(
                document, nameToken.SpanStart, options : options, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (completionList == null)
            {
                return;
            }

            var nameText          = nameToken.ValueText;
            var similarityChecker = WordSimilarityChecker.Allocate(nameText, substringsAreSimilar: true);

            try
            {
                await CheckItemsAsync(
                    context, nameToken, isGeneric,
                    completionList, similarityChecker).ConfigureAwait(false);
            }
            finally
            {
                similarityChecker.Free();
            }
        }
Beispiel #2
0
            public async Task <ImmutableArray <SymbolResult <ISymbol> > > FindDeclarationsAsync(
                string name, TSimpleNameSyntax nameNode, SymbolFilter filter)
            {
                if (name != null && string.IsNullOrWhiteSpace(name))
                {
                    return(ImmutableArray <SymbolResult <ISymbol> > .Empty);
                }

                using (var query = this.Exact ? SearchQuery.Create(name, ignoreCase: true) : SearchQuery.CreateFuzzy(name))
                {
                    var symbols = await FindDeclarationsAsync(name, filter, query).ConfigureAwait(false);

                    if (Exact)
                    {
                        // We did an exact, case insensitive, search.  Case sensitive matches should
                        // be preferred though over insensitive ones.
                        return(symbols.SelectAsArray(s =>
                                                     SymbolResult.Create(s.Name, nameNode, s, weight: s.Name == name ? 0 : 1)));
                    }

                    // TODO(cyrusn): It's a shame we have to compute this twice.  However, there's no
                    // great way to store the original value we compute because it happens deep in the
                    // compiler bowels when we call FindDeclarations.
                    var similarityChecker = WordSimilarityChecker.Allocate(name, substringsAreSimilar: false);

                    var result = symbols.SelectAsArray(s =>
                    {
                        var areSimilar = similarityChecker.AreSimilar(s.Name, out var matchCost);

                        Debug.Assert(areSimilar);
                        return(SymbolResult.Create(s.Name, nameNode, s, matchCost));
                    });

                    similarityChecker.Free();

                    return(result);
                }
            }
Beispiel #3
0
        private async Task CreateSpellCheckCodeIssueAsync(CodeFixContext context, TSimpleName nameNode, string nameText, CancellationToken cancellationToken)
        {
            var document = context.Document;
            var service  = CompletionService.GetService(document);

            // Disable snippets from ever appearing in the completion items. It's
            // very unlikely the user would ever mispell a snippet, then use spell-
            // checking to fix it, then try to invoke the snippet.
            var originalOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var options = originalOptions.WithChangedOption(CompletionOptions.SnippetsBehavior, document.Project.Language, SnippetsRule.NeverInclude);

            var completionList = await service.GetCompletionsAsync(
                document, nameNode.SpanStart, options : options, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (completionList == null)
            {
                return;
            }

            var onlyConsiderGenerics = IsGeneric(nameNode);
            var results = new MultiDictionary <double, string>();

            using (var similarityChecker = new WordSimilarityChecker(nameText, substringsAreSimilar: true))
            {
                foreach (var item in completionList.Items)
                {
                    if (onlyConsiderGenerics && !IsGeneric(item))
                    {
                        continue;
                    }

                    var candidateText = item.FilterText;
                    if (!similarityChecker.AreSimilar(candidateText, out var matchCost))
                    {
                        continue;
                    }

                    var insertionText = await GetInsertionTextAsync(document, item, cancellationToken : cancellationToken).ConfigureAwait(false);

                    results.Add(matchCost, insertionText);
                }
            }

            var codeActions = results.OrderBy(kvp => kvp.Key)
                              .SelectMany(kvp => kvp.Value.Order())
                              .Where(t => t != nameText)
                              .Take(3)
                              .Select(n => CreateCodeAction(nameNode, nameText, n, document))
                              .ToImmutableArrayOrEmpty <CodeAction>();

            if (codeActions.Length > 1)
            {
                // Wrap the spell checking actions into a single top level suggestion
                // so as to not clutter the list.
                context.RegisterCodeFix(new MyCodeAction(
                                            String.Format(FeaturesResources.Spell_check_0, nameText), codeActions), context.Diagnostics);
            }
            else
            {
                context.RegisterFixes(codeActions, context.Diagnostics);
            }
        }
Beispiel #4
0
        private async Task CheckItemsAsync(
            CodeFixContext context,
            SyntaxToken nameToken,
            bool isGeneric,
            CompletionList completionList,
            WordSimilarityChecker similarityChecker
            )
        {
            var document          = context.Document;
            var cancellationToken = context.CancellationToken;

            var onlyConsiderGenerics = isGeneric;
            var results = new MultiDictionary <double, string>();

            foreach (var item in completionList.Items)
            {
                if (onlyConsiderGenerics && !IsGeneric(item))
                {
                    continue;
                }

                var candidateText = item.FilterText;
                if (!similarityChecker.AreSimilar(candidateText, out var matchCost))
                {
                    continue;
                }

                var insertionText = await GetInsertionTextAsync(
                    document,
                    item,
                    completionList.Span,
                    cancellationToken : cancellationToken
                    )
                                    .ConfigureAwait(false);

                results.Add(matchCost, insertionText);
            }

            var nameText    = nameToken.ValueText;
            var codeActions = results
                              .OrderBy(kvp => kvp.Key)
                              .SelectMany(kvp => kvp.Value.Order())
                              .Where(t => t != nameText)
                              .Take(3)
                              .Select(n => CreateCodeAction(nameToken, nameText, n, document))
                              .ToImmutableArrayOrEmpty <CodeAction>();

            if (codeActions.Length > 1)
            {
                // Wrap the spell checking actions into a single top level suggestion
                // so as to not clutter the list.
                context.RegisterCodeFix(
                    new MyCodeAction(
                        string.Format(FeaturesResources.Fix_typo_0, nameText),
                        codeActions
                        ),
                    context.Diagnostics
                    );
            }
            else
            {
                context.RegisterFixes(codeActions, context.Diagnostics);
            }
        }