Skip to content

Commit 459f7a9

Browse files
committed
Better handle wrong see tags
1 parent ce42508 commit 459f7a9

3 files changed

Lines changed: 70 additions & 18 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1642UnitTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,15 +411,14 @@ internal abstract class CustomizableBlockSubscriberBase<TSource, TTarget, TSubsc
411411
{
412412
/// <summary>
413413
/// Initializes a new instance of the <see cref=""CustomizableBlockSubscriberBase{TSource, TTarget, TSubscribedElement}""/> class.
414-
/// Initializes a new instance of the <see cref=""ProjectBuildSnapshotService""/> class.
415414
/// </summary>
416415
protected CustomizableBlockSubscriberBase()
417416
{
418417
}
419418
}
420419
";
421420

422-
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(6, 9);
421+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 43);
423422
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
424423
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
425424
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
@@ -592,7 +591,8 @@ private async Task TestConstructorSimpleDocumentationAsync(string typeKind, stri
592591

593592
await this.VerifyCSharpDiagnosticAsync(
594593
testCode,
595-
expected, CancellationToken.None).ConfigureAwait(false);
594+
expected,
595+
CancellationToken.None).ConfigureAwait(false);
596596

597597
var fixedCode = @"namespace FooNamespace
598598
{{
@@ -637,7 +637,8 @@ private async Task TestConstructorSimpleDocumentationWrongTypeNameAsync(string t
637637

638638
await this.VerifyCSharpDiagnosticAsync(
639639
testCode,
640-
expected, CancellationToken.None).ConfigureAwait(false);
640+
expected,
641+
CancellationToken.None).ConfigureAwait(false);
641642

642643
var fixedCode = @"namespace FooNamespace
643644
{{

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1642SA1643CodeFixProvider.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,19 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
5454
continue;
5555
}
5656

57-
var node = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true) as XmlElementSyntax;
58-
if (node == null)
57+
var node = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true) as XmlNodeSyntax;
58+
59+
var xmlElementSyntax = node as XmlElementSyntax;
60+
61+
if (xmlElementSyntax != null)
5962
{
60-
continue;
63+
context.RegisterCodeFix(CodeAction.Create(DocumentationResources.SA1642SA1643CodeFix, token => GetTransformedDocumentAsync(context.Document, root, xmlElementSyntax), equivalenceKey: nameof(SA1642SA1643CodeFixProvider)), diagnostic);
64+
}
65+
else
66+
{
67+
var xmlEmptyElementSyntax = node as XmlEmptyElementSyntax;
68+
context.RegisterCodeFix(CodeAction.Create(DocumentationResources.SA1642SA1643CodeFix, token => GetTransformedDocumentAsync(context.Document, root, xmlEmptyElementSyntax), equivalenceKey: nameof(SA1642SA1643CodeFixProvider)), diagnostic);
6169
}
62-
63-
context.RegisterCodeFix(CodeAction.Create(DocumentationResources.SA1642SA1643CodeFix, token => GetTransformedDocumentAsync(context.Document, root, node), equivalenceKey: nameof(SA1642SA1643CodeFixProvider)), diagnostic);
6470
}
6571
}
6672

@@ -136,6 +142,30 @@ private static Task<Document> GetTransformedDocumentAsync(Document document, Syn
136142
return Task.FromResult(newDocument);
137143
}
138144

