33using CSharpGuidelinesAnalyzer . Extensions ;
44using JetBrains . Annotations ;
55using Microsoft . CodeAnalysis ;
6+ using Microsoft . CodeAnalysis . CSharp ;
7+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
68using Microsoft . CodeAnalysis . Diagnostics ;
79
810namespace CSharpGuidelinesAnalyzer . Rules . ClassDesign
@@ -29,35 +31,74 @@ public sealed class TypeShouldHaveASinglePurposeAnalyzer : DiagnosticAnalyzer
2931 private const string BlacklistWord = "and" ;
3032
3133 [ NotNull ]
32- private static readonly Action < SymbolAnalysisContext > AnalyzeNamedTypeAction =
33- context => context . SkipEmptyName ( AnalyzeNamedType ) ;
34+ private static readonly Action < SyntaxNodeAnalysisContext > AnalyzeTypeDeclarationAction = AnalyzeTypeDeclaration ;
35+
36+ [ NotNull ]
37+ private static readonly SyntaxKind [ ] TypeDeclarationKinds =
38+ {
39+ SyntaxKind . ClassDeclaration ,
40+ SyntaxKind . StructDeclaration ,
41+ SyntaxKind . InterfaceDeclaration ,
42+ SyntaxKind . EnumDeclaration ,
43+ SyntaxKind . DelegateDeclaration
44+ } ;
45+
46+ [ NotNull ]
47+ private static readonly TypeIdentifierResolver IdentifierResolver = new TypeIdentifierResolver ( ) ;
3448
3549 public override void Initialize ( [ NotNull ] AnalysisContext context )
3650 {
3751 context . EnableConcurrentExecution ( ) ;
3852 context . ConfigureGeneratedCodeAnalysis ( GeneratedCodeAnalysisFlags . None ) ;
3953
40- context . RegisterSymbolAction ( AnalyzeNamedTypeAction , SymbolKind . NamedType ) ;
54+ context . RegisterSyntaxNodeAction ( AnalyzeTypeDeclarationAction , TypeDeclarationKinds ) ;
4155 }
4256
43- private static void AnalyzeNamedType ( SymbolAnalysisContext context )
57+ private static void AnalyzeTypeDeclaration ( SyntaxNodeAnalysisContext context )
4458 {
45- var type = ( INamedTypeSymbol ) context . Symbol ;
46-
47- if ( type . IsSynthesized ( ) )
59+ SyntaxToken identifier = IdentifierResolver . Visit ( context . Node ) ;
60+ if ( identifier == default )
4861 {
4962 return ;
5063 }
5164
52- if ( ContainsBlacklistedWord ( type . Name ) )
65+ if ( ContainsBlacklistedWord ( identifier . ValueText ) )
5366 {
54- context . ReportDiagnostic ( Diagnostic . Create ( Rule , type . Locations [ 0 ] , type . Name ) ) ;
67+ context . ReportDiagnostic ( Diagnostic . Create ( Rule , identifier . GetLocation ( ) , identifier . ValueText ) ) ;
5568 }
5669 }
5770
5871 private static bool ContainsBlacklistedWord ( [ NotNull ] string name )
5972 {
6073 return name . ContainsWordInTheMiddle ( BlacklistWord ) ;
6174 }
75+
76+ private sealed class TypeIdentifierResolver : CSharpSyntaxVisitor < SyntaxToken >
77+ {
78+ public override SyntaxToken VisitClassDeclaration ( [ NotNull ] ClassDeclarationSyntax node )
79+ {
80+ return node . Identifier ;
81+ }
82+
83+ public override SyntaxToken VisitStructDeclaration ( [ NotNull ] StructDeclarationSyntax node )
84+ {
85+ return node . Identifier ;
86+ }
87+
88+ public override SyntaxToken VisitInterfaceDeclaration ( [ NotNull ] InterfaceDeclarationSyntax node )
89+ {
90+ return node . Identifier ;
91+ }
92+
93+ public override SyntaxToken VisitEnumDeclaration ( [ NotNull ] EnumDeclarationSyntax node )
94+ {
95+ return node . Identifier ;
96+ }
97+
98+ public override SyntaxToken VisitDelegateDeclaration ( [ NotNull ] DelegateDeclarationSyntax node )
99+ {
100+ return node . Identifier ;
101+ }
102+ }
62103 }
63104}
0 commit comments