Skip to content

Commit 02ff3ae

Browse files
committed
Updated after CR
1 parent c549534 commit 02ff3ae

3 files changed

Lines changed: 63 additions & 51 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1649CodeFixProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
3939
context.RegisterCodeFix(
4040
CodeAction.Create(
4141
DocumentationResources.SA1649CodeFix,
42-
token => GetTransformedSolutionAsync(context.Document, diagnostic, token),
43-
equivalenceKey: nameof(SA1649CodeFixProvider)),
42+
cancellationToken => GetTransformedSolutionAsync(context.Document, diagnostic, cancellationToken),
43+
nameof(SA1649CodeFixProvider)),
4444
diagnostic);
4545
}
4646

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1649FileNameMustMatchTypeName.cs

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ namespace StyleCop.Analyzers.DocumentationRules
1111
using Microsoft.CodeAnalysis.CSharp;
1212
using Microsoft.CodeAnalysis.CSharp.Syntax;
1313
using Microsoft.CodeAnalysis.Diagnostics;
14-
using Microsoft.CodeAnalysis.Text;
1514
using StyleCop.Analyzers.Settings.ObjectModel;
1615

1716
/// <summary>
@@ -53,71 +52,84 @@ public override void Initialize(AnalysisContext context)
5352

5453
private static void HandleCompilationStart(CompilationStartAnalysisContext context)
5554
{
56-
context.RegisterSyntaxTreeActionHonorExclusions(HandleSyntaxTreeAction);
55+
var analyzer = new Analyzer(context.Options);
56+
context.RegisterSyntaxTreeActionHonorExclusions(analyzer.HandleSyntaxTreeAction);
5757
}
5858

59-
private static void HandleSyntaxTreeAction(SyntaxTreeAnalysisContext context)
59+
private class Analyzer
6060
{
61-
var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);
62-
var settings = context.GetStyleCopSettings();
61+
private readonly FileNamingConvention fileNamingConvention;
6362

64-
var firstTypeDeclaration = GetFirstTypeDeclaration(syntaxRoot);
65-
if (firstTypeDeclaration == null)
63+
public Analyzer(AnalyzerOptions options)
6664
{
67-
return;
65+
StyleCopSettings settings = options.GetStyleCopSettings();
66+
this.fileNamingConvention = settings.DocumentationRules.FileNamingConvention;
6867
}
6968

70-
if (firstTypeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword))
69+
public void HandleSyntaxTreeAction(SyntaxTreeAnalysisContext context)
7170
{
72-
return;
71+
var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);
72+
73+
var firstTypeDeclaration = GetFirstTypeDeclaration(syntaxRoot);
74+
if (firstTypeDeclaration == null)
75+
{
76+
return;
77+
}
78+
79+
if (firstTypeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword))
80+
{
81+
return;
82+
}
83+
84+
var fileName = Path.GetFileName(context.Tree.FilePath);
85+
string expectedFileName;
86+
switch (this.fileNamingConvention)
87+
{
88+
case FileNamingConvention.Metadata:
89+
expectedFileName = GetMetadataFileName(firstTypeDeclaration);
90+
break;
91+
92+
default:
93+
expectedFileName = GetStyleCopFileName(firstTypeDeclaration);
94+
break;
95+
}
96+
97+
if (string.Compare(fileName, expectedFileName, StringComparison.OrdinalIgnoreCase) != 0)
98+
{
99+
var properties = ImmutableDictionary.Create<string, string>()
100+
.Add(ExpectedFileNameKey, expectedFileName);
101+
102+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, firstTypeDeclaration.Identifier.GetLocation(), properties));
103+
}
73104
}
74105

75-
var fileName = Path.GetFileName(context.Tree.FilePath);
76-
string expectedFileName;
77-
switch (settings.DocumentationRules.FileNamingConvention)
106+
private static TypeDeclarationSyntax GetFirstTypeDeclaration(SyntaxNode root)
78107
{
79-
case FileNamingConvention.Metadata:
80-
expectedFileName = GetMetadataFileName(firstTypeDeclaration);
81-
break;
82-
83-
default:
84-
expectedFileName = GetStyleCopFileName(firstTypeDeclaration);
85-
break;
108+
return root.DescendantNodes(descendIntoChildren: node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration))
109+
.OfType<TypeDeclarationSyntax>()
110+
.FirstOrDefault();
86111
}
87112

88-
if (string.Compare(fileName, expectedFileName, StringComparison.OrdinalIgnoreCase) != 0)
113+
private static string GetStyleCopFileName(TypeDeclarationSyntax firstTypeDeclaration)
89114
{
90-
var properties = ImmutableDictionary.Create<string, string>()
91-
.Add(ExpectedFileNameKey, expectedFileName);
115+
if (firstTypeDeclaration.TypeParameterList == null)
116+
{
117+
return $"{firstTypeDeclaration.Identifier.ValueText}.cs";
118+
}
92119

93-
context.ReportDiagnostic(Diagnostic.Create(Descriptor, firstTypeDeclaration.Identifier.GetLocation(), properties));
120+
var typeParameterList = string.Join(",", firstTypeDeclaration.TypeParameterList.Parameters.Select(p => p.Identifier.ValueText));
121+
return $"{firstTypeDeclaration.Identifier.ValueText}{{{typeParameterList}}}.cs";
94122
}
95-
}
96-
97-
private static TypeDeclarationSyntax GetFirstTypeDeclaration(SyntaxNode root)
98-
{
99-
return (TypeDeclarationSyntax)root.DescendantNodes().FirstOrDefault(node => node is TypeDeclarationSyntax);
100-
}
101123

102-
private static string GetStyleCopFileName(TypeDeclarationSyntax firstTypeDeclaration)
103-
{
104-
if (firstTypeDeclaration.TypeParameterList == null)
124+
private static string GetMetadataFileName(TypeDeclarationSyntax firstTypeDeclaration)
105125
{
106-
return $"{firstTypeDeclaration.Identifier.ValueText}.cs";
107-
}
108-
109-
var typeParameterList = string.Join(",", firstTypeDeclaration.TypeParameterList.Parameters.Select(p => p.Identifier.ValueText));
110-
return $"{firstTypeDeclaration.Identifier.ValueText}{{{typeParameterList}}}.cs";
111-
}
126+
if (firstTypeDeclaration.TypeParameterList == null)
127+
{
128+
return $"{firstTypeDeclaration.Identifier.ValueText}.cs";
129+
}
112130

113-
private static string GetMetadataFileName(TypeDeclarationSyntax firstTypeDeclaration)
114-
{
115-
if (firstTypeDeclaration.TypeParameterList == null)
116-
{
117-
return $"{firstTypeDeclaration.Identifier.ValueText}.cs";
131+
return $"{firstTypeDeclaration.Identifier.ValueText}`{firstTypeDeclaration.Arity}.cs";
118132
}
119-
120-
return $"{firstTypeDeclaration.Identifier.ValueText}`{firstTypeDeclaration.Arity}.cs";
121133
}
122134
}
123135
}

documentation/SA1649.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
## Cause
1919

20-
The file name of a C# code file does not match the first type declared in the file. For generics that are defined as `Class1<T>` the name of the file needs to be `Class1{T}.cs` or `Class1``1.cs` depending on the `fileNamingConvention` setting. See [Configuration.md](documentation/Configuration.md) for more information.
20+
The file name of a C# code file does not match the first type declared in the file. For generics that are defined as `Class1<T>` the name of the file needs to be `Class1{T}.cs` or `Class1``1.cs` depending on the `fileNamingConvention` setting. See [Configuration.md](Configuration.md) for more information.
2121
Partial classes are ignored.
2222

2323
## Rule description
@@ -45,6 +45,6 @@ To fix a violation of this rule, rename the file to match the name of the first
4545
## How to suppress violations
4646

4747
```csharp
48-
#pragma warning disable SA1649 // FileHeaderFileNameDocumentationMustMatchTypeName
49-
#pragma warning restore SA1649 // FileHeaderFileNameDocumentationMustMatchTypeName
48+
#pragma warning disable SA1649 // SA1649FileNameMustMatchTypeName
49+
#pragma warning restore SA1649 // SA1649FileNameMustMatchTypeName
5050
```

0 commit comments

Comments
 (0)