145+
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlEmptyElementSyntax node)
146+
{
147+
var typeDeclaration = node.FirstAncestorOrSelf<BaseTypeDeclarationSyntax>();
148+
var declarationSyntax = node.FirstAncestorOrSelf<BaseMethodDeclarationSyntax>();
149+
bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration);
150+
151+
TypeParameterListSyntax typeParameterList;
152+
ClassDeclarationSyntax classDeclaration = typeDeclaration as ClassDeclarationSyntax;
153+
if (classDeclaration != null)
154+
{
155+
typeParameterList = classDeclaration.TypeParameterList;
156+
}
157+
else
158+
{
159+
typeParameterList = (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList;
160+
}
161+
162+
var newRoot = root.ReplaceNode(node, BuildSeeElement(typeDeclaration.Identifier, typeParameterList));
163+
164+
var newDocument = document.WithSyntaxRoot(newRoot);
165+
166+
return Task.FromResult(newDocument);
167+
}
168+
139169
private static SyntaxList<XmlNodeSyntax> RemoveMalformattedStandardText(SyntaxList<XmlNodeSyntax> content, SyntaxToken identifier, string preText, string postText, ref string trailingString)
140170
{
141171
var regex = new Regex(@"^\s*" + Regex.Escape(preText) + "[^ ]+" + Regex.Escape(postText));
@@ -208,6 +238,15 @@ private static SyntaxList<XmlNodeSyntax> RemoveMalformattedStandardText(SyntaxLi
208238
}
209239

210240
private static SyntaxList<XmlNodeSyntax> BuildStandardText(SyntaxToken identifier, TypeParameterListSyntax typeParameters, string newLineText, string preText, string postText)
241+
{
242+
return XmlSyntaxFactory.List(
243+
XmlSyntaxFactory.NewLine(newLineText),
244+
XmlSyntaxFactory.Text(preText),
245+
BuildSeeElement(identifier, typeParameters),
246+
XmlSyntaxFactory.Text(postText.EndsWith(".") ? postText : (postText + ".")));
247+
}
248+
249+
private static XmlEmptyElementSyntax BuildSeeElement(SyntaxToken identifier, TypeParameterListSyntax typeParameters)
211250
{
212251
TypeSyntax identifierName;
213252

@@ -221,11 +260,7 @@ private static SyntaxList<XmlNodeSyntax> BuildStandardText(SyntaxToken identifie
221260
identifierName = SyntaxFactory.GenericName(identifier.WithoutTrivia(), ParameterToArgumentListSyntax(typeParameters));
222261
}
223262

224-
return XmlSyntaxFactory.List(
225-
XmlSyntaxFactory.NewLine(newLineText),
226-
XmlSyntaxFactory.Text(preText),
227-
XmlSyntaxFactory.SeeElement(SyntaxFactory.TypeCref(identifierName)),
228-
XmlSyntaxFactory.Text(postText.EndsWith(".") ? postText : (postText + ".")));
263+
return XmlSyntaxFactory.SeeElement(SyntaxFactory.TypeCref(identifierName));
229264
}
230265

231266
private static TypeArgumentListSyntax ParameterToArgumentListSyntax(TypeParameterListSyntax typeParameters)

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/StandardTextDiagnosticBase.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ public enum MatchResult
3131
/// </summary>
3232
None,
3333

34+
/// <summary>
35+
/// A standard text was found but the see element was incorrect.
36+
/// </summary>
37+
InvalidSeeTag,
38+
3439
/// <summary>
3540
/// A match to the expected text was found.
3641
/// </summary>
@@ -75,11 +80,22 @@ protected static MatchResult HandleDeclaration(SyntaxNodeAnalysisContext context
7580

7681
if (firstTextPartSyntax != null && classReferencePart != null && secondTextParSyntaxt != null)
7782
{
78-
if (TextPartsMatch(firstTextPart, secondTextPart, firstTextPartSyntax, secondTextParSyntaxt)
79-
&& SeeTagIsCorrect(context, classReferencePart, declarationSyntax))
83+
if (TextPartsMatch(firstTextPart, secondTextPart, firstTextPartSyntax, secondTextParSyntaxt))
8084
{
81-
// We found a correct standard text
82-
return MatchResult.FoundMatch;
85+
if (SeeTagIsCorrect(context, classReferencePart, declarationSyntax))
86+
{
87+
// We found a correct standard text
88+
return MatchResult.FoundMatch;
89+
}
90+
else
91+
{
92+
if (diagnosticDescriptor != null)
93+
{
94+
context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, classReferencePart.GetLocation()));
95+
}
96+
97+
return MatchResult.None;
98+
}
8399
}
84100
}
85101
}

0 commit comments

Comments
 (0)