Skip to content

Commit 1039445

Browse files
authored
Add analyzer 'Add/remove blank line between switch sections' (#1302)
1 parent 65425bc commit 1039445

24 files changed

Lines changed: 650 additions & 110 deletions

ChangeLog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add analyzer "Add/remove blank line between switch sections" ([RCS0061](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0061)) ([PR](https://github.com/dotnet/roslynator/pull/1302))
13+
- Option (required): `roslynator_blank_line_between_switch_sections = include|omit|omit_after_block`
14+
- Make analyzer [RCS0014](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0014) obsolete
15+
1016
### Changed
1117

1218
- Replace type declaration's empty braces with semicolon ([RCS1251](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1251) ([PR](https://github.com/dotnet/roslynator/pull/1323))
@@ -18,6 +24,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1824
- Add analyzer "Dispose resource asynchronously" ([RCS1261](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1261)) ([PR](https://github.com/dotnet/roslynator/pull/1285))
1925
- Add analyzer "Unnecessary raw string literal" ([RCS1262](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1262)) ([PR](https://github.com/dotnet/roslynator/pull/1293))
2026
- Add analyzer "Invalid reference in a documentation comment" ([RCS1263](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1263)) ([PR](https://github.com/dotnet/roslynator/pull/1295))
27+
- Add analyzer "Add/remove blank line between switch sections" ([RCS0061](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0061)) ([PR](https://github.com/dotnet/roslynator/pull/1302))
28+
- Option (required): `roslynator_blank_line_between_switch_sections = include|omit|omit_after_block`
29+
- Make analyzer [RCS0014](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0014) obsolete
2130

2231
### Changed
2332

src/Analyzers.xml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,8 @@ object this[int index] { get; }]]></After>
388388
<Analyzer>
389389
<Id>RCS0014</Id>
390390
<Identifier>AddBlankLineBetweenSwitchSections</Identifier>
391+
<Status>Obsolete</Status>
392+
<ObsoleteMessage>Use RCS0061 instead</ObsoleteMessage>
391393
<Title>Add blank line between switch sections</Title>
392394
<DefaultSeverity>Info</DefaultSeverity>
393395
<IsEnabledByDefault>false</IsEnabledByDefault>
@@ -1530,6 +1532,103 @@ public class C
15301532
</Link>
15311533
</Links>
15321534
</Analyzer>
1535+
<Analyzer>
1536+
<Id>RCS0061</Id>
1537+
<Identifier>BlankLineBetweenSwitchSections</Identifier>
1538+
<Title>Add/remove blank line between switch sections</Title>
1539+
<MessageFormat>{0} blank line between switch sections</MessageFormat>
1540+
<DefaultSeverity>Info</DefaultSeverity>
1541+
<IsEnabledByDefault>false</IsEnabledByDefault>
1542+
<ConfigOptions>
1543+
<Option Key="blank_line_between_switch_sections" IsRequired="true" />
1544+
</ConfigOptions>
1545+
<Samples>
1546+
<Sample>
1547+
<ConfigOptions>
1548+
<Option Key="blank_line_between_switch_sections" Value="include" />
1549+
</ConfigOptions>
1550+
<Before><![CDATA[switch (x)
1551+
{
1552+
case "foo":
1553+
return true;
1554+
case "bar":
1555+
return false;
1556+
default:
1557+
throw new InvalidOperationException();
1558+
}
1559+
]]></Before>
1560+
<After><![CDATA[switch (x)
1561+
{
1562+
case "foo":
1563+
return true;
1564+
1565+
case "bar":
1566+
return false;
1567+
1568+
default:
1569+
throw new InvalidOperationException();
1570+
}
1571+
]]></After>
1572+
</Sample>
1573+
<Sample>
1574+
<ConfigOptions>
1575+
<Option Key="blank_line_between_switch_sections" Value="omit" />
1576+
</ConfigOptions>
1577+
<Before><![CDATA[switch (x)
1578+
{
1579+
case "foo":
1580+
return true;
1581+
1582+
case "bar":
1583+
return false;
1584+
1585+
default:
1586+
throw new InvalidOperationException();
1587+
}
1588+
]]></Before>
1589+
<After><![CDATA[switch (x)
1590+
{
1591+
case "foo":
1592+
return true;
1593+
case "bar":
1594+
return false;
1595+
default:
1596+
throw new InvalidOperationException();
1597+
}
1598+
]]></After>
1599+
</Sample>
1600+
<Sample>
1601+
<ConfigOptions>
1602+
<Option Key="blank_line_between_switch_sections" Value="omit_after_block" />
1603+
</ConfigOptions>
1604+
<Before><![CDATA[switch (x)
1605+
{
1606+
case "foo":
1607+
{
1608+
return true;
1609+
}
1610+
1611+
case "bar":
1612+
{
1613+
return false;
1614+
}
1615+
}
1616+
]]></Before>
1617+
<After><![CDATA[switch (x)
1618+
{
1619+
case "foo":
1620+
{
1621+
return true;
1622+
}
1623+
case "bar":
1624+
{
1625+
return false;
1626+
}
1627+
}
1628+
]]></After>
1629+
</Sample>
1630+
</Samples>
1631+
</Analyzer>
15331632
<Analyzer>
15341633
<Id>RCS1001</Id>
15351634
<Identifier>AddBracesWhenExpressionSpansOverMultipleLines</Identifier>

src/Analyzers/CSharp/Analysis/RemoveUnnecessaryBlankLineAnalyzer.cs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public override void Initialize(AnalysisContext context)
3838
context.RegisterSyntaxNodeAction(f => AnalyzeInterfaceDeclaration(f), SyntaxKind.InterfaceDeclaration);
3939
context.RegisterSyntaxNodeAction(f => AnalyzeEnumDeclaration(f), SyntaxKind.EnumDeclaration);
4040
context.RegisterSyntaxNodeAction(f => AnalyzeNamespaceDeclaration(f), SyntaxKind.NamespaceDeclaration);
41-
context.RegisterSyntaxNodeAction(f => AnalyzeSwitchStatement(f), SyntaxKind.SwitchStatement);
4241
context.RegisterSyntaxNodeAction(f => AnalyzeTryStatement(f), SyntaxKind.TryStatement);
4342
context.RegisterSyntaxNodeAction(f => AnalyzeElseClause(f), SyntaxKind.ElseClause);
4443

@@ -147,35 +146,6 @@ private static void AnalyzeNamespaceDeclaration(SyntaxNodeAnalysisContext contex
147146
AnalyzeEnd(context, members.Last(), namespaceDeclaration.CloseBraceToken);
148147
}
149148

150-
private static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context)
151-
{
152-
var switchStatement = (SwitchStatementSyntax)context.Node;
153-
154-
SyntaxList<SwitchSectionSyntax> sections = switchStatement.Sections;
155-
156-
if (sections.Any())
157-
{
158-
AnalyzeStart(context, sections[0], switchStatement.OpenBraceToken);
159-
AnalyzeEnd(context, sections.Last(), switchStatement.CloseBraceToken);
160-
161-
if (sections.Count > 1
162-
&& context.GetBlankLineBetweenClosingBraceAndSwitchSection() == false)
163-
{
164-
SwitchSectionSyntax prevSection = sections[0];
165-
166-
for (int i = 1; i < sections.Count; i++)
167-
{
168-
SwitchSectionSyntax section = sections[i];
169-
170-
if (prevSection.Statements.LastOrDefault() is BlockSyntax block)
171-
Analyze(context, block.CloseBraceToken, section);
172-
173-
prevSection = section;
174-
}
175-
}
176-
}
177-
}
178-
179149
private static void AnalyzeTryStatement(SyntaxNodeAnalysisContext context)
180150
{
181151
var tryStatement = (TryStatementSyntax)context.Node;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
3+
namespace Roslynator.CSharp.CodeStyle;
4+
5+
internal enum BlankLineBetweenSwitchSections
6+
{
7+
None,
8+
Include,
9+
Omit,
10+
OmitAfterBlock,
11+
}

src/Common/CSharp/Extensions/CodeStyleExtensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,23 @@ public static BlankLineStyle GetBlankLineAfterFileScopedNamespaceDeclaration(thi
581581
return null;
582582
}
583583

584+
public static BlankLineBetweenSwitchSections GetBlankLineBetweenSwitchSections(this SyntaxNodeAnalysisContext context)
585+
{
586+
if (ConfigOptions.TryGetValue(context.GetConfigOptions(), ConfigOptions.BlankLineBetweenSwitchSections, out string rawValue))
587+
{
588+
if (string.Equals(rawValue, ConfigOptionValues.BlankLineBetweenSwitchSections_Include, StringComparison.OrdinalIgnoreCase))
589+
return BlankLineBetweenSwitchSections.Include;
590+
591+
if (string.Equals(rawValue, ConfigOptionValues.BlankLineBetweenSwitchSections_Omit, StringComparison.OrdinalIgnoreCase))
592+
return BlankLineBetweenSwitchSections.Omit;
593+
594+
if (string.Equals(rawValue, ConfigOptionValues.BlankLineBetweenSwitchSections_OmitAfterBlock, StringComparison.OrdinalIgnoreCase))
595+
return BlankLineBetweenSwitchSections.OmitAfterBlock;
596+
}
597+
598+
return BlankLineBetweenSwitchSections.None;
599+
}
600+
584601
public static NewLinePosition GetEqualsSignNewLinePosition(this SyntaxNodeAnalysisContext context)
585602
{
586603
return context.GetConfigOptions().GetEqualsTokenNewLinePosition();

src/Common/ConfigOptionKeys.Generated.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ internal static partial class ConfigOptionKeys
1414
public const string BlankLineAfterFileScopedNamespaceDeclaration = "roslynator_blank_line_after_file_scoped_namespace_declaration";
1515
public const string BlankLineBetweenClosingBraceAndSwitchSection = "roslynator_blank_line_between_closing_brace_and_switch_section";
1616
public const string BlankLineBetweenSingleLineAccessors = "roslynator_blank_line_between_single_line_accessors";
17+
public const string BlankLineBetweenSwitchSections = "roslynator_blank_line_between_switch_sections";
1718
public const string BlankLineBetweenUsingDirectives = "roslynator_blank_line_between_using_directives";
1819
public const string BlockBracesStyle = "roslynator_block_braces_style";
1920
public const string BodyStyle = "roslynator_body_style";

src/Common/ConfigOptionValues.Generated.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ internal static partial class ConfigOptionValues
1717
public const string ArrowTokenNewLine_Before = "before";
1818
public const string BinaryOperatorNewLine_After = "after";
1919
public const string BinaryOperatorNewLine_Before = "before";
20+
public const string BlankLineBetweenSwitchSections_Include = "include";
21+
public const string BlankLineBetweenSwitchSections_Omit = "omit";
22+
public const string BlankLineBetweenSwitchSections_OmitAfterBlock = "omit_after_block";
2023
public const string BlankLineBetweenUsingDirectives_Never = "never";
2124
public const string BlankLineBetweenUsingDirectives_SeparateGroups = "separate_groups";
2225
public const string BlockBracesStyle_MultiLine = "multi_line";

src/Common/ConfigOptions.Generated.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ public static partial class ConfigOptions
5757
defaultValuePlaceholder: "true|false",
5858
description: "Add/remove blank line between single-line accessors");
5959

60+
public static readonly ConfigOptionDescriptor BlankLineBetweenSwitchSections = new(
61+
key: ConfigOptionKeys.BlankLineBetweenSwitchSections,
62+
defaultValue: null,
63+
defaultValuePlaceholder: "include|omit|omit_after_block",
64+
description: "Include/omit blank line between switch sections");
65+
6066
public static readonly ConfigOptionDescriptor BlankLineBetweenUsingDirectives = new(
6167
key: ConfigOptionKeys.BlankLineBetweenUsingDirectives,
6268
defaultValue: null,
@@ -240,6 +246,7 @@ private static IEnumerable<KeyValuePair<string, string>> GetRequiredOptions()
240246
yield return new KeyValuePair<string, string>("RCS0058", JoinOptionKeys(ConfigOptionKeys.NewLineAtEndOfFile));
241247
yield return new KeyValuePair<string, string>("RCS0059", JoinOptionKeys(ConfigOptionKeys.NullConditionalOperatorNewLine));
242248
yield return new KeyValuePair<string, string>("RCS0060", JoinOptionKeys(ConfigOptionKeys.BlankLineAfterFileScopedNamespaceDeclaration));
249+
yield return new KeyValuePair<string, string>("RCS0061", JoinOptionKeys(ConfigOptionKeys.BlankLineBetweenSwitchSections));
243250
yield return new KeyValuePair<string, string>("RCS1014", JoinOptionKeys(ConfigOptionKeys.ArrayCreationTypeStyle));
244251
yield return new KeyValuePair<string, string>("RCS1016", JoinOptionKeys(ConfigOptionKeys.BodyStyle, ConfigOptionKeys.UseBlockBodyWhenDeclarationSpansOverMultipleLines, ConfigOptionKeys.UseBlockBodyWhenExpressionSpansOverMultipleLines));
245252
yield return new KeyValuePair<string, string>("RCS1018", JoinOptionKeys(ConfigOptionKeys.AccessibilityModifiers));

src/ConfigOptions.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@
217217
<Value>omit_when_single_line</Value>
218218
</Values>
219219
</Option>
220+
<Option Id="BlankLineBetweenSwitchSections">
221+
<Description>Include/omit blank line between switch sections</Description>
222+
<Values>
223+
<Value>include</Value>
224+
<Value>omit</Value>
225+
<Value>omit_after_block</Value>
226+
</Values>
227+
</Option>
220228
<!--
221229
<Option Id="">
222230
<Key></Key>

src/Directory.Build.props

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,4 @@
7474
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
7575
</ItemGroup>
7676

77-
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
78-
<NoWarn>$(NoWarn);1573</NoWarn>
79-
</PropertyGroup>
80-
8177
</Project>

0 commit comments

Comments
 (0)