public override int Compare(SpellingDiagnostic x, SpellingDiagnostic y)
            {
                if (object.ReferenceEquals(x, y))
                {
                    return(0);
                }

                if (x == null)
                {
                    return(-1);
                }

                if (y == null)
                {
                    return(1);
                }

                int result = StringComparer.OrdinalIgnoreCase.Compare(
                    x.FilePath,
                    y.FilePath);

                if (result != 0)
                {
                    return(result);
                }

                return(x.Span.Start.CompareTo(y.Span.Start));
            }
예제 #2
0
 public static SpellingFixResult Create(string sourceText, SpellingDiagnostic diagnostic, SpellingFix fix)
 {
     return(new SpellingFixResult(
                sourceText,
                new SpellingCapture(diagnostic.Value, diagnostic.Index, diagnostic.Parent, diagnostic.ParentIndex),
                diagnostic.Span,
                fix,
                diagnostic.Location.GetMappedLineSpan()));
 }
            public override int GetHashCode(SpellingDiagnostic obj)
            {
                if (obj == null)
                {
                    throw new ArgumentNullException(nameof(obj));
                }

                return(Hash.Combine(
                           StringComparer.OrdinalIgnoreCase.GetHashCode(obj.FilePath),
                           obj.Span.Start));
            }
예제 #4
0
            static void AddResult(
                List<SpellingFixResult> results,
                SpellingDiagnostic diagnostic,
                SpellingFix fix,
                SourceText sourceText,
                ref string sourceTextText)
            {
                if (sourceTextText == null)
                    sourceTextText = (ShouldWrite(Verbosity.Detailed)) ? sourceText.ToString() : "";

                SpellingFixResult result = SpellingFixResult.Create(
                    (sourceTextText.Length == 0) ? null : sourceTextText,
                    diagnostic,
                    fix);

                results.Add(result);
            }
예제 #5
0
        public SpellingFix ChooseFix(
            SpellingDiagnostic diagnostic,
            List <SpellingFix> fixes,
            bool interactive)
        {
            fixes = fixes
                    .Distinct(SpellingFixComparer.InvariantCulture)
                    .Where(f =>
            {
                return(f.Kind == SpellingFixKind.Predefined ||
                       diagnostic.IsApplicableFix(f.Value));
            })
                    .Select(fix =>
            {
                if (TextUtility.GetTextCasing(fix.Value) != TextCasing.Undefined)
                {
                    return(fix.WithValue(TextUtility.SetTextCasing(fix.Value, diagnostic.Casing)));
                }

                return(fix);
            })
                    .OrderBy(f => f.Kind)
                    .Take(9)
                    .ToList();

            if (fixes.Count > 0)
            {
                for (int i = 0; i < fixes.Count; i++)
                {
                    WriteSuggestion(diagnostic, fixes[i], i, interactive);
                }

                if (TryReadSuggestion(out int index) &&
                    index < fixes.Count)
                {
                    return(fixes[index]);
                }
            }

            return(default);
            public override bool Equals(SpellingDiagnostic x, SpellingDiagnostic y)
            {
                if (object.ReferenceEquals(x, y))
                {
                    return(true);
                }

                if (x == null)
                {
                    return(false);
                }

                if (y == null)
                {
                    return(false);
                }

                return(StringComparer.OrdinalIgnoreCase.Equals(
                           x.FilePath,
                           y.FilePath) &&
                       x.Span.Start == y.Span.Start);
            }
예제 #7
0
        public async Task <ImmutableArray <SpellingFixResult> > FixProjectAsync(
            Project project,
            CancellationToken cancellationToken = default)
        {
            project = CurrentSolution.GetProject(project.Id);

            ISpellingService service = MefWorkspaceServices.Default.GetService <ISpellingService>(project.Language);

            if (service == null)
            {
                return(ImmutableArray <SpellingFixResult> .Empty);
            }

            ImmutableArray <Diagnostic> previousDiagnostics         = ImmutableArray <Diagnostic> .Empty;
            ImmutableArray <Diagnostic> previousPreviousDiagnostics = ImmutableArray <Diagnostic> .Empty;

            ImmutableArray <SpellingFixResult> .Builder results = ImmutableArray.CreateBuilder <SpellingFixResult>();

            bool nonSymbolsFixed = (Options.ScopeFilter & (SpellingScopeFilter.NonSymbol)) == 0;

            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions(
                    options: default(AnalyzerOptions),
                    onAnalyzerException: default(Action <Exception, DiagnosticAnalyzer, Diagnostic>),
                    concurrentAnalysis: true,
                    logAnalyzerExecutionTime: false,
                    reportSuppressedDiagnostics: false);

                Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                DiagnosticAnalyzer analyzer = service.CreateAnalyzer(SpellingData, Options);

                var compilationWithAnalyzers = new CompilationWithAnalyzers(
                    compilation,
                    ImmutableArray.Create(analyzer),
                    compilationWithAnalyzersOptions);

                ImmutableArray <Diagnostic> diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false);

#if DEBUG
                foreach (IGrouping <Diagnostic, Diagnostic> grouping in diagnostics
                         .GroupBy(f => f, DiagnosticDeepEqualityComparer.Instance))
                {
                    using (IEnumerator <Diagnostic> en = grouping.GetEnumerator())
                    {
                        if (en.MoveNext() &&
                            en.MoveNext())
                        {
                            Debug.Fail(DiagnosticFormatter.FormatDiagnostic(en.Current));
                        }
                    }
                }
#endif
                int length = diagnostics.Length;

                if (length == 0)
                {
                    break;
                }

                if (length == previousDiagnostics.Length &&
                    !diagnostics.Except(previousDiagnostics, DiagnosticDeepEqualityComparer.Instance).Any())
                {
                    break;
                }

                if (length == previousPreviousDiagnostics.Length &&
                    !diagnostics.Except(previousPreviousDiagnostics, DiagnosticDeepEqualityComparer.Instance).Any())
                {
                    LogHelpers.WriteInfiniteLoopSummary(diagnostics, previousDiagnostics, project, FormatProvider);
                    break;
                }

                var spellingDiagnostics = new List <SpellingDiagnostic>();

                foreach (Diagnostic diagnostic in diagnostics)
                {
                    Debug.Assert(diagnostic.Id == CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo, diagnostic.Id);

                    if (diagnostic.Id != CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo)
                    {
                        if (diagnostic.IsAnalyzerExceptionDiagnostic())
                        {
                            LogHelpers.WriteDiagnostic(diagnostic, baseDirectoryPath: Path.GetDirectoryName(project.FilePath), formatProvider: FormatProvider, indentation: "  ", verbosity: Verbosity.Detailed);
                        }

                        continue;
                    }

                    SpellingDiagnostic spellingDiagnostic = service.CreateSpellingDiagnostic(diagnostic);

                    spellingDiagnostics.Add(spellingDiagnostic);
                }

                if (!nonSymbolsFixed)
                {
                    List <SpellingFixResult> commentResults = await FixCommentsAsync(project, spellingDiagnostics, cancellationToken).ConfigureAwait(false);

                    results.AddRange(commentResults);
                    nonSymbolsFixed = true;
                }

                if ((Options.ScopeFilter & SpellingScopeFilter.Symbol) == 0)
                {
                    break;
                }

                (List <SpellingFixResult> symbolResults, bool allIgnored) = await FixSymbolsAsync(
                    project,
                    spellingDiagnostics,
                    service.SyntaxFacts,
                    cancellationToken)
                                                                            .ConfigureAwait(false);

                results.AddRange(symbolResults);

                if (allIgnored)
                {
                    break;
                }

                if (Options.DryRun)
                {
                    break;
                }

                project = CurrentSolution.GetProject(project.Id);

                previousPreviousDiagnostics = previousDiagnostics;
                previousDiagnostics         = diagnostics;
            }

            return(results.ToImmutableArray());
        }
예제 #8
0
        private async Task <(List <SpellingFixResult>, bool allIgnored)> FixSymbolsAsync(
            Project project,
            List <SpellingDiagnostic> spellingDiagnostics,
            ISyntaxFactsService syntaxFacts,
            CancellationToken cancellationToken)
        {
            var results    = new List <SpellingFixResult>();
            var allIgnored = true;

            List <(SyntaxToken identifier, List <SpellingDiagnostic> diagnostics, DocumentId documentId)> symbolDiagnostics = spellingDiagnostics
                                                                                                                              .Where(f => f.IsSymbol)
                                                                                                                              .GroupBy(f => f.Identifier)
                                                                                                                              .Select(f => (
                                                                                                                                          identifier: f.Key,
                                                                                                                                          diagnostics: f.OrderBy(f => f.Span.Start).ToList(),
                                                                                                                                          documentId: project.GetDocument(f.Key.SyntaxTree).Id))
                                                                                                                              .OrderBy(f => f.documentId.Id)
                                                                                                                              .ThenByDescending(f => f.identifier.SpanStart)
                                                                                                                              .ToList();

            for (int i = 0; i < symbolDiagnostics.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                (SyntaxToken identifier, List <SpellingDiagnostic> diagnostics, DocumentId documentId) = symbolDiagnostics[i];

                SyntaxNode node = null;

                foreach (SpellingDiagnostic diagnostic in diagnostics)
                {
                    if (diagnostic != null)
                    {
                        node = syntaxFacts.GetSymbolDeclaration(diagnostic.Identifier);
                        break;
                    }
                }

                if (node == null)
                {
                    continue;
                }

                Document document = project.GetDocument(documentId);

                if (document == null)
                {
                    Debug.Fail(identifier.GetLocation().ToString());

                    WriteLine($"    Cannot find document for '{identifier.ValueText}'", ConsoleColors.Yellow, Verbosity.Detailed);
                    continue;
                }

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

                if (identifier.SyntaxTree != root.SyntaxTree)
                {
                    SyntaxToken identifier2 = root.FindToken(identifier.SpanStart, findInsideTrivia: false);

                    if (identifier.Span != identifier2.Span ||
                        identifier.RawKind != identifier2.RawKind ||
                        !string.Equals(identifier.ValueText, identifier2.ValueText, StringComparison.Ordinal))
                    {
                        continue;
                    }

                    SyntaxNode node2 = identifier2.Parent;

                    SyntaxNode n = identifier.Parent;
                    while (n != node)
                    {
                        node2 = node2.Parent;
                        n     = n.Parent;
                    }

                    identifier = identifier2;
                    node       = node2;
                }

                SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                string sourceTextText = null;

                SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                ISymbol symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken)
                                 ?? semanticModel.GetSymbol(node, cancellationToken);

                if (symbol == null)
                {
                    // 8925 - C# tuple element
                    Debug.Assert(identifier.Parent.RawKind == 8925, identifier.ToString());

                    if (ShouldWrite(Verbosity.Detailed))
                    {
                        string message = $"    Cannot find symbol for '{identifier.ValueText}'";

                        string locationText = GetLocationText(identifier.GetLocation(), project);

                        if (locationText != null)
                        {
                            message += $" at {locationText}";
                        }

                        WriteLine(message, ConsoleColors.Yellow, Verbosity.Detailed);
                    }

                    continue;
                }

                if (!symbol.IsKind(SymbolKind.Namespace, SymbolKind.Alias) &&
                    !symbol.IsVisible(Options.SymbolVisibility))
                {
                    continue;
                }

                allIgnored = false;

                var    fixes       = new List <(SpellingDiagnostic diagnostic, SpellingFix fix)>();
                string newName     = identifier.ValueText;
                int    indexOffset = 0;

                for (int j = 0; j < diagnostics.Count; j++)
                {
                    SpellingDiagnostic diagnostic = diagnostics[j];

                    if (diagnostic == null)
                    {
                        continue;
                    }

                    LogHelpers.WriteSpellingDiagnostic(diagnostic, Options, sourceText, Path.GetDirectoryName(project.FilePath), "    ", Verbosity.Normal);

                    SpellingFix fix = GetFix(diagnostic);

                    if (!fix.IsDefault)
                    {
                        if (!string.Equals(diagnostic.Value, fix.Value, StringComparison.Ordinal))
                        {
                            WriteFix(diagnostic, fix);

                            fixes.Add((diagnostic, fix));

                            newName = TextUtility.ReplaceRange(newName, fix.Value, diagnostic.Offset + indexOffset, diagnostic.Length);

                            indexOffset += fix.Value.Length - diagnostic.Length;
                        }
                        else
                        {
                            for (int k = 0; k < symbolDiagnostics.Count; k++)
                            {
                                List <SpellingDiagnostic> diagnostics2 = symbolDiagnostics[k].diagnostics;

                                for (int l = 0; l < diagnostics2.Count; l++)
                                {
                                    if (SpellingData.IgnoredValues.KeyComparer.Equals(diagnostics2[l]?.Value, diagnostic.Value))
                                    {
                                        diagnostics2[l] = null;
                                    }
                                }
                            }

                            AddIgnoredValue(diagnostic);
                            AddResult(results, diagnostic, default(SpellingFix), sourceText, ref sourceTextText);
                        }
                    }
                    else
                    {
                        AddResult(results, diagnostic, default(SpellingFix), sourceText, ref sourceTextText);
                    }
                }

                if (string.Equals(identifier.Text, newName, StringComparison.Ordinal))
                {
                    continue;
                }

                Solution newSolution = null;
                if (!Options.DryRun)
                {
                    WriteLine($"    Rename '{identifier.ValueText}' to '{newName}'", ConsoleColors.Green, Verbosity.Minimal);

                    try
                    {
                        //TODO: detect naming conflict
                        newSolution = await Microsoft.CodeAnalysis.Rename.Renamer.RenameSymbolAsync(
                            CurrentSolution,
                            symbol,
                            newName,
                            default(Microsoft.CodeAnalysis.Options.OptionSet),
                            cancellationToken)
                                      .ConfigureAwait(false);
                    }
                    catch (InvalidOperationException
#if DEBUG
                           ex
#endif
                           )
                    {
                        WriteLine($"    Cannot rename '{symbol.Name}'", ConsoleColors.Yellow, Verbosity.Normal);
#if DEBUG
                        WriteLine(document.FilePath);
                        WriteLine(identifier.ValueText);
                        WriteLine(ex.ToString());
#endif
                        continue;
                    }
                }

                if (newSolution != null)
                {
                    if (Workspace.TryApplyChanges(newSolution))
                    {
                        project = CurrentSolution.GetProject(project.Id);
                    }
                    else
                    {
                        Debug.Fail($"Cannot apply changes to solution '{newSolution.FilePath}'");
                        WriteLine($"    Cannot apply changes to solution '{newSolution.FilePath}'", ConsoleColors.Yellow, Verbosity.Normal);
                        continue;
                    }
                }

                foreach ((SpellingDiagnostic diagnostic, SpellingFix fix) in fixes)
                {
                    AddResult(results, diagnostic, fix, sourceText, ref sourceTextText);

                    ProcessFix(diagnostic, fix);
                }
            }

            return(results, allIgnored);
예제 #9
0
 public static SpellingFixResult Create(string sourceText, SpellingDiagnostic diagnostic)
 {
     return(Create(sourceText, diagnostic, default));
 }