44namespace StyleCop . Analyzers . DocumentationRules
55{
66 using System ;
7+ using System . Collections . Generic ;
78 using System . Collections . Immutable ;
9+ using System . Linq ;
10+ using System . Xml . Linq ;
811 using Helpers ;
912 using Microsoft . CodeAnalysis ;
10- using Microsoft . CodeAnalysis . CSharp ;
1113 using Microsoft . CodeAnalysis . CSharp . Syntax ;
1214 using Microsoft . CodeAnalysis . Diagnostics ;
1315
@@ -26,7 +28,7 @@ namespace StyleCop.Analyzers.DocumentationRules
2628 /// which is missing a <c>name</c> attribute, or which contains an empty <c>name</c> attribute.</para>
2729 /// </remarks>
2830 [ DiagnosticAnalyzer ( LanguageNames . CSharp ) ]
29- internal class SA1613ElementParameterDocumentationMustDeclareParameterName : DiagnosticAnalyzer
31+ internal class SA1613ElementParameterDocumentationMustDeclareParameterName : ElementDocumentationParameterBase
3032 {
3133 /// <summary>
3234 /// The ID for diagnostics produced by the
@@ -41,55 +43,86 @@ internal class SA1613ElementParameterDocumentationMustDeclareParameterName : Dia
4143 private static readonly DiagnosticDescriptor Descriptor =
4244 new DiagnosticDescriptor ( DiagnosticId , Title , MessageFormat , AnalyzerCategory . DocumentationRules , DiagnosticSeverity . Warning , AnalyzerConstants . EnabledByDefault , Description , HelpLink ) ;
4345
44- private static readonly Action < CompilationStartAnalysisContext > CompilationStartAction = HandleCompilationStart ;
45- private static readonly Action < SyntaxNodeAnalysisContext > XmlElementAction = HandleXmlElement ;
46- private static readonly Action < SyntaxNodeAnalysisContext > XmlEmptyElementAction = HandleXmlEmptyElement ;
46+ /// <summary>
47+ /// Initializes a new instance of the <see cref="SA1613ElementParameterDocumentationMustDeclareParameterName"/> class.
48+ /// </summary>
49+ /// <remarks>The presence of a <inheritdoc/> tag should NOT suppress warnings from this diagnostic. See DotNetAnalyzers/StyleCopAnalyzers#631</remarks>
50+ public SA1613ElementParameterDocumentationMustDeclareParameterName ( )
51+ : base ( inheritDocSuppressesWarnings : false )
52+ {
53+ }
4754
4855 /// <inheritdoc/>
4956 public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } =
5057 ImmutableArray . Create ( Descriptor ) ;
5158
5259 /// <inheritdoc/>
53- public override void Initialize ( AnalysisContext context )
60+ protected override void HandleXmlElement ( SyntaxNodeAnalysisContext context , IEnumerable < XmlNodeSyntax > syntaxList , XElement completeDocumentation , params Location [ ] diagnosticLocations )
5461 {
55- context . RegisterCompilationStartAction ( CompilationStartAction ) ;
56- }
62+ bool includeElementPresent = completeDocumentation != null ;
63+ if ( includeElementPresent )
64+ {
65+ var xmlParameterNames = completeDocumentation . Nodes ( )
66+ . OfType < XElement > ( )
67+ . Where ( e => e . Name == XmlCommentHelper . ParamXmlTag )
68+ . Select ( x =>
69+ {
70+ var name = x . Attributes ( ) . FirstOrDefault ( a => a . Name == "name" ) ? . Value ;
5771
58- private static void HandleCompilationStart ( CompilationStartAnalysisContext context )
59- {
60- context . RegisterSyntaxNodeActionHonorExclusions ( XmlElementAction , SyntaxKind . XmlElement ) ;
61- context . RegisterSyntaxNodeActionHonorExclusions ( XmlEmptyElementAction , SyntaxKind . XmlEmptyElement ) ;
62- }
72+ return new Tuple < string , Location > ( name , null ) ;
73+ } )
74+ . ToImmutableArray ( ) ;
6375
64- private static void HandleXmlElement ( SyntaxNodeAnalysisContext context )
65- {
66- XmlElementSyntax emptyElement = context . Node as XmlElementSyntax ;
76+ VerifyParameters ( context , xmlParameterNames , diagnosticLocations . First ( ) ) ;
77+ }
78+ else if ( syntaxList != null )
79+ {
80+ var xmlParameterNames = syntaxList
81+ . Where ( x => string . Equals ( GetName ( x ) ? . ToString ( ) , XmlCommentHelper . ParamXmlTag ) )
82+ . Select ( x =>
83+ {
84+ var nameAttribute = XmlCommentHelper . GetFirstAttributeOrDefault < XmlNameAttributeSyntax > ( x ) ;
85+ var location = x . GetLocation ( ) ;
86+
87+ if ( nameAttribute != null )
88+ {
89+ location = nameAttribute . GetLocation ( ) ;
90+ }
6791
68- var name = emptyElement ? . StartTag ? . Name ;
92+ return new Tuple < string , Location > ( nameAttribute ? . Identifier ? . Identifier . ValueText , location ) ;
93+ } )
94+ . ToImmutableArray ( ) ;
6995
70- HandleElement ( context , emptyElement , name , emptyElement ? . StartTag ? . GetLocation ( ) ) ;
96+ VerifyParameters ( context , xmlParameterNames , diagnosticLocations . First ( ) ) ;
97+ }
7198 }
7299
73- private static void HandleXmlEmptyElement ( SyntaxNodeAnalysisContext context )
100+ private static void VerifyParameters ( SyntaxNodeAnalysisContext context , ImmutableArray < Tuple < string , Location > > documentationParameters , Location identifierLocation )
74101 {
75- XmlEmptyElementSyntax emptyElement = context . Node as XmlEmptyElementSyntax ;
102+ var index = 0 ;
76103
77- var name = emptyElement ? . Name ;
104+ foreach ( var documentedParameter in documentationParameters )
105+ {
106+ if ( string . IsNullOrWhiteSpace ( documentedParameter . Item1 ) )
107+ {
108+ context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , documentedParameter . Item2 ?? identifierLocation ) ) ;
109+ }
78110
79- HandleElement ( context , emptyElement , name , emptyElement ? . GetLocation ( ) ) ;
111+ index ++ ;
112+ }
80113 }
81114
82- private static void HandleElement ( SyntaxNodeAnalysisContext context , XmlNodeSyntax element , XmlNameSyntax name , Location alternativeDiagnosticLocation )
115+ private static XmlNameSyntax GetName ( XmlNodeSyntax element )
83116 {
84- if ( string . Equals ( name . ToString ( ) , XmlCommentHelper . ParamXmlTag ) )
85- {
86- var nameAttribute = XmlCommentHelper . GetFirstAttributeOrDefault < XmlNameAttributeSyntax > ( element ) ;
117+ return ( element as XmlElementSyntax ) ? . StartTag ? . Name
118+ ?? ( element as XmlEmptyElementSyntax ) ? . Name ;
119+ }
87120
88- if ( string . IsNullOrWhiteSpace ( nameAttribute ? . Identifier ? . Identifier . ValueText ) )
89- {
90- context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , nameAttribute ? . GetLocation ( ) ?? alternativeDiagnosticLocation ) ) ;
91- }
92- }
121+ private static SyntaxToken GetIdentifier ( SyntaxNode node )
122+ {
123+ return ( node as MethodDeclarationSyntax ) ? . Identifier
124+ ?? ( node as IndexerDeclarationSyntax ) ? . ThisKeyword
125+ ?? ( node as DelegateDeclarationSyntax ) . Identifier ;
93126 }
94127 }
95128}
0 commit comments