diff --git a/.editorconfig b/.editorconfig index f9ecc06957..8e329bae64 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,6 +6,12 @@ root = true [*] indent_style = space +[*.xml] +indent_size = 2 + +[Analyzers.xml] +trim_trailing_whitespace = false + # Code files [*.{cs,csx}] indent_size = 4 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3c90a08ef..ae7e800a61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,7 +71,7 @@ jobs: ../wordb/data/tech.acronyms.txt build_core_and_testing: - if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') + if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') needs: pre_build runs-on: ubuntu-24.04 env: @@ -90,7 +90,7 @@ jobs: path: src/_nupkg/*nupkg build_analyzers: - if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') + if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') needs: pre_build runs-on: ubuntu-24.04 env: @@ -123,7 +123,7 @@ jobs: path: src/${{ matrix.component.name }}.CodeFixes/bin/Release/*.*nupkg build_refactorings: - if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') + if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') needs: pre_build runs-on: ubuntu-24.04 env: @@ -144,7 +144,7 @@ jobs: path: src/Refactorings/bin/Release/*.*nupkg build_code_fixes: - if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') + if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') needs: pre_build runs-on: ubuntu-24.04 env: @@ -165,7 +165,7 @@ jobs: path: src/CodeFixes/bin/Release/*.*nupkg build_vs_extension: - if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') + if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') needs: pre_build runs-on: windows-latest env: @@ -199,7 +199,7 @@ jobs: delete-merged: true build_vs_code_extension: - if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') + if: github.ref_type != 'tag' || startsWith(github.ref_name, 'v') needs: [ pre_build, build_analyzers ] runs-on: ubuntu-24.04 env: @@ -209,6 +209,9 @@ jobs: working-directory: src/VisualStudioCode steps: - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.301 - run: dotnet restore - run: dotnet build --no-restore - run: | @@ -263,7 +266,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.101 + dotnet-version: 9.0.301 - run: dotnet restore - run: dotnet build --no-restore - run: dotnet pack --no-build diff --git a/.gitignore b/.gitignore index aa3419f5f5..a5ec2da68c 100644 --- a/.gitignore +++ b/.gitignore @@ -140,7 +140,7 @@ publish/ *.[Pp]ublish.xml *.azurePubxml -# TODO: Un-comment the next line if you do not want to checkin +# TODO: Un-comment the next line if you do not want to checkin # your web deploy settings because they may include unencrypted # passwords #*.pubxml @@ -244,4 +244,7 @@ ModelManifest.xml # FAKE - F# Make .fake/ -.DS_Store \ No newline at end of file +.DS_Store + +# JetBrains Rider setting files +.idea/ diff --git a/src/Analyzers.xml b/src/Analyzers.xml index 072001d577..f2ff360b3e 100644 --- a/src/Analyzers.xml +++ b/src/Analyzers.xml @@ -7819,6 +7819,46 @@ string s = """ + + RCS1269 + FixBracketFormattingOfList + Fix bracket formatting of a list + Fix bracket formatting of {0} + Info + false + + + + This analyzer: + * adds new line after an opening bracket of argument/parameter lists and similar lists + * adds new line before a closing bracket of argument/parameter lists and similar lists + * aligns the closing bracket with the block containing its opening bracket + The analyzer works only for multi-line declarations. + + + + + + + + + + + + RCS9001 UsePatternMatching diff --git a/src/CSharp/DetermineParameterTypeHelper.cs b/src/CSharp/DetermineParameterTypeHelper.cs index 85ed539cf6..dabed05fee 100644 --- a/src/CSharp/DetermineParameterTypeHelper.cs +++ b/src/CSharp/DetermineParameterTypeHelper.cs @@ -45,7 +45,7 @@ public static ImmutableArray DetermineParameterTypes( if (typeSymbol?.IsErrorType() == false) { - (typeSymbols ??= new HashSet()).Add(typeSymbol); + (typeSymbols ??= new HashSet(SymbolEqualityComparer.Default)).Add(typeSymbol); } } diff --git a/src/Common/CSharp/CodeStyle/TargetBracesStyle.cs b/src/Common/CSharp/CodeStyle/TargetBracesStyle.cs new file mode 100644 index 0000000000..5c6ee146b9 --- /dev/null +++ b/src/Common/CSharp/CodeStyle/TargetBracesStyle.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Roslynator.CSharp.CodeStyle; + +[Flags] +public enum TargetBracesStyle +{ + None, + Opening, + Closing, + Both = Opening | Closing, +} diff --git a/src/Common/CSharp/Extensions/CodeStyleExtensions.cs b/src/Common/CSharp/Extensions/CodeStyleExtensions.cs index 48fafdc967..eb853672f2 100644 --- a/src/Common/CSharp/Extensions/CodeStyleExtensions.cs +++ b/src/Common/CSharp/Extensions/CodeStyleExtensions.cs @@ -656,6 +656,30 @@ public static NewLinePosition GetNullConditionalOperatorNewLinePosition(this Syn return context.GetConfigOptions().GetNullConditionalOperatorNewLinePosition(defaultValue); } + public static TargetBracesStyle GetTargetBracesStyle(this SyntaxNodeAnalysisContext context) + => context.GetConfigOptions().GetTargetBracesStyle(); + + public static TargetBracesStyle GetTargetBracesStyle(this AnalyzerConfigOptions configOptions) + { + if (ConfigOptions.TryGetValue(configOptions, ConfigOptions.TargetBracesStyle, out string rawValue)) + { + if (string.Equals(rawValue, ConfigOptionValues.TargetBracesStyle_Both, StringComparison.OrdinalIgnoreCase)) + { + return TargetBracesStyle.Both; + } + else if (string.Equals(rawValue, ConfigOptionValues.TargetBracesStyle_Closing, StringComparison.OrdinalIgnoreCase)) + { + return TargetBracesStyle.Closing; + } + else if (string.Equals(rawValue, ConfigOptionValues.TargetBracesStyle_Opening, StringComparison.OrdinalIgnoreCase)) + { + return TargetBracesStyle.Opening; + } + } + + return TargetBracesStyle.None; + } + private static bool TryGetNewLinePosition( AnalyzerConfigOptions configOptions, ConfigOptionDescriptor option, diff --git a/src/Common/CSharp/SyntaxTriviaAnalysis.cs b/src/Common/CSharp/SyntaxTriviaAnalysis.cs index e995ce2e8b..5bc1fedd42 100644 --- a/src/Common/CSharp/SyntaxTriviaAnalysis.cs +++ b/src/Common/CSharp/SyntaxTriviaAnalysis.cs @@ -111,6 +111,9 @@ public static IndentationAnalysis AnalyzeIndentation(SyntaxNode node, AnalyzerCo } public static SyntaxTrivia DetermineIndentation(SyntaxNodeOrToken nodeOrToken, CancellationToken cancellationToken = default) + => DetermineIndentation(nodeOrToken, true, cancellationToken); + + public static SyntaxTrivia DetermineIndentation(SyntaxNodeOrToken nodeOrToken, bool searchInAccessors, CancellationToken cancellationToken = default) { SyntaxTree tree = nodeOrToken.SyntaxTree; @@ -171,7 +174,7 @@ public static SyntaxTrivia DetermineIndentation(SyntaxNodeOrToken nodeOrToken, C } } - if (!IsMemberDeclarationOrStatementOrAccessorDeclaration(node)) + if (searchInAccessors && !IsMemberDeclarationOrStatementOrAccessorDeclaration(node)) { node = node.Parent; diff --git a/src/Common/ConfigOptionKeys.Generated.cs b/src/Common/ConfigOptionKeys.Generated.cs index d03c51daff..b5b25046a3 100644 --- a/src/Common/ConfigOptionKeys.Generated.cs +++ b/src/Common/ConfigOptionKeys.Generated.cs @@ -37,6 +37,7 @@ internal static partial class ConfigOptionKeys public const string PrefixFieldIdentifierWithUnderscore = "roslynator_prefix_field_identifier_with_underscore"; public const string SuppressUnityScriptMethods = "roslynator_suppress_unity_script_methods"; public const string TabLength = "roslynator_tab_length"; + public const string TargetBracesStyle = "roslynator_target_braces_style"; public const string TrailingCommaStyle = "roslynator_trailing_comma_style"; public const string UnityCodeAnalysisEnabled = "roslynator_unity_code_analysis.enabled"; public const string UseAnonymousFunctionOrMethodGroup = "roslynator_use_anonymous_function_or_method_group"; diff --git a/src/Common/ConfigOptionValues.Generated.cs b/src/Common/ConfigOptionValues.Generated.cs index 06ae33fb45..ee449d1350 100644 --- a/src/Common/ConfigOptionValues.Generated.cs +++ b/src/Common/ConfigOptionValues.Generated.cs @@ -52,6 +52,10 @@ internal static partial class ConfigOptionValues public const string ObjectCreationTypeStyle_Explicit = "explicit"; public const string ObjectCreationTypeStyle_Implicit = "implicit"; public const string ObjectCreationTypeStyle_ImplicitWhenTypeIsObvious = "implicit_when_type_is_obvious"; + public const string TargetBracesStyle_None = "none"; + public const string TargetBracesStyle_Opening = "opening"; + public const string TargetBracesStyle_Closing = "closing"; + public const string TargetBracesStyle_Both = "both"; public const string TrailingCommaStyle_Include = "include"; public const string TrailingCommaStyle_Omit = "omit"; public const string TrailingCommaStyle_OmitWhenSingleLine = "omit_when_single_line"; diff --git a/src/Common/ConfigOptions.Generated.cs b/src/Common/ConfigOptions.Generated.cs index 556a34bd13..95e6066949 100644 --- a/src/Common/ConfigOptions.Generated.cs +++ b/src/Common/ConfigOptions.Generated.cs @@ -196,6 +196,12 @@ public static partial class ConfigOptions defaultValuePlaceholder: "", description: "A number of spaces that are equivalent to a tab character"); + public static readonly ConfigOptionDescriptor TargetBracesStyle = new( + key: ConfigOptionKeys.TargetBracesStyle, + defaultValue: "none", + defaultValuePlaceholder: "both|closing|none|opening", + description: "Define which braces should be used as a target of the code fix"); + public static readonly ConfigOptionDescriptor TrailingCommaStyle = new( key: ConfigOptionKeys.TrailingCommaStyle, defaultValue: null, diff --git a/src/Common/DiagnosticIdentifiers.Generated.cs b/src/Common/DiagnosticIdentifiers.Generated.cs index 7d6e59085e..3f811ce922 100644 --- a/src/Common/DiagnosticIdentifiers.Generated.cs +++ b/src/Common/DiagnosticIdentifiers.Generated.cs @@ -280,5 +280,6 @@ public static partial class DiagnosticIdentifiers public const string UseRawStringLiteral = "RCS1266"; public const string UseStringInterpolationInsteadOfStringConcat = "RCS1267"; public const string SimplifyNumericComparison = "RCS1268"; + public const string FixBracketFormattingOfList = "RCS1269"; } } \ No newline at end of file diff --git a/src/Common/DiagnosticRules.Generated.cs b/src/Common/DiagnosticRules.Generated.cs index 0b631ac6fb..e9f72ec0e6 100644 --- a/src/Common/DiagnosticRules.Generated.cs +++ b/src/Common/DiagnosticRules.Generated.cs @@ -3323,5 +3323,17 @@ public static partial class DiagnosticRules helpLinkUri: DiagnosticIdentifiers.SimplifyNumericComparison, customTags: []); + /// RCS1269 + public static readonly DiagnosticDescriptor FixBracketFormattingOfList = DiagnosticDescriptorFactory.Create( + id: DiagnosticIdentifiers.FixBracketFormattingOfList, + title: "Fix bracket formatting of a list", + messageFormat: "Fix bracket formatting of {0}", + category: DiagnosticCategories.Roslynator, + defaultSeverity: DiagnosticSeverity.Info, + isEnabledByDefault: false, + description: null, + helpLinkUri: DiagnosticIdentifiers.FixBracketFormattingOfList, + customTags: []); + } } \ No newline at end of file diff --git a/src/ConfigOptions.xml b/src/ConfigOptions.xml index 7e43508098..cb70170eee 100644 --- a/src/ConfigOptions.xml +++ b/src/ConfigOptions.xml @@ -237,6 +237,15 @@ when_type_is_obvious +