@@ -5,6 +5,9 @@ namespace StyleCop.Analyzers.DocumentationRules
55{
66 using System ;
77 using System . Collections . Immutable ;
8+ using System . Linq ;
9+ using System . Xml . Linq ;
10+ using Helpers ;
811 using Microsoft . CodeAnalysis ;
912 using Microsoft . CodeAnalysis . CSharp ;
1013 using Microsoft . CodeAnalysis . CSharp . Syntax ;
@@ -37,6 +40,12 @@ internal class SA1651DoNotUsePlaceholderElements : DiagnosticAnalyzer
3740 /// analyzer.
3841 /// </summary>
3942 public const string DiagnosticId = "SA1651" ;
43+
44+ /// <summary>
45+ /// The key used for signalling that no codefix should be offered.
46+ /// </summary>
47+ internal const string NoCodeFixKey = "NoCodeFix" ;
48+
4049 private const string Title = "Do not use placeholder elements" ;
4150 private const string MessageFormat = "Do not use placeholder elements" ;
4251 private const string Description = "The element documentation contains a <placeholder> element." ;
@@ -48,6 +57,8 @@ internal class SA1651DoNotUsePlaceholderElements : DiagnosticAnalyzer
4857 private static readonly Action < SyntaxNodeAnalysisContext > XmlElementAction = HandleXmlElement ;
4958 private static readonly Action < SyntaxNodeAnalysisContext > XmlEmptyElementAction = HandleXmlEmptyElement ;
5059
60+ private static readonly ImmutableDictionary < string , string > NoCodeFixProperties = ImmutableDictionary . Create < string , string > ( ) . Add ( NoCodeFixKey , string . Empty ) ;
61+
5162 /// <inheritdoc/>
5263 public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } =
5364 ImmutableArray . Create ( Descriptor ) ;
@@ -65,23 +76,54 @@ public override void Initialize(AnalysisContext context)
6576 private static void HandleXmlElement ( SyntaxNodeAnalysisContext context )
6677 {
6778 XmlElementSyntax syntax = ( XmlElementSyntax ) context . Node ;
68- if ( ! string . Equals ( "placeholder" , syntax . StartTag ? . Name ? . ToString ( ) , StringComparison . Ordinal ) )
79+ CheckTag ( context , syntax . StartTag ? . Name ? . ToString ( ) ) ;
80+ }
81+
82+ private static void HandleXmlEmptyElement ( SyntaxNodeAnalysisContext context )
83+ {
84+ XmlEmptyElementSyntax syntax = ( XmlEmptyElementSyntax ) context . Node ;
85+ CheckTag ( context , syntax . Name ? . ToString ( ) ) ;
86+ }
87+
88+ private static void CheckTag ( SyntaxNodeAnalysisContext context , string tagName )
89+ {
90+ if ( string . Equals ( XmlCommentHelper . IncludeXmlTag , tagName , StringComparison . Ordinal ) )
6991 {
70- return ;
92+ if ( ! IncludedDocumentationContainsPlaceHolderTags ( context ) )
93+ {
94+ return ;
95+ }
96+
97+ context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , context . Node . GetLocation ( ) , NoCodeFixProperties ) ) ;
7198 }
99+ else
100+ {
101+ if ( ! string . Equals ( XmlCommentHelper . PlaceholderTag , tagName , StringComparison . Ordinal ) )
102+ {
103+ return ;
104+ }
72105
73- context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , syntax . GetLocation ( ) ) ) ;
106+ context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , context . Node . GetLocation ( ) ) ) ;
107+ }
74108 }
75109
76- private static void HandleXmlEmptyElement ( SyntaxNodeAnalysisContext context )
110+ private static bool IncludedDocumentationContainsPlaceHolderTags ( SyntaxNodeAnalysisContext context )
77111 {
78- XmlEmptyElementSyntax syntax = ( XmlEmptyElementSyntax ) context . Node ;
79- if ( ! string . Equals ( "placeholder" , syntax . Name ? . ToString ( ) , StringComparison . Ordinal ) )
112+ var memberDeclaration = context . Node . FirstAncestorOrSelf < MemberDeclarationSyntax > ( ) ;
113+ if ( memberDeclaration == null )
114+ {
115+ return false ;
116+ }
117+
118+ var declaration = context . SemanticModel . GetDeclaredSymbol ( memberDeclaration , context . CancellationToken ) ;
119+ if ( declaration == null )
80120 {
81- return ;
121+ return false ;
82122 }
83123
84- context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , syntax . GetLocation ( ) ) ) ;
124+ var rawDocumentation = declaration . GetDocumentationCommentXml ( expandIncludes : true , cancellationToken : context . CancellationToken ) ;
125+ var completeDocumentation = XElement . Parse ( rawDocumentation , LoadOptions . None ) ;
126+ return completeDocumentation . DescendantNodesAndSelf ( ) . OfType < XElement > ( ) . Any ( element => element . Name == XmlCommentHelper . PlaceholderTag ) ;
85127 }
86128 }
87129}
0 commit comments