| File: src\roslyn\src\Workspaces\SharedUtilitiesAndExtensions\Workspace\CSharp\CodeGeneration\NamespaceGenerator.cs | Web Access |
| Project: src\roslyn\src\CodeStyle\CSharp\CodeFixes\Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes) |
// 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.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeGeneration.CodeGenerationHelpers; using static Microsoft.CodeAnalysis.CSharp.CodeGeneration.CSharpCodeGenerationHelpers; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; using static SyntaxFactory; internal static class NamespaceGenerator { public static BaseNamespaceDeclarationSyntax AddNamespaceTo( ICodeGenerationService service, BaseNamespaceDeclarationSyntax destination, INamespaceSymbol @namespace, CSharpCodeGenerationContextInfo info, IList<bool>? availableIndices, CancellationToken cancellationToken) { var declaration = GenerateNamespaceDeclaration( service, @namespace, CodeGenerationDestination.Namespace, info, cancellationToken); if (declaration is not BaseNamespaceDeclarationSyntax namespaceDeclaration) throw new ArgumentException(WorkspaceExtensionsResources.Namespace_can_not_be_added_in_this_destination); var members = Insert(destination.Members, namespaceDeclaration, info, availableIndices); return destination.WithMembers(members); } public static CompilationUnitSyntax AddNamespaceTo( ICodeGenerationService service, CompilationUnitSyntax destination, INamespaceSymbol @namespace, CSharpCodeGenerationContextInfo info, IList<bool>? availableIndices, CancellationToken cancellationToken) { var declaration = GenerateNamespaceDeclaration( service, @namespace, CodeGenerationDestination.CompilationUnit, info, cancellationToken); if (declaration is not BaseNamespaceDeclarationSyntax namespaceDeclaration) throw new ArgumentException(WorkspaceExtensionsResources.Namespace_can_not_be_added_in_this_destination); var members = Insert(destination.Members, namespaceDeclaration, info, availableIndices); return destination.WithMembers(members); } internal static SyntaxNode GenerateNamespaceDeclaration( ICodeGenerationService service, INamespaceSymbol @namespace, CodeGenerationDestination destination, CSharpCodeGenerationContextInfo info, CancellationToken cancellationToken) { GetNameAndInnermostNamespace(@namespace, info, out var name, out var innermostNamespace); var declaration = GetDeclarationSyntaxWithoutMembers( @namespace, innermostNamespace, name, destination, info); declaration = info.Context.GenerateMembers ? service.AddMembers(declaration, innermostNamespace.GetMembers(), info, cancellationToken) : declaration; return AddFormatterAndCodeGeneratorAnnotationsTo(declaration); } public static SyntaxNode UpdateCompilationUnitOrNamespaceDeclaration( ICodeGenerationService service, SyntaxNode declaration, IList<ISymbol> newMembers, CSharpCodeGenerationContextInfo info, CancellationToken cancellationToken) { declaration = RemoveAllMembers(declaration); declaration = service.AddMembers(declaration, newMembers, info, cancellationToken); return AddFormatterAndCodeGeneratorAnnotationsTo(declaration); } private static SyntaxNode GenerateNamespaceDeclarationWorker( string name, INamespaceSymbol innermostNamespace, CodeGenerationDestination destination, CSharpCodeGenerationContextInfo info) { var usings = GenerateUsingDirectives(innermostNamespace); // If they're just generating the empty namespace then make that into compilation unit. if (name == string.Empty) return CompilationUnit().WithUsings(usings); if (destination == CodeGenerationDestination.CompilationUnit && info.Options.NamespaceDeclarations.Value == NamespaceDeclarationPreference.FileScoped && info.LanguageVersion >= LanguageVersion.CSharp10) { return FileScopedNamespaceDeclaration(ParseName(name)).WithUsings(usings); } return NamespaceDeclaration(ParseName(name)).WithUsings(usings); } private static SyntaxNode GetDeclarationSyntaxWithoutMembers( INamespaceSymbol @namespace, INamespaceSymbol innermostNamespace, string name, CodeGenerationDestination destination, CSharpCodeGenerationContextInfo info) { var reusableSyntax = GetReuseableSyntaxNodeForSymbol<SyntaxNode>(@namespace, info); return reusableSyntax == null ? GenerateNamespaceDeclarationWorker(name, innermostNamespace, destination, info) : RemoveAllMembers(reusableSyntax); } private static SyntaxNode RemoveAllMembers(SyntaxNode declaration) => declaration switch { CompilationUnitSyntax compilationUnit => compilationUnit.WithMembers(default), BaseNamespaceDeclarationSyntax namespaceDeclaration => namespaceDeclaration.WithMembers(default), _ => declaration, }; private static SyntaxList<UsingDirectiveSyntax> GenerateUsingDirectives(INamespaceSymbol innermostNamespace) { var usingDirectives = CodeGenerationNamespaceInfo.GetImports(innermostNamespace) .Select(GenerateUsingDirective) .WhereNotNull() .ToList(); return [.. usingDirectives]; } private static UsingDirectiveSyntax? GenerateUsingDirective(ISymbol symbol) { if (symbol is IAliasSymbol alias) { var name = GenerateName(alias.Target); if (name != null) { return UsingDirective( NameEquals(alias.Name.ToIdentifierName()), name); } } else if (symbol is INamespaceOrTypeSymbol namespaceOrType) { var name = GenerateName(namespaceOrType); if (name != null) { return UsingDirective(name); } } return null; } private static NameSyntax GenerateName(INamespaceOrTypeSymbol symbol) { return symbol is ITypeSymbol type ? type.GenerateNameSyntax() : ParseName(symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } }