diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/Helpers/XmlSyntaxFactory.cs b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/Helpers/XmlSyntaxFactory.cs index d54d27f..83eb116 100644 --- a/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/Helpers/XmlSyntaxFactory.cs +++ b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/Helpers/XmlSyntaxFactory.cs @@ -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)); diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC104CodeFixProvider.cs b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC104CodeFixProvider.cs new file mode 100644 index 0000000..e28f2ba --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC104CodeFixProvider.cs @@ -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.Diagnostics; + 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 FixableDiagnosticIds { get; } + = ImmutableArray.Create(DOC104UseSeeLangword.DiagnosticId); + + public override FixAllProvider GetFixAllProvider() + => CustomFixAllProviders.BatchFixer; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + foreach (var diagnostic in context.Diagnostics) + { + Debug.Assert(FixableDiagnosticIds.Contains(diagnostic.Id), "Assertion failed: FixableDiagnosticIds.Contains(diagnostic.Id)"); + + context.RegisterCodeFix( + CodeAction.Create( + StyleResources.DOC104CodeFix, + token => GetTransformedDocumentAsync(context.Document, diagnostic, token), + nameof(DOC104CodeFixProvider)), + diagnostic); + } + + return SpecializedTasks.CompletedTask; + } + + private static async Task 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)); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC105CodeFixProvider.cs b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC105CodeFixProvider.cs new file mode 100644 index 0000000..46289c8 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC105CodeFixProvider.cs @@ -0,0 +1,54 @@ +// 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.Diagnostics; + 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 FixableDiagnosticIds { get; } + = ImmutableArray.Create(DOC105UseParamref.DiagnosticId); + + public override FixAllProvider GetFixAllProvider() + => CustomFixAllProviders.BatchFixer; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + foreach (var diagnostic in context.Diagnostics) + { + Debug.Assert(FixableDiagnosticIds.Contains(diagnostic.Id), "Assertion failed: FixableDiagnosticIds.Contains(diagnostic.Id)"); + + context.RegisterCodeFix( + CodeAction.Create( + StyleResources.DOC105CodeFix, + token => GetTransformedDocumentAsync(context.Document, diagnostic, token), + nameof(DOC105CodeFixProvider)), + diagnostic); + } + + return SpecializedTasks.CompletedTask; + } + + private static async Task 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)); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC106CodeFixProvider.cs b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC106CodeFixProvider.cs new file mode 100644 index 0000000..dee37ef --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC106CodeFixProvider.cs @@ -0,0 +1,54 @@ +// 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.Diagnostics; + 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 FixableDiagnosticIds { get; } + = ImmutableArray.Create(DOC106UseTypeparamref.DiagnosticId); + + public override FixAllProvider GetFixAllProvider() + => CustomFixAllProviders.BatchFixer; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + foreach (var diagnostic in context.Diagnostics) + { + Debug.Assert(FixableDiagnosticIds.Contains(diagnostic.Id), "Assertion failed: FixableDiagnosticIds.Contains(diagnostic.Id)"); + + context.RegisterCodeFix( + CodeAction.Create( + StyleResources.DOC106CodeFix, + token => GetTransformedDocumentAsync(context.Document, diagnostic, token), + nameof(DOC106CodeFixProvider)), + diagnostic); + } + + return SpecializedTasks.CompletedTask; + } + + private static async Task 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)); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC107CodeFixProvider.cs b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC107CodeFixProvider.cs new file mode 100644 index 0000000..e2e9b90 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.CodeFixes/StyleRules/DOC107CodeFixProvider.cs @@ -0,0 +1,59 @@ +// 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.Diagnostics; + 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; + using Microsoft.CodeAnalysis.CSharp.Syntax; + + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DOC107CodeFixProvider))] + [Shared] + internal class DOC107CodeFixProvider : CodeFixProvider + { + public override ImmutableArray FixableDiagnosticIds { get; } + = ImmutableArray.Create(DOC107UseSeeCref.DiagnosticId); + + public override FixAllProvider GetFixAllProvider() + => CustomFixAllProviders.BatchFixer; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + foreach (var diagnostic in context.Diagnostics) + { + Debug.Assert(FixableDiagnosticIds.Contains(diagnostic.Id), "Assertion failed: FixableDiagnosticIds.Contains(diagnostic.Id)"); + + context.RegisterCodeFix( + CodeAction.Create( + StyleResources.DOC107CodeFix, + token => GetTransformedDocumentAsync(context.Document, diagnostic, token), + nameof(DOC107CodeFixProvider)), + diagnostic); + } + + return SpecializedTasks.CompletedTask; + } + + private static async Task 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", + SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.XmlTextLiteralToken, xmlElement.Content.ToFullString(), xmlElement.Content.ToFullString(), SyntaxTriviaList.Empty))) + .WithTriviaFrom(xmlElement); + + return document.WithSyntaxRoot(root.ReplaceNode(xmlElement, newXmlElement)); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC104CSharp7UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC104CSharp7UnitTests.cs new file mode 100644 index 0000000..0bac951 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC104CSharp7UnitTests.cs @@ -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 + { + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC105CSharp7UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC105CSharp7UnitTests.cs new file mode 100644 index 0000000..5c7822f --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC105CSharp7UnitTests.cs @@ -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 + { + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC106CSharp7UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC106CSharp7UnitTests.cs new file mode 100644 index 0000000..534a083 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC106CSharp7UnitTests.cs @@ -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 + { + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC107CSharp7UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC107CSharp7UnitTests.cs new file mode 100644 index 0000000..2120ea6 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test.CSharp7/StyleRules/DOC107CSharp7UnitTests.cs @@ -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 + { + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC104UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC104UnitTests.cs new file mode 100644 index 0000000..6a2886d --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC104UnitTests.cs @@ -0,0 +1,132 @@ +// 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; + + /// + /// This class contains unit tests for . + /// + 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 = $@" +/// +/// The keyword is [|{keyword}|]. +/// +class TestClass +{{ +}} +"; + var fixedCode = $@" +/// +/// The keyword is . +/// +class TestClass +{{ +}} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Theory] + [InlineData("public")] + public async Task TestNonKeywordsAsync(string keyword) + { + var testCode = $@" +/// +/// The keyword is {keyword}. +/// +class TestClass +{{ +}} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonDiagnosticPotentialCasesAsync() + { + // These cases could qualify for this diagnostic, but currently do not. + var testCode = @" +class TestClass +{ + /// + /// The keyword is await. + /// The keyword is true. + /// The keyword is true . + /// The keyword is true . + /// The keyword is true + /// . + /// The keyword is + /// true. + /// The keyword is + /// true + /// . + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonDiagnosticCasesAsync() + { + // These cases *shouldn't* qualify for this diagnostic. + var testCode = @" +class TestClass +{ + /// + /// The keyword is not-keyword. + /// The keyword is True. + /// The keyword is true>. + /// The keyword is >true. + /// The keyword is true. + /// The keyword is truetrue. + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonCodeAsync() + { + var testCode = @" +/// +/// The keyword is true. +/// +class TestClass +{ +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC105UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC105UnitTests.cs new file mode 100644 index 0000000..bd67324 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC105UnitTests.cs @@ -0,0 +1,173 @@ +// 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; + + /// + /// This class contains unit tests for . + /// + public class DOC105UnitTests + { + [Fact] + public async Task TestParameterNameAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a parameter [|a|]. + /// + void Method(int a) + { + } +} +"; + var fixedCode = @" +class TestClass +{ + /// + /// Consider a parameter . + /// + void Method(int a) + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestParameterNameEncodedAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a parameter [|a|]. + /// + void Method(int a) + { + } +} +"; + var fixedCode = @" +class TestClass +{ + /// + /// Consider a parameter . + /// + void Method(int a) + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestParameterNameMatchesKeywordAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider parameter [|true|]. + /// + void Method(int @true) + { + } +} +"; + var fixedCode = @" +class TestClass +{ + /// + /// Consider parameter . + /// + void Method(int @true) + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestNonDiagnosticPotentialCasesAsync() + { + // These cases could qualify for this diagnostic, but currently do not. + var testCode = @" +class TestClass +{ + /// + /// Consider a parameter a. + /// Consider a parameter a . + /// Consider a parameter a . + /// Consider a parameter a + /// . + /// Consider a parameter + /// a. + /// Consider a parameter + /// a + /// . + /// + void Method(int a) + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonDiagnosticCasesAsync() + { + // These cases *shouldn't* qualify for this diagnostic. + var testCode = @" +class TestClass +{ + /// + /// Consider a parameter b. + /// Consider a parameter A. + /// Consider a parameter a>. + /// Consider a parameter >a. + /// Consider a parameter a. + /// Consider a parameter aa. + /// + void Method(int a) + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonCodeAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a parameter a. + /// + void Method(int a) + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC106UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC106UnitTests.cs new file mode 100644 index 0000000..1ed2b6f --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC106UnitTests.cs @@ -0,0 +1,173 @@ +// 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; + + /// + /// This class contains unit tests for . + /// + public class DOC106UnitTests + { + [Fact] + public async Task TestTypeParameterNameAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a type parameter [|a|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + /// + /// Consider a type parameter . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestTypeParameterNameEncodedAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a type parameter [|a|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + /// + /// Consider a type parameter . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestTypeParameterNameMatchesKeywordAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider type parameter [|true|]. + /// + void Method<@true>() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + /// + /// Consider type parameter . + /// + void Method<@true>() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestNonDiagnosticPotentialCasesAsync() + { + // These cases could qualify for this diagnostic, but currently do not. + var testCode = @" +class TestClass +{ + /// + /// Consider a type parameter a. + /// Consider a type parameter a . + /// Consider a type parameter a . + /// Consider a type parameter a + /// . + /// Consider a type parameter + /// a. + /// Consider a type parameter + /// a + /// . + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonDiagnosticCasesAsync() + { + // These cases *shouldn't* qualify for this diagnostic. + var testCode = @" +class TestClass +{ + /// + /// Consider a type parameter b. + /// Consider a type parameter A. + /// Consider a type parameter a>. + /// Consider a type parameter >a. + /// Consider a type parameter a. + /// Consider a type parameter aa. + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonCodeAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a type parameter a. + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC107UnitTests.cs b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC107UnitTests.cs new file mode 100644 index 0000000..455f38c --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers.Test/StyleRules/DOC107UnitTests.cs @@ -0,0 +1,364 @@ +// 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; + + /// + /// This class contains unit tests for . + /// + public class DOC107UnitTests + { + [Fact] + public async Task TestPropertyNameAsync() + { + var testCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property [|a|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestPropertyNameEncodedAsync() + { + var testCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property [|a|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestFieldNameAsync() + { + var testCode = @" +class TestClass +{ + int a = 3; + + /// + /// Consider a member [|a|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + int a = 3; + + /// + /// Consider a member . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestEventNameAsync() + { + var testCode = @" +class TestClass +{ + event System.EventHandler a; + + /// + /// Consider a member [|a|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + event System.EventHandler a; + + /// + /// Consider a member . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestMethodNameAsync() + { + var testCode = @" +class TestClass +{ + int a() => 3; + + /// + /// Consider a member a. + /// + void Method() + { + } +} +"; + + // Methods are not currently checked + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestContainingNamespaceNameAsync() + { + var testCode = @" +namespace a +{ + class TestClass + { + /// + /// Consider a containing namespace a. + /// + void Method() + { + } + } +} +"; + + // Containing namespaces are not currently checked + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestContainingTypeNameAsync() + { + var testCode = @" +class a +{ + class TestClass + { + /// + /// Consider a containing type a. + /// + void Method() + { + } + } +} +"; + + // Containing types are not currently checked + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNestedTypeNameAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a nested type a. + /// + void Method() + { + } + + class a { } +} +"; + + // Nested types are not currently checked + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestSiblingTypeNameAsync() + { + var testCode = @" +class TestClass +{ + /// + /// Consider a type a. + /// + void Method() + { + } +} + +class a { } +"; + + // Types are not currently checked + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestPropertyNameMatchesKeywordAsync() + { + var testCode = @" +class TestClass +{ + int @true => 3; + + /// + /// Consider property [|true|]. + /// + void Method() + { + } +} +"; + var fixedCode = @" +class TestClass +{ + int @true => 3; + + /// + /// Consider property . + /// + void Method() + { + } +} +"; + + await Verify.VerifyCodeFixAsync(testCode, fixedCode); + } + + [Fact] + public async Task TestNonDiagnosticPotentialCasesAsync() + { + // These cases could qualify for this diagnostic, but currently do not. + var testCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property a. + /// Consider a property a . + /// Consider a property a . + /// Consider a property a + /// . + /// Consider a property + /// a. + /// Consider a property + /// a + /// . + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonDiagnosticCasesAsync() + { + // These cases *shouldn't* qualify for this diagnostic. + var testCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property b. + /// Consider a property A. + /// Consider a property a>. + /// Consider a property >a. + /// Consider a property a. + /// Consider a property aa. + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task TestNonCodeAsync() + { + var testCode = @" +class TestClass +{ + int a => 3; + + /// + /// Consider a property a. + /// + void Method() + { + } +} +"; + + await Verify.VerifyAnalyzerAsync(testCode); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC104UseSeeLangword.cs b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC104UseSeeLangword.cs new file mode 100644 index 0000000..74ef4dd --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC104UseSeeLangword.cs @@ -0,0 +1,70 @@ +// 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 Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class DOC104UseSeeLangword : InlineCodeAnalyzerBase + { + /// + /// The ID for diagnostics produced true by the analyzer. + /// + public const string DiagnosticId = "DOC104"; + private const string HelpLink = "https://github.com/DotNetAnalyzers/DocumentationAnalyzers/blob/master/docs/DOC104.md"; + + private static readonly LocalizableString Title = new LocalizableResourceString(nameof(StyleResources.DOC104Title), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(StyleResources.DOC104MessageFormat), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString Description = new LocalizableResourceString(nameof(StyleResources.DOC104Description), StyleResources.ResourceManager, typeof(StyleResources)); + + private static readonly DiagnosticDescriptor Descriptor = + new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.StyleRules, DiagnosticSeverity.Info, AnalyzerConstants.EnabledByDefault, Description, HelpLink); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(Descriptor); + + protected override void HandleInlineCodeElement(ref SyntaxNodeAnalysisContext context, XmlElementSyntax xmlElement) + { + // This rule will only apply if the content is a single XmlTextSyntax containing a single + // XmlTextLiteralToken token + if (xmlElement.Content.Count != 1) + { + return; + } + + if (!(xmlElement.Content[0] is XmlTextSyntax xmlText)) + { + return; + } + + if (xmlText.TextTokens.Count != 1) + { + return; + } + + switch (xmlText.TextTokens[0].ValueText) + { + case "null": + case "static": + case "virtual": + case "true": + case "false": + case "abstract": + case "sealed": + case "async": + case "await": + break; + + default: + return; + } + + context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElement.GetLocation())); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC105UseParamref.cs b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC105UseParamref.cs new file mode 100644 index 0000000..afbe30f --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC105UseParamref.cs @@ -0,0 +1,62 @@ +// 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; + using System.Collections.Immutable; + using DocumentationAnalyzers.Helpers; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class DOC105UseParamref : InlineCodeAnalyzerBase + { + /// + /// The ID for diagnostics produced by the analyzer. + /// + public const string DiagnosticId = "DOC105"; + private const string HelpLink = "https://github.com/DotNetAnalyzers/DocumentationAnalyzers/blob/master/docs/DOC105.md"; + + private static readonly LocalizableString Title = new LocalizableResourceString(nameof(StyleResources.DOC105Title), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(StyleResources.DOC105MessageFormat), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString Description = new LocalizableResourceString(nameof(StyleResources.DOC105Description), StyleResources.ResourceManager, typeof(StyleResources)); + + private static readonly DiagnosticDescriptor Descriptor = + new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.StyleRules, DiagnosticSeverity.Info, AnalyzerConstants.EnabledByDefault, Description, HelpLink); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(Descriptor); + + protected override void HandleInlineCodeElement(ref SyntaxNodeAnalysisContext context, XmlElementSyntax xmlElement) + { + // This rule will only apply if the content is a single XmlTextSyntax containing a single + // XmlTextLiteralToken token + if (xmlElement.Content.Count != 1) + { + return; + } + + if (!(xmlElement.Content[0] is XmlTextSyntax xmlText)) + { + return; + } + + if (xmlText.TextTokens.Count != 1) + { + return; + } + + var semanticModel = context.SemanticModel; + var documentedSymbol = semanticModel.GetDeclaredSymbol(xmlElement.FirstAncestorOrSelf(SyntaxNodeExtensionsEx.IsSymbolDeclaration), context.CancellationToken); + if (!documentedSymbol.HasAnyParameter(xmlText.TextTokens[0].ValueText, StringComparer.Ordinal)) + { + return; + } + + context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElement.GetLocation())); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC106UseTypeparamref.cs b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC106UseTypeparamref.cs new file mode 100644 index 0000000..ccd4dab --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC106UseTypeparamref.cs @@ -0,0 +1,62 @@ +// 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; + using System.Collections.Immutable; + using DocumentationAnalyzers.Helpers; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class DOC106UseTypeparamref : InlineCodeAnalyzerBase + { + /// + /// The ID for diagnostics produced by the analyzer. + /// + public const string DiagnosticId = "DOC106"; + private const string HelpLink = "https://github.com/DotNetAnalyzers/DocumentationAnalyzers/blob/master/docs/DOC106.md"; + + private static readonly LocalizableString Title = new LocalizableResourceString(nameof(StyleResources.DOC106Title), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(StyleResources.DOC106MessageFormat), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString Description = new LocalizableResourceString(nameof(StyleResources.DOC106Description), StyleResources.ResourceManager, typeof(StyleResources)); + + private static readonly DiagnosticDescriptor Descriptor = + new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.StyleRules, DiagnosticSeverity.Info, AnalyzerConstants.EnabledByDefault, Description, HelpLink); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(Descriptor); + + protected override void HandleInlineCodeElement(ref SyntaxNodeAnalysisContext context, XmlElementSyntax xmlElement) + { + // This rule will only apply if the content is a single XmlTextSyntax containing a single + // XmlTextLiteralToken token + if (xmlElement.Content.Count != 1) + { + return; + } + + if (!(xmlElement.Content[0] is XmlTextSyntax xmlText)) + { + return; + } + + if (xmlText.TextTokens.Count != 1) + { + return; + } + + var semanticModel = context.SemanticModel; + var documentedSymbol = semanticModel.GetDeclaredSymbol(xmlElement.FirstAncestorOrSelf(SyntaxNodeExtensionsEx.IsSymbolDeclaration), context.CancellationToken); + if (!documentedSymbol.HasAnyTypeParameter(xmlText.TextTokens[0].ValueText, StringComparer.Ordinal)) + { + return; + } + + context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElement.GetLocation())); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC107UseSeeCref.cs b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC107UseSeeCref.cs new file mode 100644 index 0000000..c1a5477 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/DOC107UseSeeCref.cs @@ -0,0 +1,85 @@ +// 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 DocumentationAnalyzers.Helpers; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class DOC107UseSeeCref : InlineCodeAnalyzerBase + { + /// + /// The ID for diagnostics produced by the analyzer. + /// + public const string DiagnosticId = "DOC107"; + private const string HelpLink = "https://github.com/DotNetAnalyzers/DocumentationAnalyzers/blob/master/docs/DOC107.md"; + + private static readonly LocalizableString Title = new LocalizableResourceString(nameof(StyleResources.DOC107Title), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(StyleResources.DOC107MessageFormat), StyleResources.ResourceManager, typeof(StyleResources)); + private static readonly LocalizableString Description = new LocalizableResourceString(nameof(StyleResources.DOC107Description), StyleResources.ResourceManager, typeof(StyleResources)); + + private static readonly DiagnosticDescriptor Descriptor = + new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.StyleRules, DiagnosticSeverity.Info, AnalyzerConstants.EnabledByDefault, Description, HelpLink); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(Descriptor); + + protected override void HandleInlineCodeElement(ref SyntaxNodeAnalysisContext context, XmlElementSyntax xmlElement) + { + // Currently this rule will only apply if the content is a single XmlTextSyntax containing a single + // XmlTextLiteralToken token + if (xmlElement.Content.Count != 1) + { + return; + } + + if (!(xmlElement.Content[0] is XmlTextSyntax xmlText)) + { + return; + } + + if (xmlText.TextTokens.Count != 1) + { + return; + } + + var semanticModel = context.SemanticModel; + var documentedSymbol = semanticModel.GetDeclaredSymbol(xmlElement.FirstAncestorOrSelf(SyntaxNodeExtensionsEx.IsSymbolDeclaration), context.CancellationToken); + var name = xmlText.TextTokens[0].ValueText; + for (var currentSymbol = documentedSymbol; currentSymbol != null; currentSymbol = currentSymbol?.ContainingSymbol) + { + switch (currentSymbol.Kind) + { + case SymbolKind.NamedType: + var namedType = (INamedTypeSymbol)currentSymbol; + var matchingMembers = namedType.GetMembers(name); + if (matchingMembers.Length != 1) + { + return; + } + + if (matchingMembers[0].Kind == SymbolKind.Property + || matchingMembers[0].Kind == SymbolKind.Field + || matchingMembers[0].Kind == SymbolKind.Event) + { + context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElement.GetLocation())); + } + + return; + + case SymbolKind.Namespace: + case SymbolKind.NetModule: + return; + + default: + continue; + } + } + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/InlineCodeAnalyzerBase.cs b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/InlineCodeAnalyzerBase.cs new file mode 100644 index 0000000..28a9791 --- /dev/null +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/InlineCodeAnalyzerBase.cs @@ -0,0 +1,45 @@ +// 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 DocumentationAnalyzers.Helpers; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + /// + /// This is the base class for diagnostic analyzers which report diagnostics for use of <c> which a + /// more appropriate inline element is available. + /// + internal abstract class InlineCodeAnalyzerBase : DiagnosticAnalyzer + { + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(HandleXmlElementSyntax, SyntaxKind.XmlElement); + } + + protected abstract void HandleInlineCodeElement(ref SyntaxNodeAnalysisContext context, XmlElementSyntax xmlElement); + + private void HandleXmlElementSyntax(SyntaxNodeAnalysisContext context) + { + var xmlElement = (XmlElementSyntax)context.Node; + var name = xmlElement.StartTag.Name; + if (name.Prefix != null) + { + return; + } + + if (name.LocalName.ValueText != XmlCommentHelper.CXmlTag) + { + return; + } + + HandleInlineCodeElement(ref context, xmlElement); + } + } +} diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.Designer.cs b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.Designer.cs index bdd33ea..d16c578 100644 --- a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.Designer.cs +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.Designer.cs @@ -187,6 +187,150 @@ internal static string DOC103Title { } } + /// + /// Looks up a localized string similar to Use 'see langword'. + /// + internal static string DOC104CodeFix { + get { + return ResourceManager.GetString("DOC104CodeFix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<see langword="keyword"/>' to '<c>keyword</c>' for referencing language keywords. + /// + internal static string DOC104Description { + get { + return ResourceManager.GetString("DOC104Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<see langword="keyword"/>' to '<c>keyword</c>' for referencing language keywords. + /// + internal static string DOC104MessageFormat { + get { + return ResourceManager.GetString("DOC104MessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'see langword'. + /// + internal static string DOC104Title { + get { + return ResourceManager.GetString("DOC104Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'paramref'. + /// + internal static string DOC105CodeFix { + get { + return ResourceManager.GetString("DOC105CodeFix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<paramref name="parameter"/>' to '<c>parameter</c>' for referencing parameters. + /// + internal static string DOC105Description { + get { + return ResourceManager.GetString("DOC105Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<paramref name="parameter"/>' to '<c>parameter</c>' for referencing parameters. + /// + internal static string DOC105MessageFormat { + get { + return ResourceManager.GetString("DOC105MessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'paramref'. + /// + internal static string DOC105Title { + get { + return ResourceManager.GetString("DOC105Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'typeparamref'. + /// + internal static string DOC106CodeFix { + get { + return ResourceManager.GetString("DOC106CodeFix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<typeparamref name="type_parameter"/>' to '<c>type_parameter</c>' for referencing type parameters. + /// + internal static string DOC106Description { + get { + return ResourceManager.GetString("DOC106Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<typeparamref name="type_parameter"/>' to '<c>type_parameter</c>' for referencing type parameters. + /// + internal static string DOC106MessageFormat { + get { + return ResourceManager.GetString("DOC106MessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'typeparamref'. + /// + internal static string DOC106Title { + get { + return ResourceManager.GetString("DOC106Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'see cref'. + /// + internal static string DOC107CodeFix { + get { + return ResourceManager.GetString("DOC107CodeFix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<see cref="target"/>' to '<c>target</c>' for referencing code elements. + /// + internal static string DOC107Description { + get { + return ResourceManager.GetString("DOC107Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefer '<see cref="target"/>' to '<c>target</c>' for referencing code elements. + /// + internal static string DOC107MessageFormat { + get { + return ResourceManager.GetString("DOC107MessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use 'see cref'. + /// + internal static string DOC107Title { + get { + return ResourceManager.GetString("DOC107Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to Wrap text in paragraph element. /// diff --git a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.resx b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.resx index cd7c46d..6d5f2b5 100644 --- a/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.resx +++ b/DocumentationAnalyzers/DocumentationAnalyzers/StyleRules/StyleResources.resx @@ -159,6 +159,54 @@ Use Unicode characters + + Use 'see langword' + + + Prefer '<see langword="keyword"/>' to '<c>keyword</c>' for referencing language keywords + + + Prefer '<see langword="keyword"/>' to '<c>keyword</c>' for referencing language keywords + + + Use 'see langword' + + + Use 'paramref' + + + Prefer '<paramref name="parameter"/>' to '<c>parameter</c>' for referencing parameters + + + Prefer '<paramref name="parameter"/>' to '<c>parameter</c>' for referencing parameters + + + Use 'paramref' + + + Use 'typeparamref' + + + Prefer '<typeparamref name="type_parameter"/>' to '<c>type_parameter</c>' for referencing type parameters + + + Prefer '<typeparamref name="type_parameter"/>' to '<c>type_parameter</c>' for referencing type parameters + + + Use 'typeparamref' + + + Use 'see cref' + + + Prefer '<see cref="target"/>' to '<c>target</c>' for referencing code elements + + + Prefer '<see cref="target"/>' to '<c>target</c>' for referencing code elements + + + Use 'see cref' + Wrap text in paragraph element diff --git a/docs/DOC104.md b/docs/DOC104.md new file mode 100644 index 0000000..fdf6777 --- /dev/null +++ b/docs/DOC104.md @@ -0,0 +1,61 @@ +# DOC104 + + + + + + + + + + + + + + +
TypeNameDOC104UseSeeLangword
CheckIdDOC104
CategoryStyle Rules
+ +## Cause + +The contains a language keyword reference using `keyword` that can be converted to the preferred form +``. + +## Rule description + +A violation of this rule occurs when documentation a language keyword reference written in inline code that can be +written in a preferred form using `see langword`. + +```csharp +/// +/// This type is sealed. +/// +public sealed class SomeType +{ +} +``` + +## How to fix violations + +To fix a violation of this rule, replace the inline code with the equivalent `see langword` syntax. + +```csharp +/// +/// This type is . +/// +public sealed class SomeType +{ +} +``` + +## How to suppress violations + +```csharp +#pragma warning disable DOC104 // Use 'see langword' +/// +/// This type is sealed. +/// +public sealed class SomeType +#pragma warning restore DOC104 // Use 'see langword' +{ +} +``` diff --git a/docs/DOC105.md b/docs/DOC105.md new file mode 100644 index 0000000..d744188 --- /dev/null +++ b/docs/DOC105.md @@ -0,0 +1,61 @@ +# DOC105 + + + + + + + + + + + + + + +
TypeNameDOC105UseParamref
CheckIdDOC105
CategoryStyle Rules
+ +## Cause + +The contains a parameter reference using `name` that can be converted to the preferred form +``. + +## Rule description + +A violation of this rule occurs when documentation contains a parameter reference written in inline code that can be +written in a preferred form using `paramref`. + +```csharp +/// +/// Pass in a value. +/// +public void Method(int value) +{ +} +``` + +## How to fix violations + +To fix a violation of this rule, replace the inline code with the equivalent `paramref` syntax. + +```csharp +/// +/// Pass in a . +/// +public void Method(int value) +{ +} +``` + +## How to suppress violations + +```csharp +#pragma warning disable DOC105 // Use 'paramref' +/// +/// Pass in a value. +/// +public void Method(int value) +#pragma warning restore DOC104 // Use 'paramref' +{ +} +``` diff --git a/docs/DOC106.md b/docs/DOC106.md new file mode 100644 index 0000000..ac8eb1d --- /dev/null +++ b/docs/DOC106.md @@ -0,0 +1,61 @@ +# DOC106 + + + + + + + + + + + + + + +
TypeNameDOC106UseTypeparamref
CheckIdDOC106
CategoryStyle Rules
+ +## Cause + +The contains a type parameter reference using `T` that can be converted to the preferred form +``. + +## Rule description + +A violation of this rule occurs when documentation contains a type parameter reference written in inline code that can +be written in a preferred form using `typeparamref`. + +```csharp +/// +/// Pass in a T. +/// +public void Method() +{ +} +``` + +## How to fix violations + +To fix a violation of this rule, replace the inline code with the equivalent `typeparamref` syntax. + +```csharp +/// +/// Pass in a . +/// +public void Method() +{ +} +``` + +## How to suppress violations + +```csharp +#pragma warning disable DOC106 // Use 'typeparamref' +/// +/// Pass in a T. +/// +public void Method() +#pragma warning restore DOC106 // Use 'typeparamref' +{ +} +``` diff --git a/docs/DOC107.md b/docs/DOC107.md new file mode 100644 index 0000000..777bd13 --- /dev/null +++ b/docs/DOC107.md @@ -0,0 +1,67 @@ +# DOC107 + + + + + + + + + + + + + + +
TypeNameDOC107UseSeeCref
CheckIdDOC107
CategoryStyle Rules
+ +## Cause + +The contains a code element reference using `name` that can be converted to the preferred form +``. + +## Rule description + +A violation of this rule occurs when documentation contains a code element reference written in inline code that can +be written in a preferred form using `see cref`. + +```csharp +int SomeValue { get; } + +/// +/// Depends on SomeValue. +/// +public void Method() +{ +} +``` + +## How to fix violations + +To fix a violation of this rule, replace the inline code with the equivalent `see cref` syntax. + +```csharp +int SomeValue { get; } + +/// +/// Depends on . +/// +public void Method() +{ +} +``` + +## How to suppress violations + +```csharp +int SomeValue { get; } + +#pragma warning disable DOC107 // Use 'see cref' +/// +/// Depends on SomeValue. +/// +public void Method() +#pragma warning restore DOC107 // Use 'see cref' +{ +} +``` diff --git a/docs/StyleRules.md b/docs/StyleRules.md index 5fea148..00bd71a 100644 --- a/docs/StyleRules.md +++ b/docs/StyleRules.md @@ -8,4 +8,8 @@ Identifier | Name | Description [DOC101](DOC101.md) | UseChildBlocksConsistently | The documentation for the element contains some text which is wrapped in block-level elements, and other text which is written inline. [DOC102](DOC102.md) | UseChildBlocksConsistentlyAcrossElementsOfTheSameKind | The documentation for the element contains inline text, but the documentation for a sibling element of the same kind uses block-level elements. [DOC103](DOC103.md) | UseUnicodeCharacters | The documentation contains an unnecessary or unrecognized HTML character entity. +[DOC104](DOC104.md) | UseSeeLangword | The contains a language keyword reference using `keyword` that can be converted to the preferred form ``. +[DOC105](DOC105.md) | UseParamref | The contains a parameter reference using `name` that can be converted to the preferred form ``. +[DOC106](DOC106.md) | UseTypeparamref | The contains a type parameter reference using `T` that can be converted to the preferred form ``. +[DOC107](DOC107.md) | UseSeeCref | The contains a code element reference using `name` that can be converted to the preferred form ``. [DOC108](DOC108.md) | AvoidEmptyParagraphs | The documentation contains an empty paragraph element (`` or `

`) used as a paragraph separator.