Skip to content

Commit 3a75847

Browse files
committed
Update SA1112 for target-typed new
1 parent 400d34a commit 3a75847

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/ReadabilityRules/SA1112CSharp9UnitTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,51 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp9.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp8.ReadabilityRules;
10+
using StyleCop.Analyzers.Test.Helpers;
11+
using Xunit;
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.ReadabilityRules.SA1112ClosingParenthesisMustBeOnLineOfOpeningParenthesis,
14+
StyleCop.Analyzers.SpacingRules.TokenSpacingCodeFixProvider>;
715

816
public partial class SA1112CSharp9UnitTests : SA1112CSharp8UnitTests
917
{
18+
[Fact]
19+
[WorkItem(3972, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3972")]
20+
public async Task TestTargetTypedNewClosingParenthesisAsync()
21+
{
22+
var testCode = @"
23+
struct TestStruct
24+
{
25+
}
26+
27+
class Test
28+
{
29+
void M()
30+
{
31+
TestStruct value = new(
32+
{|#0:)|};
33+
}
34+
}";
35+
36+
var fixedCode = @"
37+
struct TestStruct
38+
{
39+
}
40+
41+
class Test
42+
{
43+
void M()
44+
{
45+
TestStruct value = new();
46+
}
47+
}";
48+
49+
var expected = Diagnostic().WithLocation(0);
50+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
51+
}
1052
}
1153
}

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1112ClosingParenthesisMustBeOnLineOfOpeningParenthesis.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ internal class SA1112ClosingParenthesisMustBeOnLineOfOpeningParenthesis : Diagno
5151
private static readonly Action<SyntaxNodeAnalysisContext> ConstructorDeclarationAction = HandleConstructorDeclaration;
5252
private static readonly Action<SyntaxNodeAnalysisContext> InvocationExpressionAction = HandleInvocationExpression;
5353
private static readonly Action<SyntaxNodeAnalysisContext> ObjectCreationExpressionAction = HandleObjectCreationExpression;
54+
private static readonly Action<SyntaxNodeAnalysisContext> ImplicitObjectCreationExpressionAction = HandleImplicitObjectCreationExpression;
5455

5556
/// <inheritdoc/>
5657
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
@@ -67,6 +68,7 @@ public override void Initialize(AnalysisContext context)
6768
context.RegisterSyntaxNodeAction(ConstructorDeclarationAction, SyntaxKind.ConstructorDeclaration);
6869
context.RegisterSyntaxNodeAction(InvocationExpressionAction, SyntaxKind.InvocationExpression);
6970
context.RegisterSyntaxNodeAction(ObjectCreationExpressionAction, SyntaxKind.ObjectCreationExpression);
71+
context.RegisterSyntaxNodeAction(ImplicitObjectCreationExpressionAction, SyntaxKindEx.ImplicitObjectCreationExpression);
7072
}
7173

7274
private static void HandleObjectCreationExpression(SyntaxNodeAnalysisContext context)
@@ -89,6 +91,28 @@ private static void HandleObjectCreationExpression(SyntaxNodeAnalysisContext con
8991
}
9092
}
9193

94+
private static void HandleImplicitObjectCreationExpression(SyntaxNodeAnalysisContext context)
95+
{
96+
var implicitObjectCreation = (ImplicitObjectCreationExpressionSyntaxWrapper)context.Node;
97+
var argumentList = implicitObjectCreation.ArgumentList;
98+
99+
if (argumentList == null ||
100+
argumentList.IsMissing ||
101+
argumentList.Arguments.Count > 0)
102+
{
103+
return;
104+
}
105+
106+
if (!argumentList.OpenParenToken.IsMissing &&
107+
!argumentList.CloseParenToken.IsMissing)
108+
{
109+
CheckIfLocationOfOpenAndCloseTokensAreTheSame(
110+
context,
111+
argumentList.OpenParenToken,
112+
argumentList.CloseParenToken);
113+
}
114+
}
115+
92116
private static void HandleInvocationExpression(SyntaxNodeAnalysisContext context)
93117
{
94118
var invocationExpression = (InvocationExpressionSyntax)context.Node;

documentation/SA1112.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ The closing parenthesis or bracket in a call to a C# method or indexer, or the d
2323

2424
A violation of this rule occurs when a method or indexer does not take any parameters and the closing bracket of a call or declaration for the method or indexer is not placed on the same line as the opening bracket. The following example shows correct placement of the closing parenthesis:
2525

26+
This rule applies to calls to constructors and object creation expressions, including target-typed `new()` expressions in C# 9. When no arguments are provided, the closing parenthesis should remain on the same line as the opening parenthesis following `new`.
27+
2628
```csharp
2729
public string GetName()
2830
{

0 commit comments

Comments
 (0)