Skip to content

Commit e928f82

Browse files
authored
Fix RCS1250 (#1404)
1 parent 3f1a366 commit e928f82

File tree

7 files changed

+153
-18
lines changed

7 files changed

+153
-18
lines changed

ChangeLog.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
- Fix analyzer [RCS0049](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0049) ([PR](https://github.com/dotnet/roslynator/pull/1386))
2121
- Fix analyzer [RCS1159](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1159) ([PR](https://github.com/dotnet/roslynator/pull/1390))
2222
- Fix analyzer [RCS1019](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1019) ([PR](https://github.com/dotnet/roslynator/pull/1402))
23-
- Fix analyzer [RCS1250](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1250) ([PR](https://github.com/dotnet/roslynator/pull/1403))
24-
- Fix analyzer [RCS1060](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1060) ([PR](https://github.com/dotnet/roslynator/pull/1401))
23+
- Fix analyzer [RCS1250](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1250) ([PR](https://github.com/dotnet/roslynator/pull/1403), [PR](https://github.com/dotnet/roslynator/pull/1404))
2524
- Fix code fix for [CS8600](https://josefpihrt.github.io/docs/roslynator/fixes/CS8600) changing the wrong type when casts or `var` are involved ([PR](https://github.com/dotnet/roslynator/pull/1393) by @jroessel)
2625

2726
## [4.10.0] - 2024-01-24

src/Analyzers.CodeFixes/CSharp/CodeFixes/UseExplicitlyOrImplicitlyTypedArrayCodeFixProvider.cs

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,25 @@ private static async Task<Document> ConvertToExplicitAsync(
237237
CancellationToken cancellationToken)
238238
{
239239
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
240-
ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType;
240+
var typeSymbol = (IArrayTypeSymbol)semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType;
241241

242-
ArrayCreationExpressionSyntax arrayCreation = ArrayCreationExpression(
243-
Token(SyntaxKind.NewKeyword),
244-
(ArrayTypeSyntax)typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(),
245-
ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression))
246-
.WithTriviaFrom(collectionExpression);
242+
InitializerExpressionSyntax initializer = ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression);
247243

248-
return await document.ReplaceNodeAsync(collectionExpression, arrayCreation, cancellationToken).ConfigureAwait(false);
244+
SyntaxNode newNode;
245+
if (initializer is not null)
246+
{
247+
newNode = ArrayCreationExpression(
248+
Token(SyntaxKind.NewKeyword),
249+
(ArrayTypeSyntax)typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(),
250+
initializer)
251+
.WithTriviaFrom(collectionExpression);
252+
}
253+
else
254+
{
255+
newNode = CreateArrayEmpty(typeSymbol);
256+
}
257+
258+
return await document.ReplaceNodeAsync(collectionExpression, newNode, cancellationToken).ConfigureAwait(false);
249259
}
250260

251261
private static async Task<Document> ConvertToImplicitAsync(
@@ -255,10 +265,31 @@ private static async Task<Document> ConvertToImplicitAsync(
255265
{
256266
InitializerExpressionSyntax initializer = ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression);
257267

258-
ImplicitArrayCreationExpressionSyntax implicitArrayCreation = ImplicitArrayCreationExpression(initializer)
259-
.WithTriviaFrom(collectionExpression);
268+
SyntaxNode newNode;
269+
if (initializer is not null)
270+
{
271+
newNode = ImplicitArrayCreationExpression(initializer);
272+
}
273+
else
274+
{
275+
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
276+
277+
var typeSymbol = (IArrayTypeSymbol)semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType;
278+
279+
newNode = CreateArrayEmpty(typeSymbol);
280+
}
260281

261-
return await document.ReplaceNodeAsync(collectionExpression, implicitArrayCreation, cancellationToken).ConfigureAwait(false);
282+
newNode = newNode.WithTriviaFrom(collectionExpression);
283+
284+
return await document.ReplaceNodeAsync(collectionExpression, newNode, cancellationToken).ConfigureAwait(false);
285+
}
286+
287+
private static InvocationExpressionSyntax CreateArrayEmpty(IArrayTypeSymbol typeSymbol)
288+
{
289+
return CSharpFactory.SimpleMemberInvocationExpression(
290+
ParseExpression("global::System.Array").WithSimplifierAnnotation(),
291+
(SimpleNameSyntax)ParseName($"Empty<{typeSymbol.ElementType.ToTypeSyntax().WithSimplifierAnnotation()}>"),
292+
ArgumentList());
262293
}
263294

264295
private static async Task<Document> ConvertToCollectionExpressionAsync(

src/Analyzers/CSharp/Analysis/ObjectCreation/ImplicitOrExplicitArrayCreationAnalysis.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ internal class ImplicitOrExplicitArrayCreationAnalysis : ImplicitOrExplicitCreat
1313
{
1414
public static ImplicitOrExplicitArrayCreationAnalysis Instance { get; } = new();
1515

16+
public override void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context)
17+
{
18+
if (context.SemanticModel.GetTypeInfo(context.Node, context.CancellationToken).ConvertedType?.TypeKind == TypeKind.Array)
19+
AnalyzeImplicit(ref context);
20+
}
21+
1622
public override void AnalyzeExplicitCreation(ref SyntaxNodeAnalysisContext context)
1723
{
1824
if (context.Node.ContainsDiagnostics)

src/Analyzers/CSharp/Analysis/ObjectCreation/ImplicitOrExplicitCreationAnalysis.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ internal abstract class ImplicitOrExplicitCreationAnalysis
5050
protected abstract void ReportCollectionExpressionToImplicit(ref SyntaxNodeAnalysisContext context);
5151
#endif
5252

53+
public abstract void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context);
54+
5355
protected virtual bool IsInitializerObvious(ref SyntaxNodeAnalysisContext context) => false;
5456

5557
public virtual void AnalyzeExplicitCreation(ref SyntaxNodeAnalysisContext context)
@@ -301,12 +303,7 @@ public virtual void AnalyzeImplicitCreation(ref SyntaxNodeAnalysisContext contex
301303
AnalyzeImplicit(ref context);
302304
}
303305

304-
public virtual void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context)
305-
{
306-
AnalyzeImplicit(ref context);
307-
}
308-
309-
private void AnalyzeImplicit(ref SyntaxNodeAnalysisContext context)
306+
protected void AnalyzeImplicit(ref SyntaxNodeAnalysisContext context)
310307
{
311308
if (context.Node.ContainsDiagnostics)
312309
return;

src/Analyzers/CSharp/Analysis/ObjectCreation/ImplicitOrExplicitObjectCreationAnalysis.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public override TypeStyle GetTypeStyle(ref SyntaxNodeAnalysisContext context)
1717
return context.GetObjectCreationTypeStyle();
1818
}
1919

20+
public override void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context)
21+
{
22+
if (context.SemanticModel.GetTypeInfo(context.Node, context.CancellationToken).ConvertedType?.TypeKind != TypeKind.Array)
23+
AnalyzeImplicit(ref context);
24+
}
25+
2026
protected override void ReportExplicitToImplicit(ref SyntaxNodeAnalysisContext context)
2127
{
2228
var objectCreation = (ObjectCreationExpressionSyntax)context.Node;

src/Tests/Analyzers.Tests/RCS1014UseExplicitlyTypedArrayOrViceVersaTests.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,4 +503,78 @@ void M(List<string> x)
503503
", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit)
504504
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
505505
}
506+
507+
[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)]
508+
public async Task Test_CollectionExpressionToImplicit_EmptyArray()
509+
{
510+
await VerifyDiagnosticAndFixAsync("""
511+
using System;
512+
513+
class C
514+
{
515+
void M1()
516+
{
517+
string[] values = [|[]|];
518+
}
519+
520+
void M2()
521+
{
522+
string[] values = [|["a", "b", "c"]|];
523+
}
524+
}
525+
""", """
526+
using System;
527+
528+
class C
529+
{
530+
void M1()
531+
{
532+
string[] values = Array.Empty<string>();
533+
}
534+
535+
void M2()
536+
{
537+
string[] values = new[] { "a", "b", "c" };
538+
}
539+
}
540+
""", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit)
541+
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
542+
}
543+
544+
[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)]
545+
public async Task Test_CollectionExpressionToExplicit_EmptyArray()
546+
{
547+
await VerifyDiagnosticAndFixAsync("""
548+
using System;
549+
550+
class C
551+
{
552+
void M1()
553+
{
554+
string[] values = [|[]|];
555+
}
556+
557+
void M2()
558+
{
559+
string[] values = [|["a", "b", "c"]|];
560+
}
561+
}
562+
""", """
563+
using System;
564+
565+
class C
566+
{
567+
void M1()
568+
{
569+
string[] values = Array.Empty<string>();
570+
}
571+
572+
void M2()
573+
{
574+
string[] values = new string[] { "a", "b", "c" };
575+
}
576+
}
577+
""", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Explicit)
578+
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
579+
}
506580
}

src/Tests/Analyzers.Tests/RCS1250UseImplicitOrExplicitObjectCreationTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,4 +1881,26 @@ static C M()
18811881
""", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit)
18821882
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true));
18831883
}
1884+
1885+
[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)]
1886+
public async Task TestNoDiagnostic_Array()
1887+
{
1888+
await VerifyNoDiagnosticAsync("""
1889+
using System;
1890+
1891+
class C
1892+
{
1893+
void M1()
1894+
{
1895+
string[] values = [];
1896+
}
1897+
1898+
void M2()
1899+
{
1900+
string[] values = ["a", "b", "c"];
1901+
}
1902+
}
1903+
""", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit)
1904+
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
1905+
}
18841906
}

0 commit comments

Comments
 (0)