-
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
Move Options and CodeStyle APIs to shared layer #42323
Changes from 2 commits
6692e76
cd860f7
a2c78bd
762c09c
2848a31
70b4089
3ba9025
7077431
30b4e99
e96fd8f
e182acd
2143656
a9da22c
b9cf84d
00b3593
6e1e5dd
74b90a8
f1b4348
cbead33
e4c7e8e
7e3c47e
c765e1f
11d03e1
80a215d
d6bc6f6
193ac53
8b547f4
b704f66
c45db4c
fb10c5e
04056c0
de4d5d9
7301aa3
0ff090f
f47f6d1
50287de
4985a18
0066c5c
f52f4fe
736ba89
0f22449
9793b0b
6192d8e
759dc07
e8464de
8961e3b
d02be0c
02f40aa
a56b5a7
717c508
17ce912
c533f82
6878054
f139867
6aa9798
81ff9eb
17fbad5
4c01f51
950b3b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,194 +3,56 @@ | |
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Xml.Linq; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
#if CODE_STYLE | ||
namespace Microsoft.CodeAnalysis.Internal.Options | ||
#else | ||
namespace Microsoft.CodeAnalysis.CodeStyle | ||
#endif | ||
{ | ||
internal interface ICodeStyleOption | ||
{ | ||
XElement ToXElement(); | ||
object Value { get; } | ||
NotificationOption Notification { get; } | ||
ICodeStyleOption WithValue(object value); | ||
ICodeStyleOption WithNotification(NotificationOption notification); | ||
} | ||
|
||
/// <summary> | ||
/// Represents a code style option and an associated notification option. Supports | ||
/// being instantiated with T as a <see cref="bool"/> or an <c>enum type</c>. | ||
/// | ||
/// CodeStyleOption also has some basic support for migration a <see cref="bool"/> option | ||
/// forward to an <c>enum type</c> option. Specifically, if a previously serialized | ||
/// bool-CodeStyleOption is then deserialized into an enum-CodeStyleOption then 'false' | ||
/// values will be migrated to have the 0-value of the enum, and 'true' values will be | ||
/// migrated to have the 1-value of the enum. | ||
/// | ||
/// Similarly, enum-type code options will serialize out in a way that is compatible with | ||
/// hosts that expect the value to be a boolean. Specifically, if the enum value is 0 or 1 | ||
/// then those values will write back as false/true. | ||
/// </summary> | ||
/// <inheritdoc cref="CodeStyleOption2{T}"/> | ||
public class CodeStyleOption<T> : ICodeStyleOption, IEquatable<CodeStyleOption<T>> | ||
{ | ||
private readonly CodeStyleOption2<T> _codeStyleOptionImpl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the existing code from this type was copied directly into |
||
public static CodeStyleOption<T> Default => new CodeStyleOption<T>(default, NotificationOption.Silent); | ||
|
||
private const int SerializationVersion = 1; | ||
|
||
private NotificationOption _notification; | ||
internal CodeStyleOption(CodeStyleOption2<T> codeStyleOptionImpl) | ||
{ | ||
_codeStyleOptionImpl = codeStyleOptionImpl; | ||
} | ||
|
||
public CodeStyleOption(T value, NotificationOption notification) | ||
: this(new CodeStyleOption2<T>(value, notification ?? throw new ArgumentNullException(nameof(notification)))) | ||
mavasani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
Value = value; | ||
_notification = notification ?? throw new ArgumentNullException(nameof(notification)); | ||
} | ||
|
||
public T Value { get; set; } | ||
public T Value | ||
{ | ||
get => _codeStyleOptionImpl.Value; | ||
set => _codeStyleOptionImpl.Value = value; | ||
} | ||
|
||
object ICodeStyleOption.Value => this.Value; | ||
NotificationOption2 ICodeStyleOption.Notification => _codeStyleOptionImpl.Notification; | ||
ICodeStyleOption ICodeStyleOption.WithValue(object value) => new CodeStyleOption<T>((T)value, Notification); | ||
ICodeStyleOption ICodeStyleOption.WithNotification(NotificationOption notification) => new CodeStyleOption<T>(Value, notification); | ||
|
||
private int EnumValueAsInt32 => (int)(object)Value; | ||
ICodeStyleOption ICodeStyleOption.WithNotification(NotificationOption2 notification) => new CodeStyleOption<T>(Value, notification); | ||
|
||
public NotificationOption Notification | ||
{ | ||
get => _notification; | ||
set => _notification = value ?? throw new ArgumentNullException(nameof(value)); | ||
get => _codeStyleOptionImpl.Notification; | ||
set => _codeStyleOptionImpl.Notification = value ?? throw new ArgumentNullException(nameof(value)); | ||
mavasani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
public XElement ToXElement() => | ||
new XElement(nameof(CodeStyleOption<T>), // `nameof()` returns just "CodeStyleOption" | ||
new XAttribute(nameof(SerializationVersion), SerializationVersion), | ||
new XAttribute("Type", GetTypeNameForSerialization()), | ||
new XAttribute(nameof(Value), GetValueForSerialization()), | ||
new XAttribute(nameof(DiagnosticSeverity), Notification.Severity.ToDiagnosticSeverity() ?? DiagnosticSeverity.Hidden)); | ||
|
||
private object GetValueForSerialization() | ||
{ | ||
if (typeof(T) == typeof(string)) | ||
{ | ||
return Value; | ||
} | ||
else if (typeof(T) == typeof(bool)) | ||
{ | ||
return Value; | ||
} | ||
else if (IsZeroOrOneValueOfEnum()) | ||
{ | ||
return EnumValueAsInt32 == 1; | ||
} | ||
else | ||
{ | ||
return EnumValueAsInt32; | ||
} | ||
} | ||
|
||
private string GetTypeNameForSerialization() | ||
{ | ||
if (typeof(T) == typeof(string)) | ||
{ | ||
return nameof(String); | ||
} | ||
if (typeof(T) == typeof(bool) || IsZeroOrOneValueOfEnum()) | ||
{ | ||
return nameof(Boolean); | ||
} | ||
else | ||
{ | ||
return nameof(Int32); | ||
} | ||
} | ||
|
||
private bool IsZeroOrOneValueOfEnum() | ||
{ | ||
var intVal = EnumValueAsInt32; | ||
return intVal == 0 || intVal == 1; | ||
} | ||
public XElement ToXElement() => _codeStyleOptionImpl.ToXElement(); | ||
|
||
public static CodeStyleOption<T> FromXElement(XElement element) | ||
{ | ||
var typeAttribute = element.Attribute("Type"); | ||
var valueAttribute = element.Attribute(nameof(Value)); | ||
var severityAttribute = element.Attribute(nameof(DiagnosticSeverity)); | ||
var version = (int)element.Attribute(nameof(SerializationVersion)); | ||
|
||
if (typeAttribute == null || valueAttribute == null || severityAttribute == null) | ||
{ | ||
// data from storage is corrupt, or nothing has been stored yet. | ||
return Default; | ||
} | ||
|
||
if (version != SerializationVersion) | ||
{ | ||
return Default; | ||
} | ||
|
||
var parser = GetParser(typeAttribute.Value); | ||
var value = parser(valueAttribute.Value); | ||
var severity = (DiagnosticSeverity)Enum.Parse(typeof(DiagnosticSeverity), severityAttribute.Value); | ||
|
||
return new CodeStyleOption<T>(value, severity switch | ||
{ | ||
DiagnosticSeverity.Hidden => NotificationOption.Silent, | ||
DiagnosticSeverity.Info => NotificationOption.Suggestion, | ||
DiagnosticSeverity.Warning => NotificationOption.Warning, | ||
DiagnosticSeverity.Error => NotificationOption.Error, | ||
_ => throw new ArgumentException(nameof(element)), | ||
}); | ||
} | ||
|
||
private static Func<string, T> GetParser(string type) | ||
=> type switch | ||
{ | ||
nameof(Boolean) => | ||
// Try to map a boolean value. Either map it to true/false if we're a | ||
// CodeStyleOption<bool> or map it to the 0 or 1 value for an enum if we're | ||
// a CodeStyleOption<SomeEnumType>. | ||
(Func<string, T>)(v => Convert(bool.Parse(v))), | ||
nameof(Int32) => v => Convert(int.Parse(v)), | ||
nameof(String) => v => (T)(object)v, | ||
_ => throw new ArgumentException(nameof(type)), | ||
}; | ||
|
||
private static T Convert(bool b) | ||
{ | ||
// If we had a bool and we wanted a bool, then just return this value. | ||
if (typeof(T) == typeof(bool)) | ||
{ | ||
return (T)(object)b; | ||
} | ||
|
||
// Map booleans to the 1/0 value of the enum. | ||
return b ? (T)(object)1 : (T)(object)0; | ||
} | ||
|
||
private static T Convert(int i) | ||
{ | ||
// We got an int, but we wanted a bool. Map 0 to false, 1 to true, and anything else to default. | ||
if (typeof(T) == typeof(bool)) | ||
{ | ||
return (T)(object)(i == 1); | ||
} | ||
|
||
// If had an int and we wanted an enum, then just return this value. | ||
return (T)(object)(i); | ||
} | ||
=> new CodeStyleOption<T>(CodeStyleOption2<T>.FromXElement(element)); | ||
|
||
public bool Equals(CodeStyleOption<T> other) | ||
=> EqualityComparer<T>.Default.Equals(Value, other.Value) && | ||
Notification == other.Notification; | ||
=> _codeStyleOptionImpl.Equals(other?._codeStyleOptionImpl); | ||
|
||
public override bool Equals(object obj) | ||
=> obj is CodeStyleOption<T> option && | ||
Equals(option); | ||
|
||
public override int GetHashCode() | ||
=> unchecked((Notification.GetHashCode() * (int)0xA5555529) + Value.GetHashCode()); | ||
=> _codeStyleOptionImpl.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.
Moved to shared layer