-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
editor config naming style #15065
editor config naming style #15065
Conversation
test vsi please |
528fc96
to
0132d23
Compare
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.
Many comments but a few high level concerns:
First, let's use stronger types in a lot of places. I'd happily prefer some manually created types than Tuple<string, string, string, string>
that is very challenging to maintain.
Second, there's a few places where we're building caches solely based on GetHashCode which means correctness is dependent upon an implementation that is explicitly allowed to not be correct.
{ | ||
try | ||
{ | ||
value = editorConfigPersistence.ParseValue(value.ToString(), option.Option.Type); | ||
value = EditorConfigNamingStyleParser.GetNamingStylesStringFromDictionary(_codingConventionSnapshot.AllRawConventions); |
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 we just update EditorConfigPersistence to always be given the full set, and then the simple case just throws away everything else? That'll avoid the duplicate code here.
#Resolved
public partial class EditorConfigNamingStyleParserTests | ||
{ | ||
|
||
/// <summary> |
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 always think of <summary>
to mean "I want this to be shown in QuickInfo". I'm not sure that applies here. #Resolved
#Resolved
{ | ||
internal static partial class EditorConfigNamingStyleParser | ||
{ | ||
public static IEnumerable<Tuple<string, string, Tuple<string, string, string, string>, Tuple<string, string, string, string, string>>> ParseDictionary(IReadOnlyDictionary<string, object> allRawConventions) |
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.
Please make an actual type for this, or use our new tuples or something. This makes the code very difficult to understand.
public static IEnumerable<Tuple<string, string, Tuple<string, string, string, string>, Tuple<string, string, string, string, string>>> ParseDictionary(IReadOnlyDictionary<string, object> allRawConventions) | ||
{ | ||
var namingRules = (from kvp in allRawConventions | ||
where kvp.Key.Trim().StartsWith("dotnet_naming_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.
TrimStart, just to avoid extra garbage if the end has stuff?
select kvp).ToDictionary(x => x.Key, x => x.Value); | ||
|
||
var namingRulesSeverity = (from kvp in namingRules | ||
where kvp.Key.Trim().EndsWith(".severity") |
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 trimming the keys once rather than doing it during each query.
|
||
namespace Microsoft.CodeAnalysis.CSharp.CodeStyle | ||
{ | ||
internal static class CSharpCodeStyleOptions | ||
{ | ||
// TODO: get sign off on public api changes. | ||
public static readonly Option<bool> UseVarWhenDeclaringLocals = new Option<bool>(nameof(CodeStyleOptions), nameof(UseVarWhenDeclaringLocals), defaultValue: true, | ||
storageLocations: new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseVarWhenDeclaringLocals")); | ||
storageLocations: new OptionStorageLocation[]{ |
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.
You don't have to name the type, which might make it a bit less verbose. Does this being params help? #Resolved
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.
params array doesn't work with named arguments.
It can either look like this:
public static readonly Option<bool> UseVarWhenDeclaringLocals = new Option<bool>(nameof(CodeStyleOptions), nameof(UseVarWhenDeclaringLocals), defaultValue: true,
storageLocations: new OptionStorageLocation[]{
new EditorConfigStorageLocation("csharp_style_var_for_locals", ParseEditorConfigCodeStyleOption),
new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseVarWhenDeclaringLocals")});
Or this:
public static readonly Option<bool> UseVarWhenDeclaringLocals = new Option<bool>(nameof(CodeStyleOptions), nameof(UseVarWhenDeclaringLocals), true,
new EditorConfigStorageLocation("csharp_style_var_for_locals", ParseEditorConfigCodeStyleOption),
new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseVarWhenDeclaringLocals"));
#Resolved
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 what @jasonmalinowski meant was that you could omit OptionStorageLocation
in the first one and just have new [] { ... }
.
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.
C# does not allow you to use new [] { ... }
syntax if the array contains two separate types
|
||
switch (args[1].Trim()) | ||
{ | ||
case "none": return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None); |
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.
For code styles, did we ever discuss having it be more explicit to say severity=none? My worry is an option that is "false, none" isn't exactly obvious in context what that means for somebody first seeing it.
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.
severity=none could be ambiguous to some parsers. maybe :
?
csharp_style_inlined_variable_declaration = severity=none
csharp_style_inlined_variable_declaration = severity:none
|
||
internal static readonly PerLanguageOption<CodeStyleOption<bool>> PreferInlinedVariableDeclaration = new PerLanguageOption<CodeStyleOption<bool>>( | ||
nameof(CodeStyleOptions), | ||
nameof(PreferInlinedVariableDeclaration), | ||
defaultValue: TrueWithSuggestionEnforcement, | ||
storageLocations: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferInlinedVariableDeclaration")); | ||
storageLocations: new OptionStorageLocation[]{ | ||
new EditorConfigStorageLocation("csharp_style_inlined_variable_declaration", ParseEditorConfigCodeStyleOption), |
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.
Why 'csharp' in the core layer?
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.
PreferInlinedVariableDeclaration only applies to C#. I'll move it out.
|
||
namespace Microsoft.CodeAnalysis.Options | ||
{ | ||
internal sealed class NamingEditorConfigStorageLocation : OptionStorageLocation { } |
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.
You might want to comment why this type is there. I don't disagree with it's existence (and now want to refactor the language settings one for clarity too...) but a comment is good. #Resolved
#Resolved
var optionSet = await options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).ConfigureAwait(false); | ||
string language = context.Compilation.Language; | ||
var currentValue = optionSet.GetOption(SimplificationOptions.NamingPreferences, language); | ||
int hashCode = currentValue.GetHashCode(); |
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.
Isn't this assuming possibly incorrect things about hash codes? #Resolved
where kvp.Key.Trim().StartsWith("dotnet_naming_style.") | ||
select kvp).ToDictionary(x => x.Key, x => x.Value); | ||
|
||
var namingStyleRequiredPrefix = (from kvp in namingStyles |
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.
It would seem easier to just loop through all keys, do the split you're doing around line 63, and then just switch on the last component.
76bee8b
to
57526e2
Compare
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.
Perf terrifies me here:
- Enumerating the editorconfig dictionary a bunch of times.
- Allocating tons of yield enumerators.
- No caching, so we do all of this work for every symbol the analyzer runs on (hopefully every symbol in the solution soon, currently every symbol in an open file).
Assert.Equal("method_and_property_symbols", symbolSpec.Name); | ||
|
||
|
||
Assert.Equal(2 ,symbolSpec.ApplicableSymbolKindList.Count); |
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 we have AssertEx.SetEqual
which might make this easier.
#Resolved
var optionSet = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult(); | ||
if (optionSet == null) | ||
{ | ||
return; |
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.
Can we at least assert or something here? It seems bad that all of our analyzers would just silently do nothing if we broke getting options.
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.
why not WaitAndGetResult?
{ | ||
internal static partial class EditorConfigNamingStyleParser | ||
{ | ||
private static bool TryGeySerializableNamingRule( |
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.
Typo: TryGet
{ | ||
diagnosticSeverity = default(DiagnosticSeverity); | ||
var result = (from kvp in allRawConventions | ||
where kvp.Key.Trim() == $"dotnet_naming_rule.{namingRuleName}.severity" |
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.
Isn't the whole point of a dictionary that you can look up the keys faster than iterating over the whole thing? Why not Trim
while populating the dictionary, and just use TryGetValue
here?
{ | ||
namingStyleName = null; | ||
var result = (from kvp in allRawConventions | ||
where kvp.Key.Trim() == $"dotnet_naming_rule.{namingRuleName}.style" |
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.
Same comment about switching to TryGetValue
|
||
public bool Equals(AccessibilityKind other) | ||
{ | ||
return this.Accessibility == other.Accessibility; |
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.
You don't test for other == null
but it could be from your object.Equals
override.
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.
fixed with change to struct type
{ | ||
get | ||
{ | ||
internal DeclarationModifiers Modifier { |
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.
WHAT HAVE YOU DONE?!?!
int hashCode = currentValue.GetHashCode(); | ||
var viewModel = SerializableNamingStylePreferencesInfo.FromXElement(XElement.Parse(currentValue)); | ||
var preferences = viewModel.GetPreferencesInfo(); | ||
return preferences; |
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.
It terrifies me that we don't do any caching here and instead populate all the rules from editorconfig, serialize them to xml and then deserialize back from xml ON EVERY SYMBOL?
if (optionSet == null) | ||
{ | ||
return; | ||
} | ||
|
||
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.
Whitespace
#Resolved
|
||
namespace Microsoft.CodeAnalysis.CSharp.CodeStyle | ||
{ | ||
internal static class CSharpCodeStyleOptions | ||
{ | ||
// TODO: get sign off on public api changes. | ||
public static readonly Option<bool> UseVarWhenDeclaringLocals = new Option<bool>(nameof(CodeStyleOptions), nameof(UseVarWhenDeclaringLocals), defaultValue: true, | ||
storageLocations: new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseVarWhenDeclaringLocals")); | ||
storageLocations: new OptionStorageLocation[]{ |
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 what @jasonmalinowski meant was that you could omit OptionStorageLocation
in the first one and just have new [] { ... }
.
Oh - also, did we decide on a way to deal with asynchrony here? |
57526e2
to
26f1ba8
Compare
{ | ||
// TODO: report this somewhere? |
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.
Yes. We can report a NFW here.
#Resolved
var options = context.Options; | ||
var syntaxTree = context.Node.SyntaxTree; | ||
var cancellationToken = context.CancellationToken; | ||
var optionSet = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult(); |
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.
lots of duplication across all our analyzers. Can you have a single extnsion method that does this?
{ | ||
return (analyzerOptions as WorkspaceAnalyzerOptions)?.Workspace.Options; | ||
var workspace = (analyzerOptions as WorkspaceAnalyzerOptions)?.Workspace; | ||
if (workspace == null) |
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.
how does this happen?
return null; | ||
} | ||
|
||
var documentId = workspace.CurrentSolution.GetDocumentId(syntaxTree); |
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.
Oh god... we're accessing mutable stuff in a BG analyzer? :(
{ | ||
case "pascal_case": return Capitalization.PascalCase; | ||
case "camel_case": return Capitalization.CamelCase; | ||
case "first_word_upper": return Capitalization.FirstUpper; |
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 Capitalization.FirstWordUpper? or shoudl the string be "first_upper"?
object result; | ||
if (conventionsDictionary.TryGetValue($"dotnet_naming_style.{namingStyleName}.word_separator", out result)) | ||
{ | ||
return (string)result; |
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.
can this cast fail?
private static string GetNamingRequiredPrefix(string namingStyleName, IReadOnlyDictionary<string, object> conventionsDictionary) | ||
{ | ||
object result; | ||
if (conventionsDictionary.TryGetValue($"dotnet_naming_style.{namingStyleName}.required_prefix", out result)) |
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.
you can use out-var
var requiredModifiers = GetSymbolsRequiredModifiers(symbolSpecName, conventionsDictionary); | ||
|
||
symbolSpec = new SymbolSpecification( | ||
Guid.NewGuid(), |
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.
indentation weird.
switch (symbolSpecApplicableKind) | ||
{ | ||
case "class": | ||
return new[] { new SymbolKindOrTypeKind(TypeKind.Class) }; |
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.
- can we use immutable arrays.
- can we cache these somewhere so we don't keep allocating what are essentially constants.
16a271b
to
d1b7a09
Compare
82cac5d
to
e3d55c8
Compare
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.
Only minor requests. 👍
@@ -0,0 +1,245 @@ | |||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. |
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.
Nit: We typically use underscores in file names when just splitting up the functionality of a type into partials, and use dots when separating out nested types.
private static readonly SymbolKindOrTypeKind _method = new SymbolKindOrTypeKind(SymbolKind.Method); | ||
private static readonly SymbolKindOrTypeKind _field = new SymbolKindOrTypeKind(SymbolKind.Field); | ||
private static readonly SymbolKindOrTypeKind _event = new SymbolKindOrTypeKind(SymbolKind.Event); | ||
private static readonly SymbolKindOrTypeKind _namespace = new SymbolKindOrTypeKind(SymbolKind.Namespace); |
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.
We got rid of namespaces and type parameters, at least from the UI. Did I miss removing them somewhere else that tricked you into including them here, or were you operating off the old UI?
case "public": | ||
builder.Add(Accessibility.Public); | ||
break; | ||
case "internal": |
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.
Are we standardizing on "internal" for both C# and VB? The UI in VS makes the distinction, though I don't think the old serialization code made the distinction (but that didn't matter because it wasn't user-facing).
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.
As discussed offline, maybe we can just use either language's nomenclature interchangeably.
|
||
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles | ||
{ | ||
internal class SymbolSpecification | ||
internal partial class SymbolSpecification |
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.
Why is this partial? I'm not seeing another part.
return Modifier == other.Modifier; | ||
} | ||
|
||
public static bool operator ==(ModifierKind left, ModifierKind right) |
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.
Why do you need the operators here but not in SymbolKindOrTypeKind
?
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.
oversight. Added the operators
@@ -5,11 +5,11 @@ | |||
|
|||
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles | |||
{ | |||
internal class NamingStylePreferencesInfo | |||
internal class NamingStyleRules |
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.
Rename the file to match.
/// 2. Name Style | ||
/// 3. Naming Rule (points to Symbol Specification IDs) | ||
/// </summary> | ||
internal class NamingStylePreferences : IEquatable<NamingStylePreferences> |
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.
Rename file to match.
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 this will work. Many small questions, and I see a number of other comments that should be cleaned up. But those are only local fixes.
|
||
var optionSet = await context.Options.GetDocumentOptionSetAsync(location.SourceTree, context.CancellationToken).ConfigureAwait(false); | ||
var namimgStylePreferences = optionSet.GetOption(SimplificationOptions.NamingPreferences, context.Compilation.Language); | ||
return namimgStylePreferences.GetNamingStyleRules(); |
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 don't think this is related to your change at this point, but it's really confusing what the difference is between "preferences" and "rules"...
@@ -134,6 +133,19 @@ public bool TryFetch(OptionKey optionKey, out object value) | |||
return false; | |||
} | |||
} | |||
else if (optionKey.Option.Type ==typeof(NamingStylePreferences)) |
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.
Missing space.
// We store these as strings, so deserialize | ||
if (value is string serializedValue) | ||
{ | ||
value = NamingStylePreferences.FromXElement(XElement.Parse(serializedValue)); |
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 be resilient to if that parse fails. It's the responsibility of the persister to deal with it.
@@ -202,7 +214,18 @@ public bool TryPersist(OptionKey optionKey, object value) | |||
} | |||
} | |||
|
|||
this._settingManager.SetValueAsync(storageKey, value, isMachineLocal: false); | |||
if (optionKey.Option.Type == typeof(NamingStylePreferences)) |
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.
Put as an else if with the previous test?
var options = OptionService.GetOption(SimplificationOptions.NamingPreferences, _languageName); | ||
if (string.IsNullOrEmpty(options)) | ||
var preferencesInfo = this.OptionService.GetOption(SimplificationOptions.NamingPreferences, _languageName); | ||
if (preferencesInfo == null) |
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.
"preferences" now that we dropped "info" in the type name?
@@ -325,7 +361,7 @@ internal override IEnumerable<OptionKey> GetChangedOptions(OptionSet optionSet) | |||
foreach (var kvp in _values) | |||
{ | |||
var currentValue = optionSet.GetOption(kvp.Key); | |||
if (!object.Equals(currentValue, kvp.Value)) | |||
if (currentValue?.Equals(kvp.Value) == 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.
or just use the static object.Equals() which does this right...
{ | ||
// TODO: report this somewhere? | ||
return false; | ||
return editorConfigPersistence.TryParseReadonlyDictionary(allRawConventions, option.Option.Type, out 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.
Isn't the point of such a refactoring like this that instead of this having naming-styles special case knowledge, that you'd delete NamingEditorConfigStorageLocation and make it be just a new EditorConfigStorageLocation(EditorConfigNamingStyleParser.GetNamingStylesFromDictionary)?
{ | ||
value = editorConfigPersistence.ParseValue(value.ToString(), option.Option.Type); |
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 you've removed the only call to the public ParseValue, and you could delete it.
955be72
to
e021d50
Compare
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.
Still a little bit concerned about the defaults assumed when things can't be found/parsed, and about what string comparisons we use.
@@ -5,10 +5,11 @@ | |||
using System.Xml.Linq; | |||
using Microsoft.CodeAnalysis.CodeStyle; | |||
using Microsoft.CodeAnalysis.Simplification; | |||
using System.Collections.Generic; |
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.
System first.
@@ -290,6 +290,42 @@ private OptionSet ReadOptionFrom<T>(OptionSet options, string language, PerLangu | |||
return options.WithChangedOption(option, language, value); | |||
} | |||
|
|||
protected void WriteOptionTo(OptionSet options, Option<NamingStylePreferences> option, ObjectWriter writer, CancellationToken cancellationToken) |
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.
Do we need the language-neutral ones 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.
Not today. But I've added them for consistency.
WriteOptionTo(options, language, CodeStyleOptions.PreferCoalesceExpression, writer, cancellationToken); | ||
WriteOptionTo(options, language, CodeStyleOptions.PreferCollectionInitializer, writer, cancellationToken); | ||
WriteOptionTo(options, language, CodeStyleOptions.PreferExplicitTupleNames, writer, cancellationToken); | ||
WriteOptionTo(options, language, CodeStyleOptions.PreferInlinedVariableDeclaration, writer, cancellationToken); | ||
WriteOptionTo(options, language, CodeStyleOptions.PreferNullPropagation, writer, cancellationToken); | ||
WriteOptionTo(options, language, CodeStyleOptions.PreferObjectInitializer, writer, cancellationToken); | ||
WriteOptionTo(options, language, CodeStyleOptions.PreferThrowExpression, writer, cancellationToken); | ||
WriteOptionTo(options, language, SimplificationOptions.NamingPreferences, writer, cancellationToken); |
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.
Missing before, but it didn't matter because we don't run the naming analyzer OOP?
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.
Yep
|
||
internal static Accessibility FromXElement(XElement accessibilityElement) | ||
{ | ||
return (Accessibility)Enum.Parse(typeof(Accessibility), accessibilityElement.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.
Do all callers handle exceptions in case the this doesn't parse (the file has been modified, etc)?
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.
We don't do this for code styles, are you saying we should handle this for all cases where we read XML from the option persistence service? Sounds like a good idea
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've added try/catch for all the callsites that parse XElements
|
||
public override bool Equals(object obj) | ||
{ | ||
return Equals((ModifierKind)obj); |
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 probably do an is
check here.
private static Capitalization GetNamingCapitalization(string namingStyleName, IReadOnlyDictionary<string, object> conventionsDictionary) | ||
{ | ||
var result = GetStringFromConventionsDictionary(namingStyleName, "capitalization", conventionsDictionary); | ||
return ParseCapitalizationScheme(result); |
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 will return PascalCase if it can't be found, or isn't a legal value. Is that what we want?
return ImmutableArray<SymbolKindOrTypeKind>.Empty; | ||
} | ||
|
||
var builder = ArrayBuilder<SymbolKindOrTypeKind>.GetInstance(); |
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.
Create the builder after the _all
return.
var builder = ArrayBuilder<Accessibility>.GetInstance(); | ||
if (symbolSpecApplicableAccessibilities.Trim() == "*") | ||
{ | ||
builder.AddRange(Accessibility.Public, Accessibility.Internal, Accessibility.Private, Accessibility.Protected, Accessibility.ProtectedOrInternal); |
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.
Cache the _all case as above?
return ImmutableArray<ModifierKind>.Empty; | ||
} | ||
|
||
private static readonly ModifierKind _abstractModifierKind = new ModifierKind(ModifierKindEnum.IsAbstract); |
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.
Actually - these are structs right? Do we gain anything from caching them?
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.
Perf was not measured.
var builder = ArrayBuilder<ModifierKind>.GetInstance(); | ||
if (symbolSpecRequiredModifiers.Trim() == "*") | ||
{ | ||
builder.AddRange(_abstractModifierKind, _asyncModifierKind, _constModifierKind, _readonlyModifierKind, _staticModifierKind); |
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 caching the * case.
e021d50
to
275258f
Compare
Teaching abstract options serialization service about naming styles.
275258f
to
92e3d18
Compare
Looks like there's been a bunch of commits to address feedback. Can someone else review the recent changes in @Pilchie's absence? |
I will be sure to re-review tomorrow morning. Sorry for the delay.
|
@Pilchie thanks! |
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 looks good to me, except the dictionary comparer issue, but we need to follow-up with the editor team about that.
Let's merge this and make any adjustment there after the fact if necessary.
@dotnet/roslyn-ide @jasonmalinowski
Adds the following options
Naming Style Options
<naming rule title>
.severity<naming rule title>
.symbols<naming symbols title>
<naming rule title>
.style<naming stlye title>
<naming symbols title>
.applicable_kinds<naming symbols title>
.applicable_accessibilities<naming symbols title>
.required_modifiers<naming style title>
.required_prefix<naming style title>
.required_suffix<naming style title>
.word_separator<naming style title>
.capitalizationNaming Style Examples