-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add prefer trailing commas code-style option #54859
base: main
Are you sure you want to change the base?
Conversation
@@ -295,6 +295,12 @@ private static Option2<CodeStyleOption2<AddImportPlacement>> CreateUsingDirectiv | |||
EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), | |||
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(AllowBlankLineAfterColonInConstructorInitializer)}")}); | |||
|
|||
public static readonly Option2<CodeStyleOption2<bool>> PreferTrailingCommas = CreateOption( | |||
CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferTrailingCommas), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what is the suitable CSharpCodeStyleOptionGroups
to use here.
@@ -295,6 +295,12 @@ private static Option2<CodeStyleOption2<AddImportPlacement>> CreateUsingDirectiv | |||
EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental", CodeStyleOptions2.TrueWithSilentEnforcement), | |||
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(AllowBlankLineAfterColonInConstructorInitializer)}")}); | |||
|
|||
public static readonly Option2<CodeStyleOption2<bool>> PreferTrailingCommas = CreateOption( | |||
CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferTrailingCommas), | |||
defaultValue: s_trueWithSuggestionEnforcement, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be true or false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should definitely be false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and it should be silent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect true/silent. This is a maintainability improvement, not a readability improvement (it improves the quality of git blame
over time).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm somewhat amenable to that.. i do think 'silent' has to be case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true/silent makes the most sense.
Although, I do think it improves readability (for me personally), in that it helps clarify it is an existentially qualified collection. My mind reads opening line {
with a series of lines ending in ,
followed by a matching }
as one giant math expression "construct collection with these members..."
I have dropped this for long. I'll get to it back as soon as I can. |
src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs
Outdated
Show resolved
Hide resolved
@CyrusNajmabadi Can you take a look please? Thanks! |
@@ -1785,7 +1785,7 @@ void Main() | |||
enum Color : ulong | |||
{ | |||
Green = 1UL << 0, | |||
Blue = 1UL << 1 | |||
Blue = 1UL << 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this appears to eb a regression in all these tests. i would expect nothing to change unless the test explicitly turned this option on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is impacted by the ongoing discussion in https://github.com/dotnet/roslyn/pull/54859/files#r671040273
@@ -151,6 +151,7 @@ private IEnumerable<CodeStyleSetting> GetExpressionCodeStyleOptions(AnalyzerConf | |||
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferRangeOperator, description: ServicesVSResources.Prefer_range_operator, editorConfigOptions, visualStudioOptions, updaterService, FileName); | |||
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, description: CSharpVSResources.Prefer_implicit_object_creation_when_type_is_apparent, editorConfigOptions, visualStudioOptions, updaterService, FileName); | |||
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferTupleSwap, description: ServicesVSResources.Prefer_tuple_swap, editorConfigOptions, visualStudioOptions, updaterService, FileName); | |||
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferTrailingCommas, description: ServicesVSResources.Prefer_trailing_commas, editorConfigOptions, visualStudioOptions, updaterService, FileName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hrmm... i don't think this is an expression-style... This is all for declarations (or maybe variables). consider putting in the variable section? or making a new section?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CyrusNajmabadi Actually even those in GetVariableCodeStyleOptions
have CSharpCodeStyleOptionGroups.ExpressionLevelPreferences
. I'm not sure what's the suitable group here.
public static readonly Option2<CodeStyleOption2<bool>> PreferTrailingCommas = CreateOption( | ||
CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(PreferTrailingCommas), | ||
defaultValue: s_trueWithSuggestionEnforcement, | ||
"csharp_style_prefer_trailing_commas", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think it shoudl likely be csharp_style_prefer_trailing_comma
. @sharwell thoughts? plural on singular here? We don't say prefer_switch_expressions
for example, just prefer_switch_expression
. And you can't have x,,,
and this doesn't impact anything but the last member (since the other members must have a comma already). so it's really about a singular trailing comma in these lists.
--
i'm also somewhat on the fence here if we should say csharp_style_prefer_trailing_enum_comma
. The reason here is that we have proposals (i think i'm championing one) for things like a trailing comma in a parameter list. i'm wary about having a single option now that some users might not want to apply to different constructs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CyrusNajmabadi Per @sharwell's comment on the original issue:
it makes sense to add an editorconfig option to include this comma, which the various code generation features would then account for.
The "various code generation features" part implies that a single option is needed for everything. But I'm open to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reading through the critical decision was:
@CyrusNajmabadi it seems like only one option would be needed here. I don't think StyleCop Analyzers ever had a request to split the single option in two, and even if it did it would be an extreme minority scenario.
I'm hesitantly ok with this. However, if we have this, we need to update more than just the enum generator here. We also need to check that object/collection-initializers and arrays are generated with this and checked for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, switch/with expressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CyrusNajmabadi Can you point me to where object/collection initializers and switch/with expressions generators are?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some changes def need to happen. tagging @sharwell for some thoughts (esp. about the future).
i think this woudl be required as part of this. note: you can put this in a feature branch if you want. but to be merged into main, we would need teh analzyer/fixer. |
i'm hesitant about true/false being enough here. Say i'm a user that likes new Point
{
X = 1,
Y = 2,
} it doesn't feel like i have an approach that allow me to specify this. Note: this isn't speculative. I am this user :D |
@sharwell i'd like your thoughts on #54859 (comment). I actually feel pretty darn strongly about this :) |
This style applies if and only if the |
That is definitely fine with me. maybe |
|
||
if (options.Preferences.Options.GetOption(CSharpCodeStyleOptions.PreferTrailingCommas).Value) | ||
{ | ||
members.Add(SyntaxFactory.Token(SyntaxKind.CommaToken)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i actually have mixed feelings about this approach. i actually think the generator should only do this if generating the first item. if generating a followup item it should take a 'when in rome' aproach where it follows what the existing code does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CyrusNajmabadi Per my understanding of a previous conversation with @sharwell, code generation should adhere to code-style options when possible. If the user doesn't like the style, he should change the option value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some StyleCop Analyzers options have a tri-state true/false/preserve, where preserve means the current state should be followed when adding new items to the same location. The problem with a preserve value is it doesn't allow the user to also express a preference for the behavior when creating a brand new collection.
I lean towards following the defined code style in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sharwell The false
value for analyzers in almost all code-style options means "preserve" (never report diagnostic). It doesn't enforce the opposite style. It's more of enable/disable rather than a real true/false.
@sharwell @CyrusNajmabadi Can you take a look? I haven't yet handled all possible syntax kinds, but the general idea will be the same. |
src/Analyzers/CSharp/Tests/PreferTrailingComma/PreferTrailingCommaTests.cs
Outdated
Show resolved
Hide resolved
src/Analyzers/CSharp/Tests/PreferTrailingComma/PreferTrailingCommaTests.cs
Outdated
Show resolved
Hide resolved
src/Analyzers/CSharp/Tests/PreferTrailingComma/PreferTrailingCommaTests.cs
Show resolved
Hide resolved
{ | ||
using VerifyCS = CSharpCodeFixVerifier<PreferTrailingCommaDiagnosticAnalyzer, PreferTrailingCommaCodeFixProvider>; | ||
|
||
public class PreferTrailingCommaTests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Consider reviewing the following for additional test cases:
- https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers.Test/MaintainabilityRules/SA1413UnitTests.cs
- https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/MaintainabilityRules/SA1413CSharp7UnitTests.cs
- https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/MaintainabilityRules/SA1413CSharp8UnitTests.cs
- https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/MaintainabilityRules/SA1413CSharp9UnitTests.cs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sharwell I think I'm covering all of these scenarios (and more).
I'm moving one case that is not covered in StyleCopAnalyzers in DotNetAnalyzers/StyleCopAnalyzers#3533 :)
public PreferTrailingCommaDiagnosticAnalyzer() : base( | ||
diagnosticId: IDEDiagnosticIds.PreferTrailingCommaDiagnosticId, | ||
enforceOnBuild: EnforceOnBuildValues.PreferTrailingComma, | ||
option: CSharpCodeStyleOptions.PreferTrailingComma, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😢 Every time we add an option it makes me sad.
I've found in the case of this maintainability rule, it also adds to confusion. Some users think this is a readability rule that should be configurable. However, it is not a readability rule, and mistaking the goal here will lead some users to incorrectly configure the rule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sharwell Are you referring to the fact that csharp_style_prefer_trailing_comma = false
will disable the analyzer rather than enforcing a non-trailing comma? Or in other words, you like this code-style option to be used by code generation but not by the analyzer?
If that's the case, I definitely agree, but #60584 needs a decision.
src/Analyzers/CSharp/Analyzers/PreferTrailingComma/PreferTrailingCommaDiagnosticAnalyzer.cs
Outdated
Show resolved
Hide resolved
There are two failings tests (FixAll crashes when there are nested diagnostics). I'm not sure how to best approach this. |
It looks like "Use collection initializer" uses SyntaxFactory to produce the initializer node, where the start opening curly brace Because the post processing behavior isn't consistent (sometimes a new line is put after
It's currently unclear to me under what conditions the (formatter?) doesn't add a new line. |
I can just leave collection/object initializer codefixes as they was. Is that okay? @CyrusNajmabadi @sharwell |
Fixes #25206
Fixes #21784
CSharpUseObjectInitializerCodeFixProvider
should respect this optionCSharpUseCollectionInitializerCodeFixProvider
should respect this option.CSharpPopulateSwitchExpressionCodeFixProvider
ConvertSwitchStatementToExpression