Skip to content

Commit

Permalink
Merge pull request DotNetAnalyzers#2070 from vweijsters/fix-1986
Browse files Browse the repository at this point in the history
Implemented single pass fix all for SA1651
  • Loading branch information
sharwell committed Mar 8, 2016
2 parents 9079623 + 310a979 commit 937f10d
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

namespace StyleCop.Analyzers.DocumentationRules
{
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

/// <summary>
Expand All @@ -24,14 +27,16 @@ namespace StyleCop.Analyzers.DocumentationRules
[Shared]
internal class SA1651CodeFixProvider : CodeFixProvider
{
private static readonly SyntaxAnnotation NodeToReplaceAnnotation = new SyntaxAnnotation(nameof(NodeToReplaceAnnotation));

/// <inheritdoc/>
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
ImmutableArray.Create(SA1651DoNotUsePlaceholderElements.DiagnosticId);

/// <inheritdoc/>
public override FixAllProvider GetFixAllProvider()
{
return CustomFixAllProviders.BatchFixer;
return FixAll.Instance;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -68,13 +73,9 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}
}

private async Task<Document> GetTransformedDocumentAsync(Document document, XmlElementSyntax elementSyntax, CancellationToken cancellationToken)
private static IEnumerable<XmlNodeSyntax> RemovePlaceHolder(XmlElementSyntax elementSyntax)
{
SyntaxList<XmlNodeSyntax> content = elementSyntax.Content;
if (content.Count == 0)
{
return document;
}

var leadingTrivia = elementSyntax.StartTag.GetLeadingTrivia();
leadingTrivia = leadingTrivia.AddRange(elementSyntax.StartTag.GetTrailingTrivia());
Expand All @@ -86,9 +87,77 @@ private async Task<Document> GetTransformedDocumentAsync(Document document, XmlE
trailingTrivia = trailingTrivia.AddRange(elementSyntax.EndTag.GetTrailingTrivia());
content = content.Replace(content[content.Count - 1], content[content.Count - 1].WithTrailingTrivia(trailingTrivia));

return content;
}

private async Task<Document> GetTransformedDocumentAsync(Document document, XmlElementSyntax elementSyntax, CancellationToken cancellationToken)
{
if (elementSyntax.Content.Count == 0)
{
return document;
}

SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
SyntaxNode newRoot = root.ReplaceNode(elementSyntax, content);
SyntaxNode newRoot = root.ReplaceNode(elementSyntax, RemovePlaceHolder(elementSyntax));
return document.WithSyntaxRoot(newRoot);
}

private class FixAll : DocumentBasedFixAllProvider
{
public static FixAll Instance { get; } = new FixAll();

protected override string CodeActionTitle { get; } = DocumentationResources.SA1651CodeFix;

protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document, ImmutableArray<Diagnostic> diagnostics)
{
var syntaxRoot = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
var elements = new List<XmlElementSyntax>();

foreach (var diagnostic in diagnostics)
{
var xmlElement = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true) as XmlElementSyntax;

if ((xmlElement != null)
&& (xmlElement.Content.Count > 0)
&& !string.IsNullOrWhiteSpace(xmlElement.Content.ToString()))
{
elements.Add(xmlElement);
}
}

var newSyntaxRoot = syntaxRoot.ReplaceNodes(elements, (original, rewritten) => rewritten.WithAdditionalAnnotations(NodeToReplaceAnnotation));
newSyntaxRoot = new FixAllVisitor().Visit(newSyntaxRoot);
return newSyntaxRoot;
}
}

private class FixAllVisitor : CSharpSyntaxRewriter
{
public FixAllVisitor()
: base(true)
{
}

public override SyntaxList<TNode> VisitList<TNode>(SyntaxList<TNode> list)
{
list = base.VisitList(list);

var index = 0;
while (index < list.Count)
{
var element = list[index];
if (element.HasAnnotation(NodeToReplaceAnnotation))
{
list = list.ReplaceRange(element, RemovePlaceHolder(element as XmlElementSyntax).Cast<TNode>());
}
else
{
index++;
}
}

return list;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public class ClassName

await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
}

protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
Expand Down

0 comments on commit 937f10d

Please sign in to comment.