Skip to content

Commit bcf0238

Browse files
committed
Add inline code analyzers
Closes #5 Closes #15 Closes #24 Closes #25
1 parent d33668c commit bcf0238

File tree

20 files changed

+1260
-0
lines changed

20 files changed

+1260
-0
lines changed

DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/Helpers/XmlSyntaxFactory.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,11 @@ public static XmlEmptyElementSyntax ParamRefElement(string parameterName)
268268
return EmptyElement("paramref").AddAttributes(NameAttribute(parameterName));
269269
}
270270

271+
public static XmlEmptyElementSyntax TypeParamRefElement(string parameterName)
272+
{
273+
return EmptyElement(XmlCommentHelper.TypeParamRefXmlTag).AddAttributes(NameAttribute(parameterName));
274+
}
275+
271276
public static XmlEmptyElementSyntax SeeElement(CrefSyntax cref)
272277
{
273278
return EmptyElement("see").AddAttributes(CrefAttribute(cref));
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.StyleRules
5+
{
6+
using System.Collections.Immutable;
7+
using System.Composition;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using DocumentationAnalyzers.Helpers;
11+
using Microsoft.CodeAnalysis;
12+
using Microsoft.CodeAnalysis.CodeActions;
13+
using Microsoft.CodeAnalysis.CodeFixes;
14+
using Microsoft.CodeAnalysis.CSharp.Syntax;
15+
16+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC104CodeFixProvider))]
17+
[Shared]
18+
internal class DOC104CodeFixProvider : CodeFixProvider
19+
{
20+
public override ImmutableArray<string> FixableDiagnosticIds { get; }
21+
= ImmutableArray.Create(DOC104UseSeeLangword.DiagnosticId);
22+
23+
public override FixAllProvider GetFixAllProvider()
24+
=> CustomFixAllProviders.BatchFixer;
25+
26+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
27+
{
28+
foreach (var diagnostic in context.Diagnostics)
29+
{
30+
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
31+
{
32+
continue;
33+
}
34+
35+
context.RegisterCodeFix(
36+
CodeAction.Create(
37+
StyleResources.DOC104CodeFix,
38+
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
39+
nameof(DOC104CodeFixProvider)),
40+
diagnostic);
41+
}
42+
43+
return SpecializedTasks.CompletedTask;
44+
}
45+
46+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
47+
{
48+
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
49+
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
50+
51+
var newXmlElement = XmlSyntaxFactory.EmptyElement(XmlCommentHelper.SeeXmlTag)
52+
.AddAttributes(XmlSyntaxFactory.TextAttribute("langword", xmlElement.Content.ToFullString()))
53+
.WithTriviaFrom(xmlElement);
54+
55+
return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
56+
}
57+
}
58+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.StyleRules
5+
{
6+
using System.Collections.Immutable;
7+
using System.Composition;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using DocumentationAnalyzers.Helpers;
11+
using Microsoft.CodeAnalysis;
12+
using Microsoft.CodeAnalysis.CodeActions;
13+
using Microsoft.CodeAnalysis.CodeFixes;
14+
using Microsoft.CodeAnalysis.CSharp.Syntax;
15+
16+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC105CodeFixProvider))]
17+
[Shared]
18+
internal class DOC105CodeFixProvider : CodeFixProvider
19+
{
20+
public override ImmutableArray<string> FixableDiagnosticIds { get; }
21+
= ImmutableArray.Create(DOC105UseParamref.DiagnosticId);
22+
23+
public override FixAllProvider GetFixAllProvider()
24+
=> CustomFixAllProviders.BatchFixer;
25+
26+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
27+
{
28+
foreach (var diagnostic in context.Diagnostics)
29+
{
30+
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
31+
{
32+
continue;
33+
}
34+
35+
context.RegisterCodeFix(
36+
CodeAction.Create(
37+
StyleResources.DOC105CodeFix,
38+
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
39+
nameof(DOC105CodeFixProvider)),
40+
diagnostic);
41+
}
42+
43+
return SpecializedTasks.CompletedTask;
44+
}
45+
46+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
47+
{
48+
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
49+
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
50+
51+
var newXmlElement = XmlSyntaxFactory.ParamRefElement(xmlElement.Content.ToFullString()).WithTriviaFrom(xmlElement);
52+
53+
return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
54+
}
55+
}
56+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.StyleRules
5+
{
6+
using System.Collections.Immutable;
7+
using System.Composition;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using DocumentationAnalyzers.Helpers;
11+
using Microsoft.CodeAnalysis;
12+
using Microsoft.CodeAnalysis.CodeActions;
13+
using Microsoft.CodeAnalysis.CodeFixes;
14+
using Microsoft.CodeAnalysis.CSharp.Syntax;
15+
16+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC106CodeFixProvider))]
17+
[Shared]
18+
internal class DOC106CodeFixProvider : CodeFixProvider
19+
{
20+
public override ImmutableArray<string> FixableDiagnosticIds { get; }
21+
= ImmutableArray.Create(DOC106UseTypeparamref.DiagnosticId);
22+
23+
public override FixAllProvider GetFixAllProvider()
24+
=> CustomFixAllProviders.BatchFixer;
25+
26+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
27+
{
28+
foreach (var diagnostic in context.Diagnostics)
29+
{
30+
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
31+
{
32+
continue;
33+
}
34+
35+
context.RegisterCodeFix(
36+
CodeAction.Create(
37+
StyleResources.DOC106CodeFix,
38+
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
39+
nameof(DOC106CodeFixProvider)),
40+
diagnostic);
41+
}
42+
43+
return SpecializedTasks.CompletedTask;
44+
}
45+
46+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
47+
{
48+
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
49+
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
50+
51+
var newXmlElement = XmlSyntaxFactory.TypeParamRefElement(xmlElement.Content.ToFullString()).WithTriviaFrom(xmlElement);
52+
53+
return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
54+
}
55+
}
56+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.StyleRules
5+
{
6+
using System.Collections.Immutable;
7+
using System.Composition;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using DocumentationAnalyzers.Helpers;
11+
using Microsoft.CodeAnalysis;
12+
using Microsoft.CodeAnalysis.CodeActions;
13+
using Microsoft.CodeAnalysis.CodeFixes;
14+
using Microsoft.CodeAnalysis.CSharp.Syntax;
15+
16+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC107CodeFixProvider))]
17+
[Shared]
18+
internal class DOC107CodeFixProvider : CodeFixProvider
19+
{
20+
public override ImmutableArray<string> FixableDiagnosticIds { get; }
21+
= ImmutableArray.Create(DOC107UseSeeCref.DiagnosticId);
22+
23+
public override FixAllProvider GetFixAllProvider()
24+
=> CustomFixAllProviders.BatchFixer;
25+
26+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
27+
{
28+
foreach (var diagnostic in context.Diagnostics)
29+
{
30+
if (!FixableDiagnosticIds.Contains(diagnostic.Id))
31+
{
32+
continue;
33+
}
34+
35+
context.RegisterCodeFix(
36+
CodeAction.Create(
37+
StyleResources.DOC107CodeFix,
38+
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
39+
nameof(DOC107CodeFixProvider)),
40+
diagnostic);
41+
}
42+
43+
return SpecializedTasks.CompletedTask;
44+
}
45+
46+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
47+
{
48+
SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
49+
var xmlElement = (XmlElementSyntax)root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
50+
51+
var newXmlElement = XmlSyntaxFactory.EmptyElement(XmlCommentHelper.SeeXmlTag)
52+
.AddAttributes(XmlSyntaxFactory.TextAttribute("cref", xmlElement.Content.ToFullString()))
53+
.WithTriviaFrom(xmlElement);
54+
55+
return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement));
56+
}
57+
}
58+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
5+
{
6+
using DocumentationAnalyzers.Test.StyleRules;
7+
8+
public class DOC104CSharp7UnitTests : DOC104UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
5+
{
6+
using DocumentationAnalyzers.Test.StyleRules;
7+
8+
public class DOC105CSharp7UnitTests : DOC105UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
5+
{
6+
using DocumentationAnalyzers.Test.StyleRules;
7+
8+
public class DOC106CSharp7UnitTests : DOC106UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.Test.CSharp7.StyleRules
5+
{
6+
using DocumentationAnalyzers.Test.StyleRules;
7+
8+
public class DOC107CSharp7UnitTests : DOC107UnitTests
9+
{
10+
}
11+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.Test.StyleRules
5+
{
6+
using System.Threading.Tasks;
7+
using DocumentationAnalyzers.StyleRules;
8+
using Xunit;
9+
using Verify = Microsoft.CodeAnalysis.CSharp.Testing.CSharpCodeFixVerifier<DocumentationAnalyzers.StyleRules.DOC104UseSeeLangword, DocumentationAnalyzers.StyleRules.DOC104CodeFixProvider, Microsoft.CodeAnalysis.Testing.Verifiers.XUnitVerifier>;
10+
11+
/// <summary>
12+
/// This class contains unit tests for <see cref="DOC104UseSeeLangword"/>.
13+
/// </summary>
14+
public class DOC104UnitTests
15+
{
16+
[Theory]
17+
[InlineData("null")]
18+
[InlineData("static")]
19+
[InlineData("virtual")]
20+
[InlineData("true")]
21+
[InlineData("false")]
22+
[InlineData("abstract")]
23+
[InlineData("sealed")]
24+
[InlineData("async")]
25+
[InlineData("await")]
26+
public async Task TestRecognizedKeywordAsync(string keyword)
27+
{
28+
var testCode = $@"
29+
/// <summary>
30+
/// The keyword is [|<c>{keyword}</c>|].
31+
/// </summary>
32+
class TestClass
33+
{{
34+
}}
35+
";
36+
var fixedCode = $@"
37+
/// <summary>
38+
/// The keyword is <see langword=""{keyword}""/>.
39+
/// </summary>
40+
class TestClass
41+
{{
42+
}}
43+
";
44+
45+
await Verify.VerifyCodeFixAsync(testCode, fixedCode);
46+
}
47+
48+
[Theory]
49+
[InlineData("public")]
50+
public async Task TestNonKeywordsAsync(string keyword)
51+
{
52+
var testCode = $@"
53+
/// <summary>
54+
/// The keyword is <c>{keyword}</c>.
55+
/// </summary>
56+
class TestClass
57+
{{
58+
}}
59+
";
60+
61+
await Verify.VerifyAnalyzerAsync(testCode);
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)