File: EditorConfigFileGenerator_NamingStyles.cs
Web Access
Project: ..\..\..\src\CodeStyle\Core\Analyzers\Microsoft.CodeAnalysis.CodeStyle.csproj (Microsoft.CodeAnalysis.CodeStyle)
// 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.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.NamingStyles;
 
namespace Microsoft.CodeAnalysis.Options
{
    internal static partial class EditorConfigFileGenerator
    {
        public static void AppendNamingStylePreferencesToEditorConfig(IEnumerable<NamingRule> namingRules, StringBuilder editorconfig, string? language = null)
        {
            var symbolSpecifications = namingRules.Select(x => x.SymbolSpecification).ToImmutableArray();
            var namingStyles = namingRules.Select(x => x.NamingStyle).ToImmutableArray();
            var serializedNamingRules = namingRules.Select(x => new SerializableNamingRule()
            {
                EnforcementLevel = x.EnforcementLevel,
                NamingStyleID = x.NamingStyle.ID,
                SymbolSpecificationID = x.SymbolSpecification.ID
            }).ToImmutableArray();
 
            language ??= LanguageNames.CSharp;
 
            AppendNamingStylePreferencesToEditorConfig(
                symbolSpecifications,
                namingStyles,
                serializedNamingRules,
                language,
                editorconfig);
        }
 
        public static void AppendNamingStylePreferencesToEditorConfig(NamingStylePreferences namingStylePreferences, string language, StringBuilder editorconfig)
        {
            AppendNamingStylePreferencesToEditorConfig(
                namingStylePreferences.SymbolSpecifications,
                namingStylePreferences.NamingStyles,
                namingStylePreferences.NamingRules,
                language,
                editorconfig);
        }
 
        public static void AppendNamingStylePreferencesToEditorConfig(
            ImmutableArray<SymbolSpecification> symbolSpecifications,
            ImmutableArray<NamingStyle> namingStyles,
            ImmutableArray<SerializableNamingRule> serializableNamingRules,
            string language,
            StringBuilder editorconfig)
        {
            editorconfig.AppendLine($"#### {CompilerExtensionsResources.Naming_styles} ####");
 
            var serializedNameMap = AssignNamesToNamingStyleElements(symbolSpecifications, namingStyles);
            var ruleNameMap = AssignNamesToNamingStyleRules(serializableNamingRules, serializedNameMap);
            var referencedElements = new HashSet<Guid>();
 
            editorconfig.AppendLine();
            editorconfig.AppendLine($"# {CompilerExtensionsResources.Naming_rules}");
 
            foreach (var namingRule in serializableNamingRules)
            {
                referencedElements.Add(namingRule.SymbolSpecificationID);
                referencedElements.Add(namingRule.NamingStyleID);
 
                editorconfig.AppendLine();
                editorconfig.AppendLine($"dotnet_naming_rule.{ruleNameMap[namingRule]}.severity = {namingRule.EnforcementLevel.ToNotificationOption(defaultSeverity: DiagnosticSeverity.Hidden).ToEditorConfigString()}");
                editorconfig.AppendLine($"dotnet_naming_rule.{ruleNameMap[namingRule]}.symbols = {serializedNameMap[namingRule.SymbolSpecificationID]}");
                editorconfig.AppendLine($"dotnet_naming_rule.{ruleNameMap[namingRule]}.style = {serializedNameMap[namingRule.NamingStyleID]}");
            }
 
            editorconfig.AppendLine();
            editorconfig.AppendLine($"# {CompilerExtensionsResources.Symbol_specifications}");
 
            foreach (var symbolSpecification in symbolSpecifications)
            {
                if (!referencedElements.Contains(symbolSpecification.ID))
                {
                    continue;
                }
 
                editorconfig.AppendLine();
                editorconfig.AppendLine($"dotnet_naming_symbols.{serializedNameMap[symbolSpecification.ID]}.applicable_kinds = {symbolSpecification.ApplicableSymbolKindList.ToEditorConfigString()}");
                editorconfig.AppendLine($"dotnet_naming_symbols.{serializedNameMap[symbolSpecification.ID]}.applicable_accessibilities = {symbolSpecification.ApplicableAccessibilityList.ToEditorConfigString(language)}");
                editorconfig.AppendLine($"dotnet_naming_symbols.{serializedNameMap[symbolSpecification.ID]}.required_modifiers = {symbolSpecification.RequiredModifierList.ToEditorConfigString(language)}");
            }
 
            editorconfig.AppendLine();
            editorconfig.AppendLine($"# {CompilerExtensionsResources.Naming_styles}");
 
            foreach (var namingStyle in namingStyles)
            {
                if (!referencedElements.Contains(namingStyle.ID))
                {
                    continue;
                }
 
                editorconfig.AppendLine();
                editorconfig.AppendLine($"dotnet_naming_style.{serializedNameMap[namingStyle.ID]}.required_prefix = {namingStyle.Prefix}");
                editorconfig.AppendLine($"dotnet_naming_style.{serializedNameMap[namingStyle.ID]}.required_suffix = {namingStyle.Suffix}");
                editorconfig.AppendLine($"dotnet_naming_style.{serializedNameMap[namingStyle.ID]}.word_separator = {namingStyle.WordSeparator}");
                editorconfig.AppendLine($"dotnet_naming_style.{serializedNameMap[namingStyle.ID]}.capitalization = {namingStyle.CapitalizationScheme.ToEditorConfigString()}");
            }
        }
 
        private static ImmutableDictionary<Guid, string> AssignNamesToNamingStyleElements(
            ImmutableArray<SymbolSpecification> symbolSpecifications,
            ImmutableArray<NamingStyle> namingStyles)
        {
            var symbolSpecificationNames = new HashSet<string>();
            var builder = ImmutableDictionary.CreateBuilder<Guid, string>();
            foreach (var symbolSpecification in symbolSpecifications)
            {
                var name = ToSnakeCaseName(symbolSpecification.Name);
                if (!symbolSpecificationNames.Add(name))
                {
                    name = symbolSpecification.ID.ToString("n");
                }
 
                builder.Add(symbolSpecification.ID, name);
            }
 
            var namingStyleNames = new HashSet<string>();
            foreach (var namingStyle in namingStyles)
            {
                var name = ToSnakeCaseName(namingStyle.Name);
                if (!namingStyleNames.Add(name))
                {
                    name = namingStyle.ID.ToString("n");
                }
 
                if (!builder.TryGetKey(namingStyle.ID, out _))
                {
                    builder.Add(namingStyle.ID, name);
                }
            }
 
            return builder.ToImmutable();
 
            static string ToSnakeCaseName(string name)
            {
                return new string(name
                    .Select(ch =>
                    {
                        if (char.IsLetterOrDigit(ch))
                        {
                            return char.ToLowerInvariant(ch);
                        }
                        else
                        {
                            return '_';
                        }
                    })
                    .ToArray());
            }
        }
 
        private static ImmutableDictionary<SerializableNamingRule, string> AssignNamesToNamingStyleRules(ImmutableArray<SerializableNamingRule> namingRules, ImmutableDictionary<Guid, string> serializedNameMap)
        {
            var builder = ImmutableDictionary.CreateBuilder<SerializableNamingRule, string>();
            foreach (var rule in namingRules)
            {
                builder.Add(rule, $"{serializedNameMap[rule.SymbolSpecificationID]}_should_be_{serializedNameMap[rule.NamingStyleID]}");
            }
 
            return builder.ToImmutable();
        }
    }
}