Skip to content

Commit

Permalink
Merge pull request #17097 from jmarolf/bugfix/do-not-throw-exceptions…
Browse files Browse the repository at this point in the history
…-on-bad-editorconfig-files

ensure that TryParse is used for all user input in editorconfig
  • Loading branch information
jmarolf authored Feb 24, 2017
2 parents 60efbb6 + e1c4a0b commit d935107
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 63 deletions.
26 changes: 13 additions & 13 deletions src/Workspaces/CSharp/Portable/CodeStyle/CSharpCodeStyleOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,79 +12,79 @@ internal static class CSharpCodeStyleOptions
public static readonly Option<CodeStyleOption<bool>> UseImplicitTypeForIntrinsicTypes = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(UseImplicitTypeForIntrinsicTypes), defaultValue: CodeStyleOption<bool>.Default,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_var_for_built_in_types", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_var_for_built_in_types"),
new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseImplicitTypeForIntrinsicTypes")});

public static readonly Option<CodeStyleOption<bool>> UseImplicitTypeWhereApparent = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(UseImplicitTypeWhereApparent), defaultValue: CodeStyleOption<bool>.Default,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_var_when_type_is_apparent", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_var_when_type_is_apparent"),
new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseImplicitTypeWhereApparent")});

public static readonly Option<CodeStyleOption<bool>> UseImplicitTypeWherePossible = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(UseImplicitTypeWherePossible), defaultValue: CodeStyleOption<bool>.Default,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_var_elsewhere", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_var_elsewhere"),
new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseImplicitTypeWherePossible")});

public static readonly Option<CodeStyleOption<bool>> PreferConditionalDelegateCall = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferConditionalDelegateCall), defaultValue: CodeStyleOptions.TrueWithSuggestionEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_conditional_delegate_call", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_conditional_delegate_call"),
new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.PreferConditionalDelegateCall")});

public static readonly Option<CodeStyleOption<bool>> PreferPatternMatchingOverAsWithNullCheck = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferPatternMatchingOverAsWithNullCheck), defaultValue: CodeStyleOptions.TrueWithSuggestionEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_pattern_matching_over_as_with_null_check", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_pattern_matching_over_as_with_null_check"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferPatternMatchingOverAsWithNullCheck)}")});

public static readonly Option<CodeStyleOption<bool>> PreferPatternMatchingOverIsWithCastCheck = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferPatternMatchingOverIsWithCastCheck), defaultValue: CodeStyleOptions.TrueWithSuggestionEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_pattern_matching_over_is_with_cast_check", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_pattern_matching_over_is_with_cast_check"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferPatternMatchingOverIsWithCastCheck)}")});

public static readonly Option<CodeStyleOption<bool>> PreferExpressionBodiedConstructors = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferExpressionBodiedConstructors), defaultValue: CodeStyleOptions.FalseWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_expression_bodied_constructors", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_expression_bodied_constructors"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferExpressionBodiedConstructors)}")});

public static readonly Option<CodeStyleOption<bool>> PreferExpressionBodiedMethods = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferExpressionBodiedMethods), defaultValue: CodeStyleOptions.FalseWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_expression_bodied_methods", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_expression_bodied_methods"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferExpressionBodiedMethods)}")});

public static readonly Option<CodeStyleOption<bool>> PreferExpressionBodiedOperators = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferExpressionBodiedOperators), defaultValue: CodeStyleOptions.FalseWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_expression_bodied_operators", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_expression_bodied_operators"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferExpressionBodiedOperators)}")});

public static readonly Option<CodeStyleOption<bool>> PreferExpressionBodiedProperties = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferExpressionBodiedProperties), defaultValue: CodeStyleOptions.TrueWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_expression_bodied_properties", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_expression_bodied_properties"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferExpressionBodiedProperties)}")});

public static readonly Option<CodeStyleOption<bool>> PreferExpressionBodiedIndexers = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferExpressionBodiedIndexers), defaultValue: CodeStyleOptions.TrueWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_expression_bodied_indexers", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_expression_bodied_indexers"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferExpressionBodiedIndexers)}")});

public static readonly Option<CodeStyleOption<bool>> PreferExpressionBodiedAccessors = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferExpressionBodiedAccessors), defaultValue: CodeStyleOptions.TrueWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_style_expression_bodied_accessors", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_style_expression_bodied_accessors"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferExpressionBodiedAccessors)}")});

public static readonly Option<CodeStyleOption<bool>> PreferBraces = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferBraces), defaultValue: CodeStyleOptions.TrueWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
new EditorConfigStorageLocation("csharp_prefer_braces", ParseEditorConfigCodeStyleOption),
new EditorConfigStorageLocation("csharp_prefer_braces"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferBraces)}")});

public static IEnumerable<Option<CodeStyleOption<bool>>> GetCodeStyleOptions()
Expand Down
30 changes: 20 additions & 10 deletions src/Workspaces/Core/Portable/CodeStyle/CodeStyleHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,47 @@ namespace Microsoft.CodeAnalysis.CodeStyle
internal static class CodeStyleHelpers
{
public static CodeStyleOption<bool> ParseEditorConfigCodeStyleOption(string arg)
{
TryParseEditorConfigCodeStyleOption(arg, out var option);
return option;
}

public static bool TryParseEditorConfigCodeStyleOption(string arg, out CodeStyleOption<bool> option)
{
var args = arg.Split(':');
bool isEnabled = false;
var isEnabled = false;
if (args.Length != 2)
{
if (args.Length == 1)
{
if (bool.TryParse(args[0].Trim(), out isEnabled) && !isEnabled)
{
return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None);
option = new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None);
return true;
}
else
{
return CodeStyleOption<bool>.Default;
option = CodeStyleOption<bool>.Default;
return false;
}
}
return CodeStyleOption<bool>.Default;
option = CodeStyleOption<bool>.Default;
return false;
}

if (!bool.TryParse(args[0].Trim(), out isEnabled))
{
return CodeStyleOption<bool>.Default;
option = CodeStyleOption<bool>.Default;
return false;
}

switch (args[1].Trim())
{
case EditorConfigSeverityStrings.Silent: return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None);
case EditorConfigSeverityStrings.Suggestion: return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.Suggestion);
case EditorConfigSeverityStrings.Warning: return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.Warning);
case EditorConfigSeverityStrings.Error: return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.Error);
default: return new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None);
case EditorConfigSeverityStrings.Silent: option = new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None); return true;
case EditorConfigSeverityStrings.Suggestion: option = new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.Suggestion); return true;
case EditorConfigSeverityStrings.Warning: option = new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.Warning); return true;
case EditorConfigSeverityStrings.Error: option = new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.Error); return true;
default: option = new CodeStyleOption<bool>(value: isEnabled, notification: NotificationOption.None); return false;
}
}
}
Expand Down
86 changes: 46 additions & 40 deletions src/Workspaces/Core/Portable/Options/EditorConfigStorageLocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,59 @@ internal sealed class EditorConfigStorageLocation : OptionStorageLocation

private Func<string, Type, object> _parseValue;

private static Func<string, Type, object> _cachedParseValue = (s, type) =>
{
if (type == typeof(int))
{
var value = 0;
return int.TryParse(s, out value) ? (object)value : null;
}
else if (type == typeof(bool))
{
var value = false;
return bool.TryParse(s, out value) ? (object)value : null;
}
else if (type == typeof(CodeStyleOption<bool>))
{
var value = CodeStyleOption<bool>.Default;
return TryParseEditorConfigCodeStyleOption(s, out value) ? value : null;
}
else
{
throw new NotSupportedException(WorkspacesResources.Option_0_has_an_unsupported_type_to_use_with_1_You_should_specify_a_parsing_function);
}
};

private Func<IReadOnlyDictionary<string, object>, Type, (object result, bool succeeded)> _tryParseDictionary;

private static Func<IReadOnlyDictionary<string, object>, Type, (object result, bool succeeded)> _cachedTryParseDictionary = (dictionary, type) =>
{
if (type == typeof(NamingStylePreferences))
{
var result = EditorConfigNamingStyleParser.GetNamingStylesFromDictionary(dictionary);
if (!result.NamingRules.Any() &&
!result.NamingStyles.Any() &&
!result.SymbolSpecifications.Any())
{
return (result: result, succeeded: false);
}
return (result: result, succeeded: true);
}
else
{
throw new NotSupportedException(WorkspacesResources.Option_0_has_an_unsupported_type_to_use_with_1_You_should_specify_a_parsing_function);
}
};

public bool TryParseReadonlyDictionary(IReadOnlyDictionary<string, object> allRawConventions, Type type, out object result)
{
if (_parseValue != null && KeyName != null)
{
if (allRawConventions.TryGetValue(KeyName, out object value))
{
result = _parseValue(value.ToString(), type);
return true;
return result != null;
}
}
else if (_tryParseDictionary != null)
Expand All @@ -44,26 +87,7 @@ public bool TryParseReadonlyDictionary(IReadOnlyDictionary<string, object> allRa
public EditorConfigStorageLocation(string keyName)
{
KeyName = keyName;

_parseValue = (s, type) =>
{
if (type == typeof(int))
{
return int.Parse(s);
}
else if (type == typeof(bool))
{
return bool.Parse(s);
}
else if (type == typeof(CodeStyleOption<bool>))
{
return ParseEditorConfigCodeStyleOption(s);
}
else
{
throw new NotSupportedException(WorkspacesResources.Option_0_has_an_unsupported_type_to_use_with_1_You_should_specify_a_parsing_function);
}
};
_parseValue = _cachedParseValue;
}

public EditorConfigStorageLocation(string keyName, Func<string, object> parseValue)
Expand All @@ -77,25 +101,7 @@ public EditorConfigStorageLocation(string keyName, Func<string, object> parseVal
public EditorConfigStorageLocation()
{
// If the user didn't pass a keyName assume we need to parse the entire dictionary
_tryParseDictionary = (dictionary, type) =>
{
if (type == typeof(NamingStylePreferences))
{
var result = EditorConfigNamingStyleParser.GetNamingStylesFromDictionary(dictionary);
if (!result.NamingRules.Any() &&
!result.NamingStyles.Any() &&
!result.SymbolSpecifications.Any())
{
return (result: result, succeeded: false);
}
return (result: result, succeeded: true);
}
else
{
throw new NotSupportedException(WorkspacesResources.Option_0_has_an_unsupported_type_to_use_with_1_You_should_specify_a_parsing_function);
}
};
_tryParseDictionary = _cachedTryParseDictionary;
}

public EditorConfigStorageLocation(Func<IReadOnlyDictionary<string, object>, (object result, bool succeeded)> tryParseDictionary)
Expand Down

0 comments on commit d935107

Please sign in to comment.