Skip to content

Commit

Permalink
Fix RCS1250 (#1404)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefpihrt authored Feb 17, 2024
1 parent 3f1a366 commit e928f82
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 18 deletions.
3 changes: 1 addition & 2 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix analyzer [RCS0049](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0049) ([PR](https://github.com/dotnet/roslynator/pull/1386))
- Fix analyzer [RCS1159](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1159) ([PR](https://github.com/dotnet/roslynator/pull/1390))
- Fix analyzer [RCS1019](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1019) ([PR](https://github.com/dotnet/roslynator/pull/1402))
- Fix analyzer [RCS1250](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1250) ([PR](https://github.com/dotnet/roslynator/pull/1403))
- Fix analyzer [RCS1060](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1060) ([PR](https://github.com/dotnet/roslynator/pull/1401))
- 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))
- 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)

## [4.10.0] - 2024-01-24
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,15 +237,25 @@ private static async Task<Document> ConvertToExplicitAsync(
CancellationToken cancellationToken)
{
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType;
var typeSymbol = (IArrayTypeSymbol)semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType;

ArrayCreationExpressionSyntax arrayCreation = ArrayCreationExpression(
Token(SyntaxKind.NewKeyword),
(ArrayTypeSyntax)typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(),
ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression))
.WithTriviaFrom(collectionExpression);
InitializerExpressionSyntax initializer = ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression);

return await document.ReplaceNodeAsync(collectionExpression, arrayCreation, cancellationToken).ConfigureAwait(false);
SyntaxNode newNode;
if (initializer is not null)
{
newNode = ArrayCreationExpression(
Token(SyntaxKind.NewKeyword),
(ArrayTypeSyntax)typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(),
initializer)
.WithTriviaFrom(collectionExpression);
}
else
{
newNode = CreateArrayEmpty(typeSymbol);
}

return await document.ReplaceNodeAsync(collectionExpression, newNode, cancellationToken).ConfigureAwait(false);
}

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

ImplicitArrayCreationExpressionSyntax implicitArrayCreation = ImplicitArrayCreationExpression(initializer)
.WithTriviaFrom(collectionExpression);
SyntaxNode newNode;
if (initializer is not null)
{
newNode = ImplicitArrayCreationExpression(initializer);
}
else
{
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

var typeSymbol = (IArrayTypeSymbol)semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType;

newNode = CreateArrayEmpty(typeSymbol);
}

return await document.ReplaceNodeAsync(collectionExpression, implicitArrayCreation, cancellationToken).ConfigureAwait(false);
newNode = newNode.WithTriviaFrom(collectionExpression);

return await document.ReplaceNodeAsync(collectionExpression, newNode, cancellationToken).ConfigureAwait(false);
}

private static InvocationExpressionSyntax CreateArrayEmpty(IArrayTypeSymbol typeSymbol)
{
return CSharpFactory.SimpleMemberInvocationExpression(
ParseExpression("global::System.Array").WithSimplifierAnnotation(),
(SimpleNameSyntax)ParseName($"Empty<{typeSymbol.ElementType.ToTypeSyntax().WithSimplifierAnnotation()}>"),
ArgumentList());
}

private static async Task<Document> ConvertToCollectionExpressionAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ internal class ImplicitOrExplicitArrayCreationAnalysis : ImplicitOrExplicitCreat
{
public static ImplicitOrExplicitArrayCreationAnalysis Instance { get; } = new();

public override void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context)
{
if (context.SemanticModel.GetTypeInfo(context.Node, context.CancellationToken).ConvertedType?.TypeKind == TypeKind.Array)
AnalyzeImplicit(ref context);
}

public override void AnalyzeExplicitCreation(ref SyntaxNodeAnalysisContext context)
{
if (context.Node.ContainsDiagnostics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ internal abstract class ImplicitOrExplicitCreationAnalysis
protected abstract void ReportCollectionExpressionToImplicit(ref SyntaxNodeAnalysisContext context);
#endif

public abstract void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context);

protected virtual bool IsInitializerObvious(ref SyntaxNodeAnalysisContext context) => false;

public virtual void AnalyzeExplicitCreation(ref SyntaxNodeAnalysisContext context)
Expand Down Expand Up @@ -301,12 +303,7 @@ public virtual void AnalyzeImplicitCreation(ref SyntaxNodeAnalysisContext contex
AnalyzeImplicit(ref context);
}

public virtual void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context)
{
AnalyzeImplicit(ref context);
}

private void AnalyzeImplicit(ref SyntaxNodeAnalysisContext context)
protected void AnalyzeImplicit(ref SyntaxNodeAnalysisContext context)
{
if (context.Node.ContainsDiagnostics)
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public override TypeStyle GetTypeStyle(ref SyntaxNodeAnalysisContext context)
return context.GetObjectCreationTypeStyle();
}

public override void AnalyzeCollectionExpression(ref SyntaxNodeAnalysisContext context)
{
if (context.SemanticModel.GetTypeInfo(context.Node, context.CancellationToken).ConvertedType?.TypeKind != TypeKind.Array)
AnalyzeImplicit(ref context);
}

protected override void ReportExplicitToImplicit(ref SyntaxNodeAnalysisContext context)
{
var objectCreation = (ObjectCreationExpressionSyntax)context.Node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,4 +503,78 @@ void M(List<string> x)
", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit)
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)]
public async Task Test_CollectionExpressionToImplicit_EmptyArray()
{
await VerifyDiagnosticAndFixAsync("""
using System;
class C
{
void M1()
{
string[] values = [|[]|];
}
void M2()
{
string[] values = [|["a", "b", "c"]|];
}
}
""", """
using System;
class C
{
void M1()
{
string[] values = Array.Empty<string>();
}
void M2()
{
string[] values = new[] { "a", "b", "c" };
}
}
""", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit)
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)]
public async Task Test_CollectionExpressionToExplicit_EmptyArray()
{
await VerifyDiagnosticAndFixAsync("""
using System;
class C
{
void M1()
{
string[] values = [|[]|];
}
void M2()
{
string[] values = [|["a", "b", "c"]|];
}
}
""", """
using System;
class C
{
void M1()
{
string[] values = Array.Empty<string>();
}
void M2()
{
string[] values = new string[] { "a", "b", "c" };
}
}
""", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Explicit)
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1881,4 +1881,26 @@ static C M()
""", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit)
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)]
public async Task TestNoDiagnostic_Array()
{
await VerifyNoDiagnosticAsync("""
using System;
class C
{
void M1()
{
string[] values = [];
}
void M2()
{
string[] values = ["a", "b", "c"];
}
}
""", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit)
.AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false));
}
}

0 comments on commit e928f82

Please sign in to comment.