// 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 System.Diagnostics; using System.Linq; using System.Runtime.Serialization; using System.Xml.Linq; using Microsoft.CodeAnalysis.NamingStyles; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; /// <summary> /// Contains all information related to Naming Style Preferences. /// 1. Symbol Specifications /// 2. Name Style /// 3. Naming Rule (points to Symbol Specification IDs) /// </summary> [DataContract] internal sealed class NamingStylePreferences : IEquatable<NamingStylePreferences> { private const int s_serializationVersion = 5; private static readonly string _defaultNamingPreferencesString = $@" <NamingPreferencesInfo SerializationVersion=""{s_serializationVersion}""> <SymbolSpecifications> <SymbolSpecification ID=""5c545a62-b14d-460a-88d8-e936c0a39316"" Name=""{CompilerExtensionsResources.Class}""> <ApplicableSymbolKindList> <TypeKind>Class</TypeKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""23d856b4-5089-4405-83ce-749aada99153"" Name=""{CompilerExtensionsResources.Interface}""> <ApplicableSymbolKindList> <TypeKind>Interface</TypeKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""d1796e78-ff66-463f-8576-eb46416060c0"" Name=""{CompilerExtensionsResources.Struct}""> <ApplicableSymbolKindList> <TypeKind>Struct</TypeKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""d8af8dc6-1ade-441d-9947-8946922e198a"" Name=""{CompilerExtensionsResources.Enum}""> <ApplicableSymbolKindList> <TypeKind>Enum</TypeKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""408a3347-b908-4b54-a954-1355e64c1de3"" Name=""{CompilerExtensionsResources.Delegate}""> <ApplicableSymbolKindList> <TypeKind>Delegate</TypeKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""830657f6-e7e5-4830-b328-f109d3b6c165"" Name=""{CompilerExtensionsResources.Event}""> <ApplicableSymbolKindList> <SymbolKind>Event</SymbolKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" Name=""{CompilerExtensionsResources.Method}""> <ApplicableSymbolKindList> <MethodKind>Ordinary</MethodKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""af410767-f189-47c6-b140-aeccf1ff242e"" Name=""{CompilerExtensionsResources.Private_Method}""> <ApplicableSymbolKindList> <MethodKind>Ordinary</MethodKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Private</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""8076757e-6a4a-47f1-9b4b-ae8a3284e987"" Name=""{CompilerExtensionsResources.Abstract_Method}""> <ApplicableSymbolKindList> <MethodKind>Ordinary</MethodKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList> <ModifierKind>IsAbstract</ModifierKind> </RequiredModifierList> </SymbolSpecification> <SymbolSpecification ID=""16133061-a8e7-4392-92c3-1d93cd54c218"" Name=""{CompilerExtensionsResources.Static_Method}""> <ApplicableSymbolKindList> <MethodKind>Ordinary</MethodKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList> <ModifierKind>IsStatic</ModifierKind> </RequiredModifierList> </SymbolSpecification> <SymbolSpecification ID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" Name=""{CompilerExtensionsResources.Property}""> <ApplicableSymbolKindList> <SymbolKind>Property</SymbolKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""b24a91ce-3501-4799-b6df-baf044156c83"" Name=""{CompilerExtensionsResources.Public_or_Protected_Field}""> <ApplicableSymbolKindList> <SymbolKind>Field</SymbolKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""70af42cb-1741-4027-969c-9edc4877d965"" Name=""{CompilerExtensionsResources.Static_Field}""> <ApplicableSymbolKindList> <SymbolKind>Field</SymbolKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList> <ModifierKind>IsStatic</ModifierKind> </RequiredModifierList> </SymbolSpecification> <SymbolSpecification ID=""10790aa6-0a0b-432d-a52d-d252ca92302b"" Name=""{CompilerExtensionsResources.Private_or_Internal_Field}""> <ApplicableSymbolKindList> <SymbolKind>Field</SymbolKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""ac995be4-88de-4771-9dcc-a456a7c02d89"" Name=""{CompilerExtensionsResources.Private_or_Internal_Static_Field}""> <ApplicableSymbolKindList> <SymbolKind>Field</SymbolKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList> <ModifierKind>IsStatic</ModifierKind> </RequiredModifierList> </SymbolSpecification> <SymbolSpecification ID=""2c07f5bf-bc81-4c2b-82b4-ae9b3ffd0ba4"" Name=""{CompilerExtensionsResources.Types}""> <ApplicableSymbolKindList> <TypeKind>Class</TypeKind> <TypeKind>Struct</TypeKind> <TypeKind>Interface</TypeKind> <TypeKind>Enum</TypeKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> <SymbolSpecification ID=""5f3ddba1-279f-486c-801e-5c097c36dd85"" Name=""{CompilerExtensionsResources.Non_Field_Members}""> <ApplicableSymbolKindList> <SymbolKind>Property</SymbolKind> <SymbolKind>Event</SymbolKind> <MethodKind>Ordinary</MethodKind> </ApplicableSymbolKindList> <ApplicableAccessibilityList> <AccessibilityKind>Public</AccessibilityKind> <AccessibilityKind>Internal</AccessibilityKind> <AccessibilityKind>Private</AccessibilityKind> <AccessibilityKind>Protected</AccessibilityKind> <AccessibilityKind>ProtectedOrInternal</AccessibilityKind> <AccessibilityKind>ProtectedAndInternal</AccessibilityKind> </ApplicableAccessibilityList> <RequiredModifierList /> </SymbolSpecification> </SymbolSpecifications> <NamingStyles> <NamingStyle ID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" Name=""{CompilerExtensionsResources.Pascal_Case}"" Prefix="""" Suffix="""" WordSeparator="""" CapitalizationScheme=""PascalCase"" /> <NamingStyle ID=""1ecc5eb6-b5fc-49a5-a9f1-a980f3e48c92"" Name=""{CompilerExtensionsResources.Begins_with_I}"" Prefix=""I"" Suffix="""" WordSeparator="""" CapitalizationScheme=""PascalCase"" /> </NamingStyles> <NamingRules> <SerializableNamingRule SymbolSpecificationID=""23d856b4-5089-4405-83ce-749aada99153"" NamingStyleID=""1ecc5eb6-b5fc-49a5-a9f1-a980f3e48c92"" EnforcementLevel=""Info"" /> <SerializableNamingRule SymbolSpecificationID=""2c07f5bf-bc81-4c2b-82b4-ae9b3ffd0ba4"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Info"" /> <SerializableNamingRule SymbolSpecificationID=""5f3ddba1-279f-486c-801e-5c097c36dd85"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Info"" /> </NamingRules> </NamingPreferencesInfo> "; [DataMember(Order = 0)] public readonly ImmutableArray<SymbolSpecification> SymbolSpecifications; [DataMember(Order = 1)] public readonly ImmutableArray<NamingStyle> NamingStyles; [DataMember(Order = 2)] public ImmutableArray<SerializableNamingRule> SerializableNamingRules { get { if (_lazySerializableRules.IsDefault) { ImmutableInterlocked.InterlockedInitialize( ref _lazySerializableRules, Rules.NamingRules.SelectAsArray(static rule => new SerializableNamingRule { SymbolSpecificationID = rule.SymbolSpecification.ID, NamingStyleID = rule.NamingStyle.ID, EnforcementLevel = rule.EnforcementLevel, })); } return _lazySerializableRules; } } private ImmutableArray<SerializableNamingRule> _lazySerializableRules; public readonly NamingStyleRules Rules; // used for deserialization public NamingStylePreferences( ImmutableArray<SymbolSpecification> symbolSpecifications, ImmutableArray<NamingStyle> namingStyles, ImmutableArray<SerializableNamingRule> serializableRules) { Contract.ThrowIfFalse(serializableRules.IsEmpty == namingStyles.IsEmpty); Contract.ThrowIfFalse(serializableRules.IsEmpty == symbolSpecifications.IsEmpty); SymbolSpecifications = symbolSpecifications; NamingStyles = namingStyles; _lazySerializableRules = serializableRules; Rules = new NamingStyleRules( serializableRules.SelectAsArray(static (rule, arg) => new NamingRule( arg.symbolSpecifications.Single(static (s, id) => s.ID == id, rule.SymbolSpecificationID), arg.namingStyles.Single(static (s, id) => s.ID == id, rule.NamingStyleID), rule.EnforcementLevel), (symbolSpecifications, namingStyles))); } public NamingStylePreferences( ImmutableArray<SymbolSpecification> symbolSpecifications, ImmutableArray<NamingStyle> namingStyles, ImmutableArray<NamingRule> namingRules) { Contract.ThrowIfFalse(namingRules.IsEmpty == namingStyles.IsEmpty); Contract.ThrowIfFalse(namingRules.IsEmpty == symbolSpecifications.IsEmpty); SymbolSpecifications = symbolSpecifications; NamingStyles = namingStyles; Rules = new NamingStyleRules(namingRules); } public static NamingStylePreferences Default { get; } = FromXElement(XElement.Parse(DefaultNamingPreferencesString)); public static NamingStylePreferences Empty { get; } = new([], [], ImmutableArray<NamingRule>.Empty); public static string DefaultNamingPreferencesString => _defaultNamingPreferencesString; public bool IsEmpty => Rules.NamingRules.IsEmpty; internal XElement CreateXElement() { return new XElement("NamingPreferencesInfo", new XAttribute("SerializationVersion", s_serializationVersion), new XElement("SymbolSpecifications", SymbolSpecifications.Select(s => s.CreateXElement())), new XElement("NamingStyles", NamingStyles.Select(n => n.CreateXElement())), new XElement("NamingRules", SerializableNamingRules.Select(n => n.CreateXElement()))); } internal static NamingStylePreferences FromXElement(XElement element) { element = GetUpgradedSerializationIfNecessary(element); return new NamingStylePreferences( [.. element.Element("SymbolSpecifications")!.Elements(nameof(SymbolSpecification)).Select(SymbolSpecification.FromXElement)], [.. element.Element("NamingStyles")!.Elements(nameof(NamingStyle)).Select(NamingStyle.FromXElement)], [.. element.Element("NamingRules")!.Elements(nameof(SerializableNamingRule)).Select(SerializableNamingRule.FromXElement)]); } public override bool Equals(object? obj) => Equals(obj as NamingStylePreferences); public bool Equals(NamingStylePreferences? other) { if (other is null) return false; return SymbolSpecifications.SequenceEqual(other.SymbolSpecifications) && NamingStyles.SequenceEqual(other.NamingStyles) && Rules.NamingRules.SequenceEqual(other.Rules.NamingRules); } public static bool operator ==(NamingStylePreferences? left, NamingStylePreferences? right) { if (left is null && right is null) { return true; } else if (left is null || right is null) { return false; } return left.Equals(right); } public static bool operator !=(NamingStylePreferences left, NamingStylePreferences right) => !(left == right); public override int GetHashCode() { return Hash.Combine(Hash.CombineValues(SymbolSpecifications), Hash.Combine(Hash.CombineValues(NamingStyles), Hash.CombineValues(Rules.NamingRules))); } private static XElement GetUpgradedSerializationIfNecessary(XElement rootElement) { var serializationVersion = int.Parse(rootElement.Attribute("SerializationVersion")!.Value); if (serializationVersion == 4) { UpgradeSerialization_4To5(rootElement = new XElement(rootElement)); serializationVersion = 5; } // Add future version checks here. If the version is off by more than 1, these upgrades will run in sequence. // The next one should check serializationVersion == 5 and update it to 6. // It is also important to create a new roaming location in NamingStyleOptions.NamingPreferences // so that we never store the new format in an older version. Debug.Assert(s_serializationVersion == 5, "After increasing the serialization version, add an upgrade path here."); return serializationVersion == s_serializationVersion ? rootElement : XElement.Parse(DefaultNamingPreferencesString); } private static void UpgradeSerialization_4To5(XElement rootElement) { var methodElements = rootElement .Descendants() .Where(e => e.Name.LocalName == "SymbolKind" && e.Value == "Method").ToList(); foreach (var element in methodElements) { element.ReplaceWith(XElement.Parse("<MethodKind>Ordinary</MethodKind>")); } } } |