Skip to content

Commit

Permalink
Add inline code analyzers
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Sep 21, 2018
1 parent d33668c commit bcf0238
Show file tree
Hide file tree
Showing 20 changed files with 1,260 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,11 @@ public static XmlEmptyElementSyntax ParamRefElement(string parameterName)
return EmptyElement("paramref").AddAttributes(NameAttribute(parameterName));
}

public static XmlEmptyElementSyntax TypeParamRefElement(string parameterName)
{
return EmptyElement(XmlCommentHelper.TypeParamRefXmlTag).AddAttributes(NameAttribute(parameterName));
}

public static XmlEmptyElementSyntax SeeElement(CrefSyntax cref)
{
return EmptyElement("see").AddAttributes(CrefAttribute(cref));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.StyleRules
{
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using DocumentationAnalyzers.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC104CodeFixProvider))]
[Shared]
internal class DOC104CodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(DOC104UseSeeLangword.DiagnosticId);

public override FixAllProvider GetFixAllProvider()
=> CustomFixAllProviders.BatchFixer;

public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
{
continue;
}

context.RegisterCodeFix(
CodeAction.Create(
StyleResources.DOC104CodeFix,
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
nameof(DOC104CodeFixProvider)),
diagnostic);
}

return SpecializedTasks.CompletedTask;
}

private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);

var newXmlElement = XmlSyntaxFactory.EmptyElement(XmlCommentHelper.SeeXmlTag)
.AddAttributes(XmlSyntaxFactory.TextAttribute("langword", xmlElement.Content.ToFullString()))
.WithTriviaFrom(xmlElement);

return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.StyleRules
{
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using DocumentationAnalyzers.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC105CodeFixProvider))]
[Shared]
internal class DOC105CodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(DOC105UseParamref.DiagnosticId);

public override FixAllProvider GetFixAllProvider()
=> CustomFixAllProviders.BatchFixer;

public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
{
continue;
}

context.RegisterCodeFix(
CodeAction.Create(
StyleResources.DOC105CodeFix,
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
nameof(DOC105CodeFixProvider)),
diagnostic);
}

return SpecializedTasks.CompletedTask;
}

private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);

var newXmlElement = XmlSyntaxFactory.ParamRefElement(xmlElement.Content.ToFullString()).WithTriviaFrom(xmlElement);

return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.StyleRules
{
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using DocumentationAnalyzers.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC106CodeFixProvider))]
[Shared]
internal class DOC106CodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(DOC106UseTypeparamref.DiagnosticId);

public override FixAllProvider GetFixAllProvider()
=> CustomFixAllProviders.BatchFixer;

public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
{
continue;
}

context.RegisterCodeFix(
CodeAction.Create(
StyleResources.DOC106CodeFix,
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
nameof(DOC106CodeFixProvider)),
diagnostic);
}

return SpecializedTasks.CompletedTask;
}

private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);

var newXmlElement = XmlSyntaxFactory.TypeParamRefElement(xmlElement.Content.ToFullString()).WithTriviaFrom(xmlElement);

return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.StyleRules
{
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using DocumentationAnalyzers.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC107CodeFixProvider))]
[Shared]
internal class DOC107CodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(DOC107UseSeeCref.DiagnosticId);

public override FixAllProvider GetFixAllProvider()
=> CustomFixAllProviders.BatchFixer;

public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
{
continue;
}

context.RegisterCodeFix(
CodeAction.Create(
StyleResources.DOC107CodeFix,
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
nameof(DOC107CodeFixProvider)),
diagnostic);
}

return SpecializedTasks.CompletedTask;
}

private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);

var newXmlElement = XmlSyntaxFactory.EmptyElement(XmlCommentHelper.SeeXmlTag)
.AddAttributes(XmlSyntaxFactory.TextAttribute("cref", xmlElement.Content.ToFullString()))
.WithTriviaFrom(xmlElement);

return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
{
using DocumentationAnalyzers.Test.StyleRules;

public class DOC104CSharp7UnitTests : DOC104UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
{
using DocumentationAnalyzers.Test.StyleRules;

public class DOC105CSharp7UnitTests : DOC105UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
{
using DocumentationAnalyzers.Test.StyleRules;

public class DOC106CSharp7UnitTests : DOC106UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
{
using DocumentationAnalyzers.Test.StyleRules;

public class DOC107CSharp7UnitTests : DOC107UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT license. See LICENSE in the project root for license information.

namespace DocumentationAnalyzers.Test.StyleRules
{
using System.Threading.Tasks;
using DocumentationAnalyzers.StyleRules;
using Xunit;
using Verify = Microsoft.CodeAnalysis.CSharp.Testing.CSharpCodeFixVerifier<DocumentationAnalyzers.StyleRules.DOC104UseSeeLangword, DocumentationAnalyzers.StyleRules.DOC104CodeFixProvider, Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier>;

/// <summary>
/// This class contains unit tests for <see cref="DOC104UseSeeLangword"/>.
/// </summary>
public class DOC104UnitTests
{
[Theory]
[InlineData("null")]
[InlineData("static")]
[InlineData("virtual")]
[InlineData("true")]
[InlineData("false")]
[InlineData("abstract")]
[InlineData("sealed")]
[InlineData("async")]
[InlineData("await")]
public async Task TestRecognizedKeywordAsync(string keyword)
{
var testCode = $@"
/// <summary>
/// The keyword is [|<c>{keyword}</c>|].
/// </summary>
class TestClass
{{
}}
";
var fixedCode = $@"
/// <summary>
/// The keyword is <see langword=""{keyword}""/>.
/// </summary>
class TestClass
{{
}}
";

await Verify.VerifyCodeFixAsync(testCode, fixedCode);
}

[Theory]
[InlineData("public")]
public async Task TestNonKeywordsAsync(string keyword)
{
var testCode = $@"
/// <summary>
/// The keyword is <c>{keyword}</c>.
/// </summary>
class TestClass
{{
}}
";

await Verify.VerifyAnalyzerAsync(testCode);
}
}
}
Loading

0 comments on commit bcf0238

Please sign in to comment.