File: CodeModel\CSharpCodeModelService.NodeNameGenerator.cs
Web Access
Project: src\src\VisualStudio\CSharp\Impl\Microsoft.VisualStudio.LanguageServices.CSharp_ie1ac2c5_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices.CSharp)
// 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.
 
#nullable disable
 
using System;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
 
namespace Microsoft.VisualStudio.LanguageServices.CSharp.CodeModel;
 
internal sealed partial class CSharpCodeModelService
{
    protected override AbstractNodeNameGenerator CreateNodeNameGenerator()
        => new NodeNameGenerator();
 
    private sealed class NodeNameGenerator : AbstractNodeNameGenerator
    {
        protected override bool IsNameableNode(SyntaxNode node)
            => CSharpCodeModelService.IsNameableNode(node);
 
        private static void AppendName(StringBuilder builder, NameSyntax name)
        {
            if (name is QualifiedNameSyntax qualifiedName)
                AppendName(builder, qualifiedName.Left);
 
            switch (name.Kind())
            {
                case SyntaxKind.IdentifierName:
                    AppendDotIfNeeded(builder);
                    builder.Append(((IdentifierNameSyntax)name).Identifier.ValueText);
                    break;
 
                case SyntaxKind.GenericName:
                    var genericName = (GenericNameSyntax)name;
                    AppendDotIfNeeded(builder);
                    builder.Append(genericName.Identifier.ValueText);
                    AppendArity(builder, genericName.Arity);
                    break;
 
                case SyntaxKind.AliasQualifiedName:
                    var aliasQualifiedName = (AliasQualifiedNameSyntax)name;
                    AppendName(builder, aliasQualifiedName.Alias);
                    builder.Append("::");
                    AppendName(builder, aliasQualifiedName.Name);
                    break;
 
                case SyntaxKind.QualifiedName:
                    AppendName(builder, ((QualifiedNameSyntax)name).Right);
                    break;
            }
        }
 
        private static void AppendTypeName(StringBuilder builder, TypeSyntax type)
        {
            if (type is NameSyntax name)
            {
                AppendName(builder, name);
            }
            else
            {
                switch (type.Kind())
                {
                    case SyntaxKind.PredefinedType:
                        builder.Append(((PredefinedTypeSyntax)type).Keyword.ValueText);
                        break;
 
                    case SyntaxKind.ArrayType:
                        var arrayType = (ArrayTypeSyntax)type;
                        AppendTypeName(builder, arrayType.ElementType);
 
                        var specifiers = arrayType.RankSpecifiers;
                        for (var i = 0; i < specifiers.Count; i++)
                        {
                            builder.Append('[');
 
                            var specifier = specifiers[i];
                            if (specifier.Rank > 1)
                            {
                                builder.Append(',', specifier.Rank - 1);
                            }
 
                            builder.Append(']');
                        }
 
                        break;
 
                    case SyntaxKind.PointerType:
                        AppendTypeName(builder, ((PointerTypeSyntax)type).ElementType);
                        builder.Append('*');
                        break;
 
                    case SyntaxKind.NullableType:
                        AppendTypeName(builder, ((NullableTypeSyntax)type).ElementType);
                        builder.Append('?');
                        break;
                }
            }
        }
 
        private static void AppendParameterList(StringBuilder builder, BaseParameterListSyntax parameterList)
        {
            builder.Append(parameterList is BracketedParameterListSyntax ? '[' : '(');
 
            var firstSeen = false;
 
            foreach (var parameter in parameterList.Parameters)
            {
                if (firstSeen)
                {
                    builder.Append(',');
                }
 
                if (parameter.Modifiers.Any(SyntaxKind.RefKeyword))
                {
                    builder.Append("ref ");
                }
                else if (parameter.Modifiers.Any(SyntaxKind.OutKeyword))
                {
                    builder.Append("out ");
                }
                else if (parameter.Modifiers.Any(SyntaxKind.ParamsKeyword))
                {
                    builder.Append("params ");
                }
 
                AppendTypeName(builder, parameter.Type);
 
                firstSeen = true;
            }
 
            builder.Append(parameterList is BracketedParameterListSyntax ? ']' : ')');
        }
 
        private static void AppendOperatorName(StringBuilder builder, SyntaxKind kind)
        {
            var name = "#op_" + kind.ToString();
            if (name.EndsWith("Keyword", StringComparison.Ordinal))
            {
                name = name[..^7];
            }
            else if (name.EndsWith("Token", StringComparison.Ordinal))
            {
                name = name[..^5];
            }
 
            builder.Append(name);
        }
 
        protected override void AppendNodeName(StringBuilder builder, SyntaxNode node)
        {
            Debug.Assert(node != null);
            Debug.Assert(IsNameableNode(node));
 
            AppendDotIfNeeded(builder);
 
            switch (node.Kind())
            {
                case SyntaxKind.NamespaceDeclaration:
                case SyntaxKind.FileScopedNamespaceDeclaration:
                    var namespaceDeclaration = (BaseNamespaceDeclarationSyntax)node;
                    AppendName(builder, namespaceDeclaration.Name);
                    break;
 
                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.RecordDeclaration:
                case SyntaxKind.StructDeclaration:
                case SyntaxKind.RecordStructDeclaration:
                case SyntaxKind.InterfaceDeclaration:
                    var typeDeclaration = (TypeDeclarationSyntax)node;
                    builder.Append(typeDeclaration.Identifier.ValueText);
                    AppendArity(builder, typeDeclaration.Arity);
                    break;
 
                case SyntaxKind.EnumDeclaration:
                    var enumDeclaration = (EnumDeclarationSyntax)node;
                    builder.Append(enumDeclaration.Identifier.ValueText);
                    break;
 
                case SyntaxKind.DelegateDeclaration:
                    var delegateDeclaration = (DelegateDeclarationSyntax)node;
                    builder.Append(delegateDeclaration.Identifier.ValueText);
                    AppendArity(builder, delegateDeclaration.Arity);
                    break;
 
                case SyntaxKind.EnumMemberDeclaration:
                    var enumMemberDeclaration = (EnumMemberDeclarationSyntax)node;
                    builder.Append(enumMemberDeclaration.Identifier.ValueText);
                    break;
 
                case SyntaxKind.VariableDeclarator:
                    var variableDeclarator = (VariableDeclaratorSyntax)node;
                    builder.Append(variableDeclarator.Identifier.ValueText);
                    break;
 
                case SyntaxKind.MethodDeclaration:
                    var methodDeclaration = (MethodDeclarationSyntax)node;
                    builder.Append(methodDeclaration.Identifier.ValueText);
                    AppendArity(builder, methodDeclaration.Arity);
                    AppendParameterList(builder, methodDeclaration.ParameterList);
                    break;
 
                case SyntaxKind.OperatorDeclaration:
                    var operatorDeclaration = (OperatorDeclarationSyntax)node;
                    AppendOperatorName(builder, operatorDeclaration.OperatorToken.Kind());
                    AppendParameterList(builder, operatorDeclaration.ParameterList);
                    break;
 
                case SyntaxKind.ConversionOperatorDeclaration:
                    var conversionOperatorDeclaration = (ConversionOperatorDeclarationSyntax)node;
                    AppendOperatorName(builder, conversionOperatorDeclaration.ImplicitOrExplicitKeyword.Kind());
                    builder.Append('_');
                    AppendTypeName(builder, conversionOperatorDeclaration.Type);
                    AppendParameterList(builder, conversionOperatorDeclaration.ParameterList);
                    break;
 
                case SyntaxKind.ConstructorDeclaration:
                    var constructorDeclaration = (ConstructorDeclarationSyntax)node;
                    builder.Append(constructorDeclaration.Modifiers.Any(SyntaxKind.StaticKeyword) ? "#sctor" : "#ctor");
                    AppendParameterList(builder, constructorDeclaration.ParameterList);
                    break;
 
                case SyntaxKind.DestructorDeclaration:
                    builder.Append("#dtor()");
                    break;
 
                case SyntaxKind.IndexerDeclaration:
                    var indexerDeclaration = (IndexerDeclarationSyntax)node;
                    builder.Append("#this");
                    AppendParameterList(builder, indexerDeclaration.ParameterList);
                    break;
 
                case SyntaxKind.PropertyDeclaration:
                    var propertyDeclaration = (PropertyDeclarationSyntax)node;
                    builder.Append(propertyDeclaration.Identifier.ValueText);
                    break;
 
                case SyntaxKind.EventDeclaration:
                    var eventDeclaration = (EventDeclarationSyntax)node;
                    builder.Append(eventDeclaration.Identifier.ValueText);
                    break;
            }
        }
    }
}