Skip to content

Commit 6d28a82

Browse files
committed
Added support to SA1502 for operators and conversion operators
1 parent fbc39b3 commit 6d28a82

5 files changed

Lines changed: 182 additions & 5 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.LayoutRules
5+
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using StyleCop.Analyzers.LayoutRules;
9+
using TestHelper;
10+
using Xunit;
11+
12+
/// <summary>
13+
/// Unit tests for the operators part of <see cref="SA1502ElementMustNotBeOnASingleLine"/>.
14+
/// </summary>
15+
public partial class SA1502UnitTests : CodeFixVerifier
16+
{
17+
/// <summary>
18+
/// Verifies that valid operators will pass without diagnostic.
19+
/// </summary>
20+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
21+
[Fact]
22+
public async Task TestValidOperatorsAsync()
23+
{
24+
var testCode = @"public class TestClass
25+
{
26+
public static TestClass operator +(TestClass value)
27+
{
28+
return value;
29+
}
30+
31+
public static explicit operator TestClass(int value)
32+
{
33+
return new TestClass();
34+
}
35+
}";
36+
37+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
38+
}
39+
40+
/// <summary>
41+
/// Verifies that operators with their blocks on the same line will trigger a diagnostic.
42+
/// </summary>
43+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
44+
[Fact]
45+
public async Task TestOperatorsOnSingleLineAsync()
46+
{
47+
var testCode = @"public class TestClass
48+
{
49+
public static TestClass operator +(TestClass value) { return value; }
50+
51+
public static explicit operator TestClass(int value) { return new TestClass(); }
52+
}";
53+
54+
var fixedCode = @"public class TestClass
55+
{
56+
public static TestClass operator +(TestClass value)
57+
{
58+
return value;
59+
}
60+
61+
public static explicit operator TestClass(int value)
62+
{
63+
return new TestClass();
64+
}
65+
}";
66+
67+
DiagnosticResult[] expected =
68+
{
69+
this.CSharpDiagnostic().WithLocation(3, 57),
70+
this.CSharpDiagnostic().WithLocation(5, 58)
71+
};
72+
73+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
74+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
75+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
76+
}
77+
78+
/// <summary>
79+
/// Verifies that operators with their blocks on the next line will trigger a diagnostic.
80+
/// </summary>
81+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
82+
[Fact]
83+
public async Task TestOperatorsWithBlockOnNextLineAsync()
84+
{
85+
var testCode = @"public class TestClass
86+
{
87+
public static TestClass operator +(TestClass value)
88+
{ return value; }
89+
90+
public static explicit operator TestClass(int value)
91+
{ return new TestClass(); }
92+
}";
93+
94+
var fixedCode = @"public class TestClass
95+
{
96+
public static TestClass operator +(TestClass value)
97+
{
98+
return value;
99+
}
100+
101+
public static explicit operator TestClass(int value)
102+
{
103+
return new TestClass();
104+
}
105+
}";
106+
107+
DiagnosticResult[] expected =
108+
{
109+
this.CSharpDiagnostic().WithLocation(4, 9),
110+
this.CSharpDiagnostic().WithLocation(7, 9)
111+
};
112+
113+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
114+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
115+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
116+
}
117+
118+
/// <summary>
119+
/// Verifies that operators with an expression body will pass without diagnostic.
120+
/// </summary>
121+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
122+
[Fact]
123+
public async Task TestOperatorsWithExpressionBodyAsync()
124+
{
125+
var testCode = @"public class TestClass
126+
{
127+
public static TestClass operator +(TestClass value) => value;
128+
129+
public static explicit operator TestClass(int value) => new TestClass();
130+
}";
131+
132+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
133+
}
134+
}
135+
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@
365365
<None Include="..\stylecop.json">
366366
<Link>stylecop.json</Link>
367367
</None>
368+
<Compile Include="LayoutRules\SA1502\SA1502UnitTests.Operators.cs" />
368369
<None Include="packages.config" />
369370
</ItemGroup>
370371
<ItemGroup>

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/LayoutResources.Designer.cs

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/LayoutResources.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@
126126
<data name="SA1502CodeFix" xml:space="preserve">
127127
<value>Expand element</value>
128128
</data>
129+
<data name="SA1502Description" xml:space="preserve">
130+
<value>A C# element containing opening and closing curly brackets is written completely on a single line.</value>
131+
</data>
132+
<data name="SA1502MessageFormat" xml:space="preserve">
133+
<value>Element must not be on a single line</value>
134+
</data>
135+
<data name="SA1502Title" xml:space="preserve">
136+
<value>Element must not be on a single line</value>
137+
</data>
129138
<data name="SA1503CodeFix" xml:space="preserve">
130139
<value>Wrap with curly brackets</value>
131140
</data>

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1502ElementMustNotBeOnASingleLine.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ internal class SA1502ElementMustNotBeOnASingleLine : DiagnosticAnalyzer
4343
/// The ID for diagnostics produced by the <see cref="SA1502ElementMustNotBeOnASingleLine"/> analyzer.
4444
/// </summary>
4545
public const string DiagnosticId = "SA1502";
46-
private const string Title = "Element must not be on a single line";
47-
private const string MessageFormat = "Element must not be on a single line";
48-
private const string Description = "A C# element containing opening and closing curly brackets is written completely on a single line.";
49-
private const string HelpLink = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1502.md";
46+
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(LayoutResources.SA1502Title), LayoutResources.ResourceManager, typeof(LayoutResources));
47+
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(LayoutResources.SA1502MessageFormat), LayoutResources.ResourceManager, typeof(LayoutResources));
48+
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(LayoutResources.SA1502Description), LayoutResources.ResourceManager, typeof(LayoutResources));
49+
private static readonly string HelpLink = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1502.md";
5050

5151
private static readonly DiagnosticDescriptor Descriptor =
5252
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.LayoutRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
@@ -58,7 +58,12 @@ internal class SA1502ElementMustNotBeOnASingleLine : DiagnosticAnalyzer
5858
ImmutableArray.Create(SyntaxKind.PropertyDeclaration, SyntaxKind.EventDeclaration, SyntaxKind.IndexerDeclaration);
5959

6060
private static readonly ImmutableArray<SyntaxKind> BaseMethodDeclarationKinds =
61-
ImmutableArray.Create(SyntaxKind.MethodDeclaration, SyntaxKind.ConstructorDeclaration, SyntaxKind.DestructorDeclaration);
61+
ImmutableArray.Create(
62+
SyntaxKind.MethodDeclaration,
63+
SyntaxKind.ConstructorDeclaration,
64+
SyntaxKind.DestructorDeclaration,
65+
SyntaxKind.OperatorDeclaration,
66+
SyntaxKind.ConversionOperatorDeclaration);
6267

6368
private static readonly Action<CompilationStartAnalysisContext> CompilationStartAction = HandleCompilationStart;
6469
private static readonly Action<SyntaxNodeAnalysisContext> BaseTypeDeclarationAction = HandleBaseTypeDeclaration;

0 commit comments

Comments
 (0)