internal static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, FormatterState formatterState, DiagnosticDescriptor descriptor, OptionSet options) { var tree = context.Tree; var cancellationToken = context.CancellationToken; var oldText = tree.GetText(cancellationToken); var formattingChanges = Formatter.GetFormattedTextChanges(tree.GetRoot(cancellationToken), formatterState, options, cancellationToken); // formattingChanges could include changes that impact a larger section of the original document than // necessary. Before reporting diagnostics, process the changes to minimize the span of individual // diagnostics. foreach (var formattingChange in formattingChanges) { var change = formattingChange; if (change.NewText.Length > 0 && !change.Span.IsEmpty) { // Handle cases where the change is a substring removal from the beginning. In these cases, we want // the diagnostic span to cover the unwanted leading characters (which should be removed), and // nothing more. var offset = change.Span.Length - change.NewText.Length; if (offset >= 0) { if (oldText.GetSubText(new TextSpan(change.Span.Start + offset, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) { change = new TextChange(new TextSpan(change.Span.Start, offset), ""); } else { // Handle cases where the change is a substring removal from the end. In these cases, we want // the diagnostic span to cover the unwanted trailing characters (which should be removed), and // nothing more. if (oldText.GetSubText(new TextSpan(change.Span.Start, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) { change = new TextChange(new TextSpan(change.Span.Start + change.NewText.Length, offset), ""); } } } } if (change.NewText.Length == 0 && change.Span.IsEmpty) { // No actual change (allows for the formatter to report a NOP change without triggering a // diagnostic that can't be fixed). continue; } var location = Location.Create(tree, change.Span); context.ReportDiagnostic(Diagnostic.Create( descriptor, location, additionalLocations: null, properties: null)); } }
internal static async Task <SyntaxTree> FixOneAsync(SyntaxTree syntaxTree, FormatterState formatterState, OptionSet options, Diagnostic diagnostic, CancellationToken cancellationToken) { // The span to format is the full line(s) containing the diagnostic var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var diagnosticSpan = diagnostic.Location.SourceSpan; var diagnosticLinePositionSpan = text.Lines.GetLinePositionSpan(diagnosticSpan); var spanToFormat = TextSpan.FromBounds( text.Lines[diagnosticLinePositionSpan.Start.Line].Start, text.Lines[diagnosticLinePositionSpan.End.Line].End); var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); #if CODE_STYLE var formattedRoot = Formatter.Format(root, formatterState, new[] { spanToFormat }, options, Formatter.GetDefaultFormattingRules(formatterState), cancellationToken); #else var formattedRoot = Formatter.Format(root, spanToFormat, formatterState, options, cancellationToken); #endif return(syntaxTree.WithRootAndOptions(formattedRoot, syntaxTree.Options)); }