Skip to content

Commit db9b9f3

Browse files
committed
Add MA0007.IgnoreCatchAllArm configuration option
Introduce a new configuration option `MA0007.IgnoreCatchAllArm` to control diagnostics for missing trailing commas in catch-all arms (`_`) of switch expressions.
1 parent 5cd3eeb commit db9b9f3

File tree

4 files changed

+108
-1
lines changed

4 files changed

+108
-1
lines changed

docs/Rules/MA0007.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,38 @@ new Sample
1717
B = 1,
1818
};
1919
````
20+
21+
## Configuration
22+
23+
### `MA0007.IgnoreCatchAllArm`
24+
25+
By default, the analyzer reports a diagnostic when a catch-all arm (`_`) in a switch expression is missing a trailing comma. You can disable this behavior by setting `MA0007.IgnoreCatchAllArm` to `true`.
26+
27+
````csharp
28+
// Default behavior (non-compliant)
29+
_ = value switch
30+
{
31+
1 => "one",
32+
_ => "other" // Diagnostic reported
33+
};
34+
35+
// With MA0007.IgnoreCatchAllArm = true
36+
_ = value switch
37+
{
38+
1 => "one",
39+
_ => "other" // No diagnostic
40+
};
41+
42+
// Compliant code
43+
_ = value switch
44+
{
45+
1 => "one",
46+
_ => "other",
47+
};
48+
````
49+
50+
**.editorconfig**
51+
52+
```ini
53+
# Ignore missing trailing comma on catch-all arms in switch expressions
54+
MA0007.IgnoreCatchAllArm = true

src/Meziantou.Analyzer/Configurations/AnalyzerOptionsExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ public static string GetConfigurationValue(this AnalyzerOptions options, SyntaxT
1414
return defaultValue;
1515
}
1616

17+
public static string GetConfigurationValue(this AnalyzerOptions options, SyntaxNode syntaxNode, string key, string defaultValue)
18+
{
19+
return GetConfigurationValue(options, syntaxNode.SyntaxTree, key, defaultValue);
20+
}
21+
1722
public static string GetConfigurationValue(this AnalyzerOptions options, IOperation operation, string key, string defaultValue)
1823
{
1924
return GetConfigurationValue(options, operation.Syntax.SyntaxTree, key, defaultValue);
@@ -28,6 +33,12 @@ public static bool GetConfigurationValue(this AnalyzerOptions options, SyntaxTre
2833
return defaultValue;
2934
}
3035

36+
[return: NotNullIfNotNull(nameof(defaultValue))]
37+
public static bool? GetConfigurationValue(this AnalyzerOptions options, SyntaxNode syntaxNode, string key, bool? defaultValue)
38+
{
39+
return GetConfigurationValue(options, syntaxNode.SyntaxTree, key, defaultValue);
40+
}
41+
3142
[return: NotNullIfNotNull(nameof(defaultValue))]
3243
public static bool? GetConfigurationValue(this AnalyzerOptions options, SyntaxTree syntaxTree, string key, bool? defaultValue)
3344
{

src/Meziantou.Analyzer/Rules/CommaAnalyzer.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Immutable;
1+
using System.Collections.Immutable;
2+
using Meziantou.Analyzer.Configurations;
23
using Meziantou.Analyzer.Internals;
34
using Microsoft.CodeAnalysis;
45
using Microsoft.CodeAnalysis.CSharp;
@@ -63,6 +64,14 @@ private void HandleCollectionExpression(SyntaxNodeAnalysisContext context)
6364
private void HandleSwitchExpression(SyntaxNodeAnalysisContext context)
6465
{
6566
var node = (SwitchExpressionSyntax)context.Node;
67+
var options = context.Options.GetConfigurationValue(node, Rule.Id + ".IgnoreCatchAllArm", defaultValue: false);
68+
if (options is true)
69+
{
70+
var last = node.Arms.LastOrDefault();
71+
if (last is not null && last.Pattern is DiscardPatternSyntax)
72+
return;
73+
}
74+
6675
HandleSeparatedList(context, node, node.Arms);
6776
}
6877

tests/Meziantou.Analyzer.Test/Rules/CommaAnalyzerTests.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,58 @@ await CreateProjectBuilder()
259259
}
260260
#endif
261261

262+
[Fact]
263+
public Task SwitchExpressionWithoutLeadingComma_CatchAll()
264+
=> CreateProjectBuilder()
265+
.WithLanguageVersion(Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8)
266+
.WithSourceCode("""
267+
class TypeName
268+
{
269+
public void Test()
270+
{
271+
_ = 0 switch
272+
{
273+
1 => 1,
274+
[||]_ => 2
275+
};
276+
}
277+
}
278+
""")
279+
.ShouldFixCodeWith("""
280+
class TypeName
281+
{
282+
public void Test()
283+
{
284+
_ = 0 switch
285+
{
286+
1 => 1,
287+
_ => 2,
288+
};
289+
}
290+
}
291+
""")
292+
.ValidateAsync();
293+
294+
[Fact]
295+
public Task SwitchExpressionWithoutLeadingComma_IgnoreCatchAll()
296+
=> CreateProjectBuilder()
297+
.WithLanguageVersion(Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8)
298+
.AddAnalyzerConfiguration("MA0007.IgnoreCatchAllArm", "true")
299+
.WithSourceCode("""
300+
class TypeName
301+
{
302+
public void Test()
303+
{
304+
_ = 0 switch
305+
{
306+
1 => 1,
307+
_ => 2
308+
};
309+
}
310+
}
311+
""")
312+
.ValidateAsync();
313+
262314
[Fact]
263315
public Task SwitchExpressionWithoutLeadingComma()
264316
=> CreateProjectBuilder()

0 commit comments

Comments
 (0)