public static async Task <(Document containingDocument, SyntaxAnnotation typeAnnotation)> AddTypeToNewFileAsync( Solution solution, string containingNamespaceDisplay, string fileName, ProjectId projectId, IEnumerable <string> folders, INamedTypeSymbol newSymbol, Document hintDocument, CancellationToken cancellationToken) { var newDocumentId = DocumentId.CreateNewId(projectId, debugName: fileName); var newDocumentPath = PathUtilities.CombinePaths(PathUtilities.GetDirectoryName(hintDocument.FilePath), fileName); var solutionWithInterfaceDocument = solution.AddDocument(newDocumentId, fileName, text: "", folders: folders, filePath: newDocumentPath); var newDocument = solutionWithInterfaceDocument.GetRequiredDocument(newDocumentId); var newSemanticModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var options = new CodeGenerationOptions( contextLocation: newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), generateMethodBodies: true, options: await newDocument.GetOptionsAsync(cancellationToken).ConfigureAwait(false)); var namespaceParts = containingNamespaceDisplay.Split('.').Where(s => !string.IsNullOrEmpty(s)); var newTypeDocument = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( newDocument.Project.Solution, newSemanticModel.GetEnclosingNamespace(0, cancellationToken), newSymbol.GenerateRootNamespaceOrType(namespaceParts.ToArray()), options : options, cancellationToken : cancellationToken).ConfigureAwait(false); var formattingSerivce = newTypeDocument.GetLanguageService <INewDocumentFormattingService>(); if (formattingSerivce is not null) { newTypeDocument = await formattingSerivce.FormatNewDocumentAsync(newTypeDocument, hintDocument, cancellationToken).ConfigureAwait(false); } var syntaxRoot = await newTypeDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var typeAnnotation = new SyntaxAnnotation(); var syntaxFacts = newTypeDocument.GetRequiredLanguageService <ISyntaxFactsService>(); var declarationNode = syntaxRoot.DescendantNodes().First(syntaxFacts.IsTypeDeclaration); var annotatedRoot = syntaxRoot.ReplaceNode(declarationNode, declarationNode.WithAdditionalAnnotations(typeAnnotation)); newTypeDocument = newTypeDocument.WithSyntaxRoot(annotatedRoot); var simplified = await Simplifier.ReduceAsync(newTypeDocument, cancellationToken : cancellationToken).ConfigureAwait(false); var formattedDocument = await Formatter.FormatAsync(simplified, cancellationToken : cancellationToken).ConfigureAwait(false); return(formattedDocument, typeAnnotation); }
public static async Task <(Document containingDocument, SyntaxAnnotation typeAnnotation)> AddTypeToNewFileAsync( Solution solution, string containingNamespaceDisplay, string fileName, ProjectId projectId, IEnumerable <string> folders, INamedTypeSymbol newSymbol, Document hintDocument, CancellationToken cancellationToken) { var newDocumentId = DocumentId.CreateNewId(projectId, debugName: fileName); var newDocumentPath = PathUtilities.CombinePaths(PathUtilities.GetDirectoryName(hintDocument.FilePath), fileName); var solutionWithInterfaceDocument = solution.AddDocument(newDocumentId, fileName, text: "", folders: folders, filePath: newDocumentPath); var newDocument = solutionWithInterfaceDocument.GetRequiredDocument(newDocumentId); var newSemanticModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var context = new CodeGenerationContext( contextLocation: newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), generateMethodBodies: true); // need to remove the root namespace from the containing namespace display because it is implied // For C# this does nothing as there is no root namespace (root namespace is empty string) var generateTypeService = newDocument.GetRequiredLanguageService <IGenerateTypeService>(); var rootNamespace = generateTypeService.GetRootNamespace(newDocument.Project.CompilationOptions); var index = rootNamespace.IsEmpty() ? -1 : containingNamespaceDisplay.IndexOf(rootNamespace); // if we did find the root namespace as the first element, then we remove it // this may leave us with an extra "." character at the start, but when we split it shouldn't matter var namespaceWithoutRoot = index == 0 ? containingNamespaceDisplay.Remove(index, rootNamespace.Length) : containingNamespaceDisplay; var namespaceParts = namespaceWithoutRoot.Split('.').Where(s => !string.IsNullOrEmpty(s)); var newTypeDocument = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( newDocument.Project.Solution, newSemanticModel.GetEnclosingNamespace(0, cancellationToken), newSymbol.GenerateRootNamespaceOrType(namespaceParts.ToArray()), context, cancellationToken).ConfigureAwait(false); var newTypeFormattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(newTypeDocument, cancellationToken).ConfigureAwait(false); var formattingService = newTypeDocument.GetLanguageService <INewDocumentFormattingService>(); if (formattingService is not null) { newTypeDocument = await formattingService.FormatNewDocumentAsync(newTypeDocument, hintDocument, newTypeFormattingOptions, cancellationToken).ConfigureAwait(false); } var syntaxRoot = await newTypeDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var typeAnnotation = new SyntaxAnnotation(); var syntaxFacts = newTypeDocument.GetRequiredLanguageService <ISyntaxFactsService>(); var declarationNode = syntaxRoot.DescendantNodes().First(syntaxFacts.IsTypeDeclaration); var annotatedRoot = syntaxRoot.ReplaceNode(declarationNode, declarationNode.WithAdditionalAnnotations(typeAnnotation)); newTypeDocument = newTypeDocument.WithSyntaxRoot(annotatedRoot); var simplified = await Simplifier.ReduceAsync(newTypeDocument, cancellationToken : cancellationToken).ConfigureAwait(false); var formattedDocument = await Formatter.FormatAsync(simplified, newTypeFormattingOptions, cancellationToken).ConfigureAwait(false); return(formattedDocument, typeAnnotation); }