diff --git a/ChangeLog.md b/ChangeLog.md index ed9b65a368..400de8f52b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -14,12 +14,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make analyzer [RCS0014](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0014) obsolete - Add code fix "Declare as nullable" ([PR](/~https://github.com/dotnet/roslynator/pull/1333)) - Applicable to: `CS8600`, `CS8610`, `CS8765` and `CS8767` +- Add option `roslynator_use_collection_expression = true|false` ([PR](/~https://github.com/dotnet/roslynator/pull/1325)) + - Applicable to [RCS1014](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1014) and [RCS1250](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1250) ### Changed - 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), [PR](/~https://github.com/dotnet/roslynator/pull/1327)) - [TestFramework] Bump `MSTest.TestFramerk` to `3.1.1` ([PR](/~https://github.com/dotnet/roslynator/pull/1332)) - [TestFramework] Bump `xunit.assert` to `2.6.2` ([PR](/~https://github.com/dotnet/roslynator/pull/1332)) +- Bump Roslyn to 4.7.0 ([PR](/~https://github.com/dotnet/roslynator/pull/1325)) ## [4.7.0] - 2023-12-03 diff --git a/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseExplicitlyOrImplicitlyTypedArrayCodeFixProvider.cs b/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseExplicitlyOrImplicitlyTypedArrayCodeFixProvider.cs index 9a0bdd8231..da9be67985 100644 --- a/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseExplicitlyOrImplicitlyTypedArrayCodeFixProvider.cs +++ b/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseExplicitlyOrImplicitlyTypedArrayCodeFixProvider.cs @@ -12,7 +12,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslynator.CodeFixes; +using Roslynator.CSharp.Analysis; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Roslynator.CSharp.SyntaxRefactorings; namespace Roslynator.CSharp.CodeFixes; @@ -20,6 +22,10 @@ namespace Roslynator.CSharp.CodeFixes; [Shared] public sealed class UseExplicitlyOrImplicitlyTypedArrayCodeFixProvider : BaseCodeFixProvider { + private const string UseExplicitlyTypedArrayTitle = "Use explicit type"; + private const string UseImplicitlyTypedArrayTitle = "Use implicit type"; + private const string UseCollectionExpressionTitle = "Use collection expression"; + public override ImmutableArray FixableDiagnosticIds { get { return ImmutableArray.Create(DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray); } @@ -28,79 +34,105 @@ public override ImmutableArray FixableDiagnosticIds public override FixAllProvider GetFixAllProvider() { return FixAllProvider.Create(async (context, document, diagnostics) => await FixAllAsync(document, diagnostics, context.CancellationToken).ConfigureAwait(false)); - } - private static async Task FixAllAsync(Document document, ImmutableArray diagnostics, CancellationToken cancellationToken) - { - foreach (Diagnostic diagnostic in diagnostics.OrderByDescending(d => d.Location.SourceSpan.Start)) + static async Task FixAllAsync( + Document document, + ImmutableArray diagnostics, + CancellationToken cancellationToken) { - document = await ApplyFixToDocumentAsync(document, diagnostic, cancellationToken).ConfigureAwait(false); - } + foreach (Diagnostic diagnostic in diagnostics.OrderByDescending(d => d.Location.SourceSpan.Start)) + { + (Func> CreateChangedDocument, string) result + = await GetChangedDocumentAsync(document, diagnostic, cancellationToken).ConfigureAwait(false); - return document; + document = await result.CreateChangedDocument(cancellationToken).ConfigureAwait(false); + } + + return document; + } } public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); - - if (!TryFindFirstAncestorOrSelf( - root, - context.Span, - out SyntaxNode node, - predicate: f => f.IsKind(SyntaxKind.ImplicitArrayCreationExpression, SyntaxKind.ArrayCreationExpression))) - { - return; - } - Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; - string title = node switch - { - ImplicitArrayCreationExpressionSyntax => "Use explicitly typed array", - ArrayCreationExpressionSyntax => "Use implicitly typed array", - _ => throw new InvalidOperationException(), - }; + (Func> CreateChangedDocument, string Title) + = await GetChangedDocumentAsync(document, diagnostic, context.CancellationToken).ConfigureAwait(false); CodeAction codeAction = CodeAction.Create( - title, - ct => ApplyFixToDocumentAsync(document, diagnostic, ct), - GetEquivalenceKey(diagnostic)); + Title, + ct => CreateChangedDocument(ct), + GetEquivalenceKey(diagnostic, (Title == UseCollectionExpressionTitle) ? "UseCollectionExpression" : null)); context.RegisterCodeFix(codeAction, diagnostic); } - public static async Task ApplyFixToDocumentAsync(Document document, Diagnostic diag, CancellationToken cancellationToken) + private static async Task<(Func>, string)> GetChangedDocumentAsync( + Document document, + Diagnostic diagnostic, + CancellationToken cancellationToken) { SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf( root, - diag.Location.SourceSpan, + diagnostic.Location.SourceSpan, out SyntaxNode node, - predicate: f => f.IsKind(SyntaxKind.ImplicitArrayCreationExpression, SyntaxKind.ArrayCreationExpression))) + predicate: f => f.IsKind( + SyntaxKind.ImplicitArrayCreationExpression, + SyntaxKind.ArrayCreationExpression, + SyntaxKind.CollectionExpression))) { - return null; + throw new InvalidOperationException(); } - return node switch + if (node is ArrayCreationExpressionSyntax arrayCreation) + { + if (diagnostic.Properties.ContainsKey(DiagnosticPropertyKeys.ExplicitToCollectionExpression)) + { + return (ct => ConvertToCollectionExpressionAsync(document, arrayCreation, ct), UseCollectionExpressionTitle); + } + else + { + return (ct => ConvertToImplicitAsync(document, arrayCreation, ct), UseImplicitlyTypedArrayTitle); + } + } + else if (node is ImplicitArrayCreationExpressionSyntax implicitArrayCreation) + { + if (diagnostic.Properties.ContainsKey(DiagnosticPropertyKeys.ImplicitToCollectionExpression)) + { + return (ct => ConvertToCollectionExpressionAsync(document, implicitArrayCreation, ct), UseCollectionExpressionTitle); + } + else + { + return (ct => ConvertToExplicitAsync(document, implicitArrayCreation, ct), UseExplicitlyTypedArrayTitle); + } + } + else if (node is CollectionExpressionSyntax collectionExpression) + { + if (diagnostic.Properties.ContainsKey(DiagnosticPropertyKeys.CollectionExpressionToImplicit)) + { + return (ct => ConvertToImplicitAsync(document, collectionExpression, ct), UseImplicitlyTypedArrayTitle); + } + else + { + return (ct => ConvertToExplicitAsync(document, collectionExpression, ct), UseExplicitlyTypedArrayTitle); + } + } + else { - ImplicitArrayCreationExpressionSyntax implicitArrayCreation => await ChangeArrayTypeToExplicitAsync(document, implicitArrayCreation, cancellationToken).ConfigureAwait(false), - ArrayCreationExpressionSyntax arrayCreation => await ChangeArrayTypeToImplicitAsync(document, arrayCreation, cancellationToken).ConfigureAwait(false), - _ => throw new InvalidOperationException() - }; + throw new InvalidOperationException(); + } } - private static async Task ChangeArrayTypeToExplicitAsync( + private static async Task ConvertToExplicitAsync( Document document, ImplicitArrayCreationExpressionSyntax implicitArrayCreation, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(implicitArrayCreation, cancellationToken); - var arrayType = (ArrayTypeSyntax)typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(); SyntaxToken newKeyword = implicitArrayCreation.NewKeyword; @@ -124,7 +156,24 @@ private static async Task ChangeArrayTypeToExplicitAsync( return await document.ReplaceNodeAsync(implicitArrayCreation, newNode, cancellationToken).ConfigureAwait(false); } - private static async Task ChangeArrayTypeToImplicitAsync( + private static async Task ConvertToExplicitAsync( + Document document, + CollectionExpressionSyntax collectionExpression, + CancellationToken cancellationToken) + { + SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(collectionExpression, cancellationToken).ConvertedType; + + ArrayCreationExpressionSyntax arrayCreation = ArrayCreationExpression( + Token(SyntaxKind.NewKeyword), + (ArrayTypeSyntax)typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(), + ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression)) + .WithTriviaFrom(collectionExpression); + + return await document.ReplaceNodeAsync(collectionExpression, arrayCreation, cancellationToken).ConfigureAwait(false); + } + + private static async Task ConvertToImplicitAsync( Document document, ArrayCreationExpressionSyntax arrayCreation, CancellationToken cancellationToken) @@ -159,4 +208,41 @@ private static async Task ChangeArrayTypeToImplicitAsync( return await document.ReplaceNodeAsync(arrayCreation, implicitArrayCreation, cancellationToken).ConfigureAwait(false); } + + private static async Task ConvertToImplicitAsync( + Document document, + CollectionExpressionSyntax collectionExpression, + CancellationToken cancellationToken) + { + InitializerExpressionSyntax initializer = ConvertCollectionExpressionToInitializer(collectionExpression, SyntaxKind.ArrayInitializerExpression); + + ImplicitArrayCreationExpressionSyntax implicitArrayCreation = ImplicitArrayCreationExpression(initializer) + .WithTriviaFrom(collectionExpression); + + return await document.ReplaceNodeAsync(collectionExpression, implicitArrayCreation, cancellationToken).ConfigureAwait(false); + } + + private static async Task ConvertToCollectionExpressionAsync( + Document document, + ArrayCreationExpressionSyntax arrayCreation, + CancellationToken cancellationToken) + { + CollectionExpressionSyntax collectionExpression = ConvertInitializerToCollectionExpression(arrayCreation.Initializer) + .WithTriviaFrom(arrayCreation) + .WithFormatterAnnotation(); + + return await document.ReplaceNodeAsync(arrayCreation, collectionExpression, cancellationToken).ConfigureAwait(false); + } + + private static async Task ConvertToCollectionExpressionAsync( + Document document, + ImplicitArrayCreationExpressionSyntax implicitArrayCreation, + CancellationToken cancellationToken) + { + CollectionExpressionSyntax collectionExpression = ConvertInitializerToCollectionExpression(implicitArrayCreation.Initializer) + .WithTriviaFrom(implicitArrayCreation) + .WithFormatterAnnotation(); + + return await document.ReplaceNodeAsync(implicitArrayCreation, collectionExpression, cancellationToken).ConfigureAwait(false); + } } diff --git a/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseImplicitOrExplicitObjectCreationCodeFixProvider.cs b/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseImplicitOrExplicitObjectCreationCodeFixProvider.cs index 2236a0169c..5386cfc958 100644 --- a/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseImplicitOrExplicitObjectCreationCodeFixProvider.cs +++ b/src/Analyzers.CodeFixes/CSharp/CodeFixes/UseImplicitOrExplicitObjectCreationCodeFixProvider.cs @@ -10,7 +10,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslynator.CodeFixes; +using Roslynator.CSharp.Analysis; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Roslynator.CSharp.SyntaxRefactorings; namespace Roslynator.CSharp.CodeFixes; @@ -18,6 +20,12 @@ namespace Roslynator.CSharp.CodeFixes; [Shared] public class UseImplicitOrExplicitObjectCreationCodeFixProvider : BaseCodeFixProvider { + private const string UseExplicitObjectCreationTitle = "Use explicit type"; + private const string UseImplicitObjectCreationTitle = "Use implicit type"; + private const string UseCollectionExpressionTitle = "Use collection expression"; + + private const string UseCollectionExpressionEquivalenceKey = "UseCollectionExpression"; + public sealed override ImmutableArray FixableDiagnosticIds { get { return ImmutableArray.Create(DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation); } @@ -31,7 +39,11 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) root, context.Span, out SyntaxNode node, - predicate: f => f.IsKind(SyntaxKind.ObjectCreationExpression, SyntaxKind.ImplicitObjectCreationExpression, SyntaxKind.VariableDeclaration))) + predicate: f => f.IsKind( + SyntaxKind.ObjectCreationExpression, + SyntaxKind.ImplicitObjectCreationExpression, + SyntaxKind.CollectionExpression, + SyntaxKind.VariableDeclaration))) { return; } @@ -41,14 +53,27 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) if (node is ObjectCreationExpressionSyntax objectCreation) { + bool useCollectionExpression = diagnostic.Properties.ContainsKey(DiagnosticPropertyKeys.ExplicitToCollectionExpression); + CodeAction codeAction = CodeAction.Create( - "Use implicit object creation", + (useCollectionExpression) + ? UseCollectionExpressionTitle + : UseImplicitObjectCreationTitle, ct => { - ImplicitObjectCreationExpressionSyntax implicitObjectCreation = ImplicitObjectCreationExpression( - objectCreation.NewKeyword.WithTrailingTrivia(objectCreation.NewKeyword.TrailingTrivia.EmptyIfWhitespace()), - objectCreation.ArgumentList ?? ArgumentList().WithTrailingTrivia(objectCreation.Type.GetTrailingTrivia()), - objectCreation.Initializer); + SyntaxNode newNode; + + if (useCollectionExpression) + { + newNode = ConvertInitializerToCollectionExpression(objectCreation.Initializer).WithFormatterAnnotation(); + } + else + { + newNode = ImplicitObjectCreationExpression( + objectCreation.NewKeyword.WithTrailingTrivia(objectCreation.NewKeyword.TrailingTrivia.EmptyIfWhitespace()), + objectCreation.ArgumentList ?? ArgumentList().WithTrailingTrivia(objectCreation.Type.GetTrailingTrivia()), + objectCreation.Initializer); + } if (objectCreation.IsParentKind(SyntaxKind.EqualsValueClause) && objectCreation.Parent.IsParentKind(SyntaxKind.VariableDeclarator) @@ -56,55 +81,130 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) && variableDeclaration.Type.IsVar) { VariableDeclarationSyntax newVariableDeclaration = variableDeclaration - .ReplaceNode(objectCreation, implicitObjectCreation) + .ReplaceNode(objectCreation, newNode) .WithType(objectCreation.Type.WithTriviaFrom(variableDeclaration.Type)); return document.ReplaceNodeAsync(variableDeclaration, newVariableDeclaration, ct); } else { - return document.ReplaceNodeAsync(objectCreation, implicitObjectCreation, ct); + return document.ReplaceNodeAsync(objectCreation, newNode, ct); } }, - GetEquivalenceKey(diagnostic)); + GetEquivalenceKey(diagnostic, (useCollectionExpression) ? UseCollectionExpressionEquivalenceKey : null)); context.RegisterCodeFix(codeAction, diagnostic); } else if (node is ImplicitObjectCreationExpressionSyntax implicitObjectCreation) { - CodeAction codeAction = CodeAction.Create( - "Use explicit object creation", - async ct => - { - SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(ct).ConfigureAwait(false); + if (diagnostic.Properties.ContainsKey(DiagnosticPropertyKeys.ImplicitToCollectionExpression)) + { + CodeAction codeAction = CodeAction.Create( + UseCollectionExpressionTitle, + async ct => + { + CollectionExpressionSyntax collectionExpression = ConvertInitializerToCollectionExpression(implicitObjectCreation.Initializer) + .PrependToLeadingTrivia(implicitObjectCreation.NewKeyword.LeadingTrivia); - ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(implicitObjectCreation, ct); + if (implicitObjectCreation.Initializer is null) + collectionExpression = collectionExpression.WithTrailingTrivia(implicitObjectCreation.ArgumentList.GetTrailingTrivia()); - TypeSyntax type = typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(); + collectionExpression = collectionExpression.WithFormatterAnnotation(); - SyntaxToken newKeyword = implicitObjectCreation.NewKeyword; + return await document.ReplaceNodeAsync(implicitObjectCreation, collectionExpression, ct).ConfigureAwait(false); + }, + GetEquivalenceKey(diagnostic, UseCollectionExpressionEquivalenceKey)); - if (!newKeyword.TrailingTrivia.Any()) - newKeyword = newKeyword.WithTrailingTrivia(ElasticSpace); + context.RegisterCodeFix(codeAction, diagnostic); + } + else + { + CodeAction codeAction = CodeAction.Create( + UseExplicitObjectCreationTitle, + async ct => + { + SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(ct).ConfigureAwait(false); + ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(implicitObjectCreation, ct); + TypeSyntax type = typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(); - ObjectCreationExpressionSyntax objectCreation = ObjectCreationExpression( - newKeyword, - type, - implicitObjectCreation.ArgumentList, - implicitObjectCreation.Initializer); + SyntaxToken newKeyword = implicitObjectCreation.NewKeyword; - return await document.ReplaceNodeAsync(implicitObjectCreation, objectCreation, ct).ConfigureAwait(false); - }, - GetEquivalenceKey(diagnostic)); + if (!newKeyword.TrailingTrivia.Any()) + newKeyword = newKeyword.WithTrailingTrivia(ElasticSpace); - context.RegisterCodeFix(codeAction, diagnostic); + ObjectCreationExpressionSyntax objectCreation = ObjectCreationExpression( + newKeyword, + type, + implicitObjectCreation.ArgumentList, + implicitObjectCreation.Initializer); + + return await document.ReplaceNodeAsync(implicitObjectCreation, objectCreation, ct).ConfigureAwait(false); + }, + GetEquivalenceKey(diagnostic)); + + context.RegisterCodeFix(codeAction, diagnostic); + } + } + else if (node is CollectionExpressionSyntax collectionExpression) + { + if (diagnostic.Properties.ContainsKey(DiagnosticPropertyKeys.CollectionExpressionToImplicit)) + { + CodeAction codeAction = CodeAction.Create( + UseImplicitObjectCreationTitle, + async ct => + { + SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(ct).ConfigureAwait(false); + ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(collectionExpression, ct).ConvertedType; + + ImplicitObjectCreationExpressionSyntax objectCreation = ImplicitObjectCreationExpression( + Token(SyntaxKind.NewKeyword), + ArgumentList(), + ConvertCollectionExpressionToInitializer( + collectionExpression, + SyntaxKind.CollectionInitializerExpression)) + .WithTriviaFrom(collectionExpression); + + return await document.ReplaceNodeAsync(collectionExpression, objectCreation, ct).ConfigureAwait(false); + }, + GetEquivalenceKey(diagnostic)); + + context.RegisterCodeFix(codeAction, diagnostic); + } + else + { + CodeAction codeAction = CodeAction.Create( + UseExplicitObjectCreationTitle, + async ct => + { + SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(ct).ConfigureAwait(false); + ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(collectionExpression, ct).ConvertedType; + TypeSyntax type = typeSymbol.ToTypeSyntax().WithSimplifierAnnotation(); + + ObjectCreationExpressionSyntax objectCreation = ObjectCreationExpression( + Token(SyntaxKind.NewKeyword), + type, + ArgumentList(), + ConvertCollectionExpressionToInitializer( + collectionExpression, + SyntaxKind.CollectionInitializerExpression)); + + objectCreation = objectCreation + .WithLeadingTrivia(collectionExpression.GetLeadingTrivia()) + .WithTrailingTrivia(collectionExpression.GetTrailingTrivia()); + + return await document.ReplaceNodeAsync(collectionExpression, objectCreation, ct).ConfigureAwait(false); + }, + GetEquivalenceKey(diagnostic)); + + context.RegisterCodeFix(codeAction, diagnostic); + } } else { var variableDeclaration = (VariableDeclarationSyntax)node; CodeAction codeAction = CodeAction.Create( - "Use explicit object creation", + UseExplicitObjectCreationTitle, ct => { var implicitObjectCreation = (ImplicitObjectCreationExpressionSyntax)variableDeclaration.Variables.Single().Initializer.Value; diff --git a/src/Analyzers.CodeFixes/Roslynator.Analyzers.nuspec b/src/Analyzers.CodeFixes/Roslynator.Analyzers.nuspec index 38a5cae875..ba5c9a1a83 100644 --- a/src/Analyzers.CodeFixes/Roslynator.Analyzers.nuspec +++ b/src/Analyzers.CodeFixes/Roslynator.Analyzers.nuspec @@ -11,7 +11,7 @@ false A collection of 200+ analyzers for C#, powered by Roslyn. - - This package is dependent on Microsoft.CodeAnalysis.CSharp.Workspaces 4.6.0. + - This package is dependent on Microsoft.CodeAnalysis.CSharp.Workspaces 4.7.0. A collection of 200+ analyzers for C#, powered by Roslyn. Copyright (c) 2016-2023 Josef Pihrt Roslyn Analyzer Refactoring Productivity CodeAnalysis C# CSharp diff --git a/src/Analyzers.xml b/src/Analyzers.xml index 5f30d9d116..d3b2e49c3e 100644 --- a/src/Analyzers.xml +++ b/src/Analyzers.xml @@ -1879,7 +1879,7 @@ foreach (var item in items) RCS1014 UseExplicitlyOrImplicitlyTypedArray Use explicitly/implicitly typed array - Use {0} typed array + {0} Info false @@ -1890,6 +1890,7 @@ foreach (var item in items) + - 4.6.0 + 4.7.0 3.3.4 4.8.0 4.8.0 diff --git a/src/Formatting.Analyzers.CodeFixes/Roslynator.Formatting.Analyzers.nuspec b/src/Formatting.Analyzers.CodeFixes/Roslynator.Formatting.Analyzers.nuspec index c4c34645fd..632b6aa5fb 100644 --- a/src/Formatting.Analyzers.CodeFixes/Roslynator.Formatting.Analyzers.nuspec +++ b/src/Formatting.Analyzers.CodeFixes/Roslynator.Formatting.Analyzers.nuspec @@ -11,7 +11,7 @@ false A collection of formatting analyzers, powered by Roslyn. - - This package is dependent on Microsoft.CodeAnalysis.CSharp.Workspaces 4.6.0. + - This package is dependent on Microsoft.CodeAnalysis.CSharp.Workspaces 4.7.0. - All analyzers are disabled by default. A collection of formatting analyzers, powered by Roslyn. Copyright (c) 2016-2023 Josef Pihrt diff --git a/src/Formatting.Analyzers/CSharp/PutEmbeddedStatementOnItsOwnLineAnalyzer.cs b/src/Formatting.Analyzers/CSharp/PutEmbeddedStatementOnItsOwnLineAnalyzer.cs index c6d1232f80..0f0fd4a26a 100644 --- a/src/Formatting.Analyzers/CSharp/PutEmbeddedStatementOnItsOwnLineAnalyzer.cs +++ b/src/Formatting.Analyzers/CSharp/PutEmbeddedStatementOnItsOwnLineAnalyzer.cs @@ -99,6 +99,9 @@ internal static void AnalyzeFixedStatement(SyntaxNodeAnalysisContext context) private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxToken token, StatementSyntax statement) { + if (statement.IsMissing) + return; + TriviaBlock block = TriviaBlock.FromBetween(token, statement); if (block.Kind == TriviaBlockKind.NoNewLine) diff --git a/src/Tests/Analyzers.Tests/RCS1014UseExplicitlyTypedArrayOrViceVersaTests.cs b/src/Tests/Analyzers.Tests/RCS1014UseExplicitlyTypedArrayOrViceVersaTests.cs index 37711b3203..8543630200 100644 --- a/src/Tests/Analyzers.Tests/RCS1014UseExplicitlyTypedArrayOrViceVersaTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1014UseExplicitlyTypedArrayOrViceVersaTests.cs @@ -34,6 +34,39 @@ void M() ", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Explicit)); } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_TypeIsObvious() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + private object[] f = new [|string|][] { string.Empty }; +} +", @" +class C +{ + private object[] f = new[] { string.Empty }; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_TypeIsObvious_ToCollectionExpression() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + private object[] f = new [|string|][] { string.Empty }; +} +", @" +class C +{ + private object[] f = [string.Empty]; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] public async Task Test_TypeIsNotObvious() { @@ -192,6 +225,282 @@ void M() var items = new string[0]; } } -", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.AccessibilityModifiers_Implicit)); +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task TestNoDiagnostic_AssignmentToObject() + { + await VerifyNoDiagnosticAsync(@" +class C +{ + void M() + { + object o = new[] { "", "" }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task TestNoDiagnostic_ForEachExpression() + { + await VerifyNoDiagnosticAsync(@" +class C +{ + void M() + { + foreach (string item in new[] { "", "" }) + { + } + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_ExplicitToCollectionExpression_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + void M(string[] arr) + { + arr = new [|string|][] { """" }; + } +} +", @" +class C +{ + void M(string[] arr) + { + arr = [""""]; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_ExplicitToCollectionExpression_ImplicitStyle_WithComments() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + void M(string[] arr) + { + arr = new [|string|][] + { + """", // a + string.Empty // b + }; + } +} +", @" +class C +{ + void M(string[] arr) + { + arr = [ + """", // a + string.Empty // b + ]; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_ExplicitToCollectionExpression_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + string[] P { get; } = new [|string|][] { """" }; +} +", @" +class C +{ + string[] P { get; } = [""""]; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_ImplicitToCollectionExpression_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + void M(string[] arr) + { + arr = [|new[]|] { """" }; + } +} +", @" +class C +{ + void M(string[] arr) + { + arr = [""""]; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_ImplicitToCollectionExpression_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + string[] P { get; } = [|new[]|] { """" }; +} +", @" +class C +{ + string[] P { get; } = [""""]; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToExplicit_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + void M(string[] arr) + { + arr = [|[""""]|]; + } +} +", @" +class C +{ + void M(string[] arr) + { + arr = new string[] { """" }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Explicit)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToExplicit_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + private string _f = """"; + + void M(string[] arr) + { + arr = [|[_f]|]; + } +} +", @" +class C +{ + private string _f = """"; + + void M(string[] arr) + { + arr = new string[] { _f }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToImplicit_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + void M(string[] arr) + { + arr = [|[""""]|]; + } +} +", @" +class C +{ + void M(string[] arr) + { + arr = new[] { """" }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToImplicit_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + string[] P { get; } = [|[""""]|]; +} +", @" +class C +{ + string[] P { get; } = new[] { """" }; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToImplicit_ImplicitWhenObviousStyle2() + { + await VerifyNoDiagnosticAsync(@" +class C +{ + void M(string p1, object p2) + { + var nodes = new[] { p1, p2 }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToExplicit_NotArray() + { + await VerifyNoDiagnosticAsync(@" +using System.Collections.Generic; +class C +{ + void M(List x) + { + x = []; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Explicit)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task Test_CollectionExpressionToImplicit_NotArray() + { + await VerifyNoDiagnosticAsync(@" +using System.Collections.Generic; +class C +{ + void M(List x) + { + x = []; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false)); } } diff --git a/src/Tests/Analyzers.Tests/RCS1014UseImplicitlyTypedArrayTests.cs b/src/Tests/Analyzers.Tests/RCS1014UseImplicitlyTypedArrayTests.cs index 5379cbc4f2..13a0436c70 100644 --- a/src/Tests/Analyzers.Tests/RCS1014UseImplicitlyTypedArrayTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1014UseImplicitlyTypedArrayTests.cs @@ -114,7 +114,7 @@ public async Task Test_NestedArray() await VerifyDiagnosticAndFixAsync(@" class C { - string[][] _f = new [|string[]|][] + string[][] _f = new [|string|][][] { new[] { """" }, }; @@ -181,4 +181,19 @@ void M() } ", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious)); } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitlyOrImplicitlyTypedArray)] + public async Task TestNoDiagnostic_UseVarInsteadOfObjectCreation() + { + await VerifyNoDiagnosticAsync(@" +class C +{ + void M() + { + var items = new string[] { string.Empty }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ArrayCreationTypeStyle, ConfigOptionValues.ArrayCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseVarInsteadOfImplicitObjectCreation, true)); + } } diff --git a/src/Tests/Analyzers.Tests/RCS1250UseImplicitOrExplicitObjectCreationTests.cs b/src/Tests/Analyzers.Tests/RCS1250UseImplicitOrExplicitObjectCreationTests.cs index 246b385fdc..6e8251facf 100644 --- a/src/Tests/Analyzers.Tests/RCS1250UseImplicitOrExplicitObjectCreationTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1250UseImplicitOrExplicitObjectCreationTests.cs @@ -680,7 +680,7 @@ class C { string M() { - return new string(' ', 1); + return new(' ', 1); } } ", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious)); @@ -1600,4 +1600,258 @@ void M() } ", options: Options.AddConfigOption(ConfigOptionKeys.UseVarInsteadOfImplicitObjectCreation, false)); } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task TestNoDiagnostic_ForEachExpression2() + { + await VerifyNoDiagnosticAsync(@" +class C +{ + string[] M() + { + return ["""", """"]; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_ExplicitToCollectionExpression_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = new [|List|]() { """" }; + } +} +", @" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = [""""]; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_ExplicitToCollectionExpression_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + List P { get; } = new [|List|]() { """" }; +} +", @" +using System.Collections.Generic; +class C +{ + List P { get; } = [""""]; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_ImplicitToCollectionExpression_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = [|new() { """" }|]; + } +} +", @" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = [""""]; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_ImplicitToCollectionExpression_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + List P { get; } = [|new() { """" }|]; +} +", @" +using System.Collections.Generic; +class C +{ + List P { get; } = [""""]; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_CollectionExpressionToExplicit_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = [|[""""]|]; + } +} +", @" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = new List() { """" }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Explicit)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_CollectionExpressionToExplicit_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + private string _f = """"; + + void M(List items) + { + items = [|[_f]|]; + } +} +", @" +using System.Collections.Generic; +class C +{ + private string _f = """"; + + void M(List items) + { + items = new List() { _f }; + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_CollectionExpressionToImplicit_ImplicitStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = [|[""""]|]; + } +} +", @" +using System.Collections.Generic; +class C +{ + void M(List items) + { + items = new() { """" }; + } +} +", options: Options + .AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Implicit) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_CollectionExpressionToImplicit_ImplicitWhenObviousStyle() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + List P { get; } = [|[""""]|]; +} +", @" +using System.Collections.Generic; +class C +{ + List P { get; } = new() { """" }; +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, false)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_ExplicitWithParameters() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C : List +{ + C() { } + C(string p) { } + + C M() + { + return new [|C|](""s""); + } +} +", @" +using System.Collections.Generic; +class C : List +{ + C() { } + C(string p) { } + + C M() + { + return new(""s""); + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious) + .AddConfigOption(ConfigOptionKeys.UseCollectionExpression, true)); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseImplicitOrExplicitObjectCreation)] + public async Task Test_CollectionExpressionToExplicit() + { + await VerifyDiagnosticAndFixAsync(@" +using System.Collections.Generic; +class C +{ + void M(List x) + { + x = [|[]|]; + } +} +", @" +using System.Collections.Generic; +class C +{ + void M(List x) + { + x = new List(); + } +} +", options: Options.AddConfigOption(ConfigOptionKeys.ObjectCreationTypeStyle, ConfigOptionValues.ObjectCreationTypeStyle_Explicit)); + } } diff --git a/src/Tools/CodeGeneration/CSharp/Symbols.Generated.cs b/src/Tools/CodeGeneration/CSharp/Symbols.Generated.cs index 5de5318ecc..de2a7d6147 100644 --- a/src/Tools/CodeGeneration/CSharp/Symbols.Generated.cs +++ b/src/Tools/CodeGeneration/CSharp/Symbols.Generated.cs @@ -270,6 +270,12 @@ public static IEnumerable GetKinds(INamedTypeSymbol syntaxSymbol) break; } + case "CollectionExpressionSyntax": + { + yield return SyntaxKind.CollectionExpression; + break; + } + case "CompilationUnitSyntax": { yield return SyntaxKind.CompilationUnit; @@ -518,6 +524,12 @@ public static IEnumerable GetKinds(INamedTypeSymbol syntaxSymbol) break; } + case "ExpressionElementSyntax": + { + yield return SyntaxKind.ExpressionElement; + break; + } + case "ExpressionStatementSyntax": { yield return SyntaxKind.ExpressionStatement; @@ -1219,6 +1231,12 @@ public static IEnumerable GetKinds(INamedTypeSymbol syntaxSymbol) break; } + case "SpreadElementSyntax": + { + yield return SyntaxKind.SpreadElement; + break; + } + case "StackAllocArrayCreationExpressionSyntax": { yield return SyntaxKind.StackAllocArrayCreationExpression; diff --git a/src/Tools/CodeGeneration/CSharp/SymbolsGetKindsGenerator.cs b/src/Tools/CodeGeneration/CSharp/SymbolsGetKindsGenerator.cs index ee79a491c6..51c83a323f 100644 --- a/src/Tools/CodeGeneration/CSharp/SymbolsGetKindsGenerator.cs +++ b/src/Tools/CodeGeneration/CSharp/SymbolsGetKindsGenerator.cs @@ -1352,6 +1352,21 @@ static IEnumerable GetSyntaxKinds(INamedTypeSymbol syntaxSymbol) yield return SyntaxKind.ScopedType; break; } + case "CollectionExpressionSyntax": + { + yield return SyntaxKind.CollectionExpression; + break; + } + case "ExpressionElementSyntax": + { + yield return SyntaxKind.ExpressionElement; + break; + } + case "SpreadElementSyntax": + { + yield return SyntaxKind.SpreadElement; + break; + } default: { throw new InvalidOperationException(syntaxSymbol.Name); diff --git a/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.Generated.cs b/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.Generated.cs index e2dc9675bf..efa24901b9 100644 --- a/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.Generated.cs +++ b/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.Generated.cs @@ -3377,6 +3377,42 @@ protected virtual bool ShouldVisit(IPropertySymbol propertySymbol) } } + case "CollectionExpressionSyntax": + { + switch (propertySymbol.Name) + { + case "OpenBracketToken": + case "Elements": + case "CloseBracketToken": + return true; + default: + throw new InvalidOperationException($"Unrecognized property '{propertySymbol.ToDisplayString(SymbolDisplayFormats.Test)}'"); + } + } + + case "ExpressionElementSyntax": + { + switch (propertySymbol.Name) + { + case "Expression": + return true; + default: + throw new InvalidOperationException($"Unrecognized property '{propertySymbol.ToDisplayString(SymbolDisplayFormats.Test)}'"); + } + } + + case "SpreadElementSyntax": + { + switch (propertySymbol.Name) + { + case "OperatorToken": + case "Expression": + return true; + default: + throw new InvalidOperationException($"Unrecognized property '{propertySymbol.ToDisplayString(SymbolDisplayFormats.Test)}'"); + } + } + default: { throw new InvalidOperationException($"Unrecognized type '{propertySymbol.ContainingType.Name}'"); diff --git a/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.cs b/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.cs index 8b9a6948ed..7490a79a65 100644 --- a/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.cs +++ b/src/Tools/CodeGeneration/CSharp/SyntaxWalker/CSharpSyntaxWalkerGenerator.cs @@ -90,6 +90,7 @@ public List CreateMemberDeclarations() AddIfNotNull(CreateVisitAbstractSyntaxMethodDeclaration(Microsoft_CodeAnalysis_CSharp_Syntax_VariableDesignationSyntax)); AddIfNotNull(CreateVisitAbstractSyntaxMethodDeclaration(Microsoft_CodeAnalysis_CSharp_Syntax_XmlAttributeSyntax)); AddIfNotNull(CreateVisitAbstractSyntaxMethodDeclaration(Microsoft_CodeAnalysis_CSharp_Syntax_XmlNodeSyntax)); + AddIfNotNull(CreateVisitAbstractSyntaxMethodDeclaration(Microsoft_CodeAnalysis_CSharp_Syntax_CollectionElementSyntax)); } return members; @@ -410,6 +411,7 @@ private static string GetMethodName(ITypeSymbol typeSymbol) case "XmlAttributeSyntax": case "XmlNodeSyntax": case "BaseExpressionColonSyntax": + case "CollectionElementSyntax": { if (typeSymbol .ContainingNamespace diff --git a/src/VisualStudioCode/package/src/configurationFiles.generated.ts b/src/VisualStudioCode/package/src/configurationFiles.generated.ts index c410d94f27..5879b70c11 100644 --- a/src/VisualStudioCode/package/src/configurationFiles.generated.ts +++ b/src/VisualStudioCode/package/src/configurationFiles.generated.ts @@ -139,6 +139,9 @@ roslynator_analyzers.enabled_by_default = true|false #roslynator_use_block_body_when_expression_spans_over_multiple_lines = true|false # Applicable to: rcs1016 +#roslynator_use_collection_expression = true|false +# Applicable to: rcs1014, rcs1250 + #roslynator_use_var_instead_of_implicit_object_creation = true|false # Applicable to: rcs1250 @@ -341,7 +344,7 @@ roslynator_analyzers.enabled_by_default = true|false # Use explicitly/implicitly typed array #dotnet_diagnostic.rcs1014.severity = none -# Options: roslynator_array_creation_type_style +# Options: roslynator_array_creation_type_style, roslynator_use_collection_expression # Use nameof operator #dotnet_diagnostic.rcs1015.severity = suggestion @@ -870,7 +873,7 @@ roslynator_analyzers.enabled_by_default = true|false # Use implicit/explicit object creation #dotnet_diagnostic.rcs1250.severity = none -# Options: roslynator_object_creation_type_style, roslynator_use_var_instead_of_implicit_object_creation +# Options: roslynator_object_creation_type_style, roslynator_use_collection_expression, roslynator_use_var_instead_of_implicit_object_creation # Remove unnecessary braces from record declaration #dotnet_diagnostic.rcs1251.severity = suggestion