예제 #1
0
 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)