public NamingRule GetRule(NamingStylePreferences info) { return(new NamingRule( info.GetSymbolSpecification(SymbolSpecificationID), info.GetNamingStyle(NamingStyleID), EnforcementLevel)); }
public static NamingStylePreferences ParseDictionary(IReadOnlyDictionary <string, string> allRawConventions) { var symbolSpecifications = ArrayBuilder <SymbolSpecification> .GetInstance(); var namingStyles = ArrayBuilder <NamingStyle> .GetInstance(); var namingRules = ArrayBuilder <SerializableNamingRule> .GetInstance(); var ruleNames = new Dictionary <(Guid symbolSpecificationID, Guid namingStyleID, ReportDiagnostic enforcementLevel), string>(); var trimmedDictionary = TrimDictionary(allRawConventions); foreach (var namingRuleTitle in GetRuleTitles(trimmedDictionary)) { if (TryGetSymbolSpec(namingRuleTitle, trimmedDictionary, out var symbolSpec) && TryGetNamingStyleData(namingRuleTitle, trimmedDictionary, out var namingStyle) && TryGetSerializableNamingRule(namingRuleTitle, symbolSpec, namingStyle, trimmedDictionary, out var serializableNamingRule)) { symbolSpecifications.Add(symbolSpec); namingStyles.Add(namingStyle); namingRules.Add(serializableNamingRule); var ruleKey = (serializableNamingRule.SymbolSpecificationID, serializableNamingRule.NamingStyleID, serializableNamingRule.EnforcementLevel); if (ruleNames.TryGetValue(ruleKey, out var existingName)) { // For duplicated rules, only preserve the one with a name that would sort first var ordinalIgnoreCaseOrdering = StringComparer.OrdinalIgnoreCase.Compare(namingRuleTitle, existingName); if (ordinalIgnoreCaseOrdering > 0) { continue; } else if (ordinalIgnoreCaseOrdering == 0) { var ordinalOrdering = StringComparer.Ordinal.Compare(namingRuleTitle, existingName); if (ordinalOrdering > 0) { continue; } } } ruleNames[ruleKey] = namingRuleTitle; } } var preferences = new NamingStylePreferences( symbolSpecifications.ToImmutableAndFree(), namingStyles.ToImmutableAndFree(), namingRules.ToImmutableAndFree()); // Deterministically order the naming style rules according to the symbols matched by the rule. The rules // are applied in order; later rules are only relevant if earlier rules fail to specify an order. // // 1. If the modifiers required by rule 'x' are a strict superset of the modifiers required by rule 'y', // then rule 'x' is evaluated before rule 'y'. // 2. If the accessibilities allowed by rule 'x' are a strict subset of the accessibilities allowed by rule // 'y', then rule 'x' is evaluated before rule 'y'. // 3. If the set of symbols matched by rule 'x' are a strict subset of the symbols matched by rule 'y', then // rule 'x' is evaluated before rule 'y'. // // If none of the above produces an order between two rules 'x' and 'y', then the rules are ordered // according to their name, first by OrdinalIgnoreCase and finally by Ordinal. // // Historical note: rules used to be ordered by their position in the .editorconfig file. However, this // relied on an implementation detail of the .editorconfig parser which is not preserved by all // implementations. In a review of .editorconfig files in the wild, the rules applied in this section were // the closest deterministic match for the files without having any reliance on order. For any pair of rules // which a user has trouble ordering, the intersection of the two rules can be broken out into a new rule // will always match earlier than the broader rules it was derived from. var orderedRules = preferences.Rules.NamingRules .OrderBy(rule => rule, NamingRuleModifierListComparer.Instance) .ThenBy(rule => rule, NamingRuleAccessibilityListComparer.Instance) .ThenBy(rule => rule, NamingRuleSymbolListComparer.Instance) .ThenBy(rule => ruleNames[(rule.SymbolSpecification.ID, rule.NamingStyle.ID, rule.EnforcementLevel)], StringComparer.OrdinalIgnoreCase)