@@ -11,6 +11,7 @@ namespace StyleCop.Analyzers.MaintainabilityRules
1111 using Microsoft . CodeAnalysis . CSharp ;
1212 using Microsoft . CodeAnalysis . CSharp . Syntax ;
1313 using Microsoft . CodeAnalysis . Diagnostics ;
14+ using Settings . ObjectModel ;
1415 using StyleCop . Analyzers . Helpers ;
1516
1617 /// <summary>
@@ -33,6 +34,7 @@ internal class SA1402FileMayOnlyContainASingleClass : DiagnosticAnalyzer
3334 /// The ID for diagnostics produced by the <see cref="SA1402FileMayOnlyContainASingleClass"/> analyzer.
3435 /// </summary>
3536 public const string DiagnosticId = "SA1402" ;
37+
3638 private const string Title = "File may only contain a single class" ;
3739 private const string MessageFormat = "File may only contain a single class" ;
3840 private const string Description = "A C# code file contains more than one unique class." ;
@@ -42,7 +44,6 @@ internal class SA1402FileMayOnlyContainASingleClass : DiagnosticAnalyzer
4244 new DiagnosticDescriptor ( DiagnosticId , Title , MessageFormat , AnalyzerCategory . MaintainabilityRules , DiagnosticSeverity . Warning , AnalyzerConstants . EnabledByDefault , Description , HelpLink ) ;
4345
4446 private static readonly Action < CompilationStartAnalysisContext > CompilationStartAction = HandleCompilationStart ;
45- private static readonly Action < SyntaxTreeAnalysisContext > SyntaxTreeAction = HandleSyntaxTree ;
4647
4748 /// <inheritdoc/>
4849 public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } =
@@ -56,21 +57,36 @@ public override void Initialize(AnalysisContext context)
5657
5758 private static void HandleCompilationStart ( CompilationStartAnalysisContext context )
5859 {
59- context . RegisterSyntaxTreeActionHonorExclusions ( SyntaxTreeAction ) ;
60+ var analyzer = new Analyzer ( context . Options ) ;
61+ context . RegisterSyntaxTreeActionHonorExclusions ( analyzer . HandleSyntaxTree ) ;
6062 }
6163
62- private static void HandleSyntaxTree ( SyntaxTreeAnalysisContext context )
64+ private class Analyzer
6365 {
64- var syntaxRoot = context . Tree . GetRoot ( context . CancellationToken ) ;
65- var descentNodes = syntaxRoot . DescendantNodes ( descendIntoChildren : node => node != null && ! node . IsKind ( SyntaxKind . ClassDeclaration ) ) ;
66- var classNodes = from descentNode in descentNodes
67- where descentNode . IsKind ( SyntaxKind . ClassDeclaration )
68- select descentNode as ClassDeclarationSyntax ;
66+ private readonly FileNamingConvention fileNamingConvention ;
6967
70- var preferredClassNode = classNodes . FirstOrDefault ( n => n . Identifier . Text == Path . GetFileNameWithoutExtension ( context . Tree . FilePath ) ) ?? classNodes . FirstOrDefault ( ) ;
68+ public Analyzer ( AnalyzerOptions options )
69+ {
70+ StyleCopSettings settings = options . GetStyleCopSettings ( ) ;
71+ this . fileNamingConvention = settings . DocumentationRules . FileNamingConvention ;
72+ }
7173
72- if ( preferredClassNode != null )
74+ public void HandleSyntaxTree ( SyntaxTreeAnalysisContext context )
7375 {
76+ var syntaxRoot = context . Tree . GetRoot ( context . CancellationToken ) ;
77+ var descentNodes = syntaxRoot . DescendantNodes ( descendIntoChildren : node => node != null && ! node . IsKind ( SyntaxKind . ClassDeclaration ) ) ;
78+ var classNodes = from descentNode in descentNodes
79+ where descentNode . IsKind ( SyntaxKind . ClassDeclaration )
80+ select descentNode as ClassDeclarationSyntax ;
81+
82+ var fileName = Path . GetFileName ( context . Tree . FilePath ) ;
83+ var preferredClassNode = classNodes . FirstOrDefault ( n => NamedTypeHelpers . GetConventionalFileName ( n , this . fileNamingConvention ) == fileName ) ?? classNodes . FirstOrDefault ( ) ;
84+
85+ if ( preferredClassNode == null )
86+ {
87+ return ;
88+ }
89+
7490 string foundClassName = null ;
7591 bool isPartialClass = false ;
7692
0 commit comments