diff --git a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs index f91f4aa928302de645fabacde96b6c405dd407fe..0ac3d930fae7a7057dedee54c9936d25f38608f2 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs @@ -4,12 +4,18 @@ using System; using System.Xml.Linq; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeStyle { /// public class CodeStyleOption : ICodeStyleOption, IEquatable> { + static CodeStyleOption() + { + ObjectBinder.RegisterTypeReader(typeof(CodeStyleOption), ReadFrom); + } + private readonly CodeStyleOption2 _codeStyleOptionImpl; public static CodeStyleOption Default => new CodeStyleOption(default, NotificationOption.Silent); @@ -27,6 +33,7 @@ public T Value set => _codeStyleOptionImpl.Value = value; } + bool IObjectWritable.ShouldReuseInSerialization => _codeStyleOptionImpl.ShouldReuseInSerialization; object ICodeStyleOption.Value => this.Value; NotificationOption2 ICodeStyleOption.Notification => _codeStyleOptionImpl.Notification; ICodeStyleOption ICodeStyleOption.WithValue(object value) => new CodeStyleOption((T)value, Notification); @@ -48,6 +55,12 @@ public NotificationOption Notification public static CodeStyleOption FromXElement(XElement element) => new CodeStyleOption(CodeStyleOption2.FromXElement(element)); + void IObjectWritable.WriteTo(ObjectWriter writer) + => _codeStyleOptionImpl.WriteTo(writer); + + internal static CodeStyleOption ReadFrom(ObjectReader reader) + => new CodeStyleOption(CodeStyleOption2.ReadFrom(reader)); + public bool Equals(CodeStyleOption other) => _codeStyleOptionImpl.Equals(other?._codeStyleOptionImpl); diff --git a/src/Workspaces/Core/Portable/Options/SerializableOptionSet.cs b/src/Workspaces/Core/Portable/Options/SerializableOptionSet.cs index eb30322d46b3a3ca25fcbec8dbc42d8093837e31..a53c7f486f74c9909a876fa62dc12e3316563546 100644 --- a/src/Workspaces/Core/Portable/Options/SerializableOptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/SerializableOptionSet.cs @@ -11,7 +11,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using System.Xml.Linq; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Roslyn.Utilities; @@ -206,12 +205,12 @@ public void Serialize(ObjectWriter writer, CancellationToken cancellationToken) } kind = OptionValueKind.CodeStyleOption; - valueToWrite = codeStyleOption.ToXElement().ToString(); + valueToWrite = codeStyleOption; break; case NamingStylePreferences stylePreferences: kind = OptionValueKind.NamingStylePreferences; - valueToWrite = stylePreferences.CreateXElement().ToString(); + valueToWrite = stylePreferences; break; case string str: @@ -253,6 +252,11 @@ public void Serialize(ObjectWriter writer, CancellationToken cancellationToken) RoslynDebug.Assert(value != null); writer.WriteInt32((int)value); } + else if (kind == OptionValueKind.CodeStyleOption || kind == OptionValueKind.NamingStylePreferences) + { + RoslynDebug.Assert(value != null); + ((IObjectWritable)value).WriteTo(writer); + } else { writer.WriteValue(value); @@ -308,7 +312,13 @@ public static SerializableOptionSet Deserialize(ObjectReader reader, IOptionServ { var optionKey = DeserializeOptionKey(reader, lookup); var kind = (OptionValueKind)reader.ReadInt32(); - var readValue = kind == OptionValueKind.Enum ? reader.ReadInt32() : reader.ReadValue(); + var readValue = kind switch + { + OptionValueKind.Enum => reader.ReadInt32(), + OptionValueKind.CodeStyleOption => CodeStyleOption2.ReadFrom(reader), + OptionValueKind.NamingStylePreferences => NamingStylePreferences.ReadFrom(reader), + _ => reader.ReadValue(), + }; if (optionKey == default || !serializableOptions.Contains(optionKey.Option)) @@ -327,7 +337,7 @@ public static SerializableOptionSet Deserialize(ObjectReader reader, IOptionServ continue; } - var parsedCodeStyleOption = CodeStyleOption2.FromXElement(XElement.Parse((string)readValue)); + var parsedCodeStyleOption = (CodeStyleOption2)readValue; var value = parsedCodeStyleOption.Value; var type = optionKey.Option.Type.GenericTypeArguments[0]; var convertedValue = type.IsEnum ? Enum.ToObject(type, value) : Convert.ChangeType(value, type); @@ -335,7 +345,7 @@ public static SerializableOptionSet Deserialize(ObjectReader reader, IOptionServ break; case OptionValueKind.NamingStylePreferences: - optionValue = NamingStylePreferences.FromXElement(XElement.Parse((string)readValue)); + optionValue = (NamingStylePreferences)readValue; break; case OptionValueKind.Enum: diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs index 2bf2edee3893d958eae9ad1633bedf602b4e0108..65c8af814b4579ff5088fffc3e95eb1a3d6b9636 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeStyle/CodeStyleOption2`1.cs @@ -6,10 +6,11 @@ using System.Collections.Generic; using System.Xml.Linq; using Microsoft.CodeAnalysis.Diagnostics; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeStyle { - internal interface ICodeStyleOption + internal interface ICodeStyleOption : IObjectWritable { XElement ToXElement(); object Value { get; } @@ -38,6 +39,11 @@ internal interface ICodeStyleOption /// internal partial class CodeStyleOption2 : ICodeStyleOption, IEquatable> { + static CodeStyleOption2() + { + ObjectBinder.RegisterTypeReader(typeof(CodeStyleOption2), ReadFrom); + } + public static CodeStyleOption2 Default => new CodeStyleOption2(default, NotificationOption2.Silent); private const int SerializationVersion = 1; @@ -153,6 +159,28 @@ public static CodeStyleOption2 FromXElement(XElement element) }); } + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + { + writer.WriteValue(GetValueForSerialization()); + writer.WriteInt32((int)(Notification.Severity.ToDiagnosticSeverity() ?? DiagnosticSeverity.Hidden)); + } + + public static CodeStyleOption2 ReadFrom(ObjectReader reader) + { + return new CodeStyleOption2( + reader.ReadValue(), + (DiagnosticSeverity)reader.ReadInt32() switch + { + DiagnosticSeverity.Hidden => NotificationOption2.Silent, + DiagnosticSeverity.Info => NotificationOption2.Suggestion, + DiagnosticSeverity.Warning => NotificationOption2.Warning, + DiagnosticSeverity.Error => NotificationOption2.Error, + var v => throw ExceptionUtilities.UnexpectedValue(v), + }); + } + private static Func GetParser(string type) => type switch { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 3bbc78457b7ae93d9492c6c74205e36c11b5733e..9ff4f7dfcf947bdd45d9e109d31a5a0cb464efdd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -189,6 +189,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..9153c27f7b56cc7dc5f6771ab489235e387ea90f --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ObjectWriterExtensions.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Shared.Extensions +{ + internal static class ObjectWriterExtensions + { + public static void WriteArray(this ObjectWriter writer, ImmutableArray values, Action write) + { + writer.WriteInt32(values.Length); + foreach (var val in values) + write(writer, val); + } + } + + internal static class ObjectReaderExtensions + { + public static ImmutableArray ReadArray(this ObjectReader reader, Func read) + { + var length = reader.ReadInt32(); + using var _ = ArrayBuilder.GetInstance(length, out var builder); + + for (var i = 0; i < length; i++) + builder.Add(read(reader)); + + return builder.ToImmutable(); + } + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs index 7ff97cb53d91446d8225667770fc1d36815d637b..576e9ac9c789393b199e38b239bc24c2c1b53638 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.NamingStyles { - internal partial struct NamingStyle : IEquatable + internal partial struct NamingStyle : IEquatable, IObjectWritable { public Guid ID { get; } public string Name { get; } @@ -493,5 +493,28 @@ internal static NamingStyle FromXElement(XElement namingStyleElement) suffix: namingStyleElement.Attribute(nameof(Suffix)).Value, wordSeparator: namingStyleElement.Attribute(nameof(WordSeparator)).Value, capitalizationScheme: (Capitalization)Enum.Parse(typeof(Capitalization), namingStyleElement.Attribute(nameof(CapitalizationScheme)).Value)); + + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + { + writer.WriteGuid(ID); + writer.WriteString(Name); + writer.WriteString(Prefix ?? string.Empty); + writer.WriteString(Suffix ?? string.Empty); + writer.WriteString(WordSeparator ?? string.Empty); + writer.WriteInt32((int)CapitalizationScheme); + } + + public static NamingStyle ReadFrom(ObjectReader reader) + { + return new NamingStyle( + reader.ReadGuid(), + reader.ReadString(), + reader.ReadString(), + reader.ReadString(), + reader.ReadString(), + (Capitalization)reader.ReadInt32()); + } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs index 99ffd45f7c00b86fea991cf8a92c7c0d4fe86352..8dc932d0d1a66d0d42cc3e506f9867929c36508f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/NamingStylePreferences.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Xml.Linq; using Microsoft.CodeAnalysis.NamingStyles; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles @@ -18,8 +19,13 @@ namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles /// 2. Name Style /// 3. Naming Rule (points to Symbol Specification IDs) /// - internal sealed class NamingStylePreferences : IEquatable + internal sealed class NamingStylePreferences : IEquatable, IObjectWritable { + static NamingStylePreferences() + { + ObjectBinder.RegisterTypeReader(typeof(NamingStylePreferences), ReadFrom); + } + private const int s_serializationVersion = 5; public readonly ImmutableArray SymbolSpecifications; @@ -77,6 +83,23 @@ internal static NamingStylePreferences FromXElement(XElement element) .Select(SerializableNamingRule.FromXElement).ToImmutableArray()); } + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + { + writer.WriteArray(SymbolSpecifications, (w, v) => v.WriteTo(w)); + writer.WriteArray(NamingStyles, (w, v) => v.WriteTo(w)); + writer.WriteArray(NamingRules, (w, v) => v.WriteTo(w)); + } + + public static NamingStylePreferences ReadFrom(ObjectReader reader) + { + return new NamingStylePreferences( + reader.ReadArray(r => SymbolSpecification.ReadFrom(r)), + reader.ReadArray(r => NamingStyle.ReadFrom(r)), + reader.ReadArray(r => SerializableNamingRule.ReadFrom(r))); + } + public override bool Equals(object obj) => Equals(obj as NamingStylePreferences); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SerializableNamingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SerializableNamingRule.cs index df2f911648232ebbeeea536ab676df14b8c291ce..929a9f65944d89831bd415b1d6af25f53b52e28e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SerializableNamingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SerializableNamingRule.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles { - internal sealed class SerializableNamingRule : IEquatable + internal sealed class SerializableNamingRule : IEquatable, IObjectWritable { public Guid SymbolSpecificationID; public Guid NamingStyleID; @@ -42,6 +42,25 @@ internal static SerializableNamingRule FromXElement(XElement namingRuleElement) }; } + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + { + writer.WriteGuid(SymbolSpecificationID); + writer.WriteGuid(NamingStyleID); + writer.WriteInt32((int)(EnforcementLevel.ToDiagnosticSeverity() ?? DiagnosticSeverity.Hidden)); + } + + public static SerializableNamingRule ReadFrom(ObjectReader reader) + { + return new SerializableNamingRule + { + SymbolSpecificationID = reader.ReadGuid(), + NamingStyleID = reader.ReadGuid(), + EnforcementLevel = ((DiagnosticSeverity)reader.ReadInt32()).ToReportDiagnostic(), + }; + } + public override bool Equals(object obj) { return Equals(obj as SerializableNamingRule); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SymbolSpecification.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SymbolSpecification.cs index c0543c03d141fafbd581ad98af1a636f2dd4a2a9..76ca282826bb65cda75e6337d19bdba7941415f0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SymbolSpecification.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/Serialization/SymbolSpecification.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles { - internal sealed class SymbolSpecification : IEquatable + internal sealed class SymbolSpecification : IEquatable, IObjectWritable { private static readonly SymbolSpecification DefaultSymbolSpecificationTemplate = CreateDefaultSymbolSpecification(); @@ -218,6 +218,27 @@ internal XElement CreateXElement() CreateModifiersXElement()); } + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + { + writer.WriteGuid(ID); + writer.WriteString(Name); + writer.WriteArray(ApplicableSymbolKindList, (w, v) => v.WriteTo(w)); + writer.WriteArray(ApplicableAccessibilityList, (w, v) => w.WriteInt32((int)v)); + writer.WriteArray(RequiredModifierList, (w, v) => v.WriteTo(w)); + } + + public static SymbolSpecification ReadFrom(ObjectReader reader) + { + return new SymbolSpecification( + reader.ReadGuid(), + reader.ReadString(), + reader.ReadArray(r => SymbolKindOrTypeKind.ReadFrom(r)), + reader.ReadArray(r => (Accessibility)r.ReadInt32()), + reader.ReadArray(r => ModifierKind.ReadFrom(r))); + } + private XElement CreateSymbolKindsXElement() { var symbolKindsElement = new XElement(nameof(ApplicableSymbolKindList)); @@ -309,7 +330,7 @@ private interface ISymbolMatcher bool MatchesSymbol(ISymbol symbol); } - public struct SymbolKindOrTypeKind : IEquatable, ISymbolMatcher + public struct SymbolKindOrTypeKind : IEquatable, ISymbolMatcher, IObjectWritable { public SymbolKind? SymbolKind { get; } public TypeKind? TypeKind { get; } @@ -348,6 +369,43 @@ internal XElement CreateXElement() MethodKind.HasValue ? new XElement(nameof(MethodKind), MethodKind) : throw ExceptionUtilities.Unreachable; + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + { + if (SymbolKind != null) + { + writer.WriteInt32(1); + writer.WriteInt32((int)SymbolKind); + } + else if (TypeKind != null) + { + writer.WriteInt32(2); + writer.WriteInt32((int)TypeKind); + } + else if (MethodKind != null) + { + writer.WriteInt32(3); + writer.WriteInt32((int)MethodKind); + } + else + { + writer.WriteInt32(0); + } + } + + public static SymbolKindOrTypeKind ReadFrom(ObjectReader reader) + { + return reader.ReadInt32() switch + { + 0 => default, + 1 => new SymbolKindOrTypeKind((SymbolKind)reader.ReadInt32()), + 2 => new SymbolKindOrTypeKind((TypeKind)reader.ReadInt32()), + 3 => new SymbolKindOrTypeKind((MethodKind)reader.ReadInt32()), + var v => throw ExceptionUtilities.UnexpectedValue(v), + }; + } + internal static SymbolKindOrTypeKind AddSymbolKindFromXElement(XElement symbolKindElement) => new SymbolKindOrTypeKind((SymbolKind)Enum.Parse(typeof(SymbolKind), symbolKindElement.Value)); @@ -370,7 +428,7 @@ public override int GetHashCode() } } - public struct ModifierKind : ISymbolMatcher, IEquatable + public struct ModifierKind : ISymbolMatcher, IEquatable, IObjectWritable { public ModifierKindEnum ModifierKindWrapper; @@ -458,6 +516,14 @@ internal XElement CreateXElement() internal static ModifierKind FromXElement(XElement modifierElement) => new ModifierKind((ModifierKindEnum)Enum.Parse(typeof(ModifierKindEnum), modifierElement.Value)); + public bool ShouldReuseInSerialization => false; + + public void WriteTo(ObjectWriter writer) + => writer.WriteInt32((int)ModifierKindWrapper); + + public static ModifierKind ReadFrom(ObjectReader reader) + => new ModifierKind((ModifierKindEnum)reader.ReadInt32()); + public override bool Equals(object obj) => obj is ModifierKind kind && Equals(kind);