".Replace("\r\n", "\n").Replace("\n", Environment.NewLine); // normalize regardless of git checkout policy /// <summary> /// Produces a new document in response to any code generation attributes found in the specified document. /// </summary> /// <param name="compilation">The compilation to which the document belongs.</param> /// <param name="inputDocument">The document to scan for generator attributes.</param> /// <param name="projectDirectory">The path of the <c>.csproj</c> project file.</param> /// <param name="assemblyLoader">A function that can load an assembly with the given name.</param> /// <param name="progress">Reports warnings and errors in code generation.</param> /// <returns>A task whose result is the generated document.</returns> public static async Task <SyntaxTree> TransformAsync( CSharpCompilation compilation, SyntaxTree inputDocument, string projectDirectory, Func <AssemblyName, Assembly> assemblyLoader, IProgress <Diagnostic> progress) { Requires.NotNull(compilation, nameof(compilation)); Requires.NotNull(inputDocument, nameof(inputDocument)); Requires.NotNull(assemblyLoader, nameof(assemblyLoader)); var inputSemanticModel = compilation.GetSemanticModel(inputDocument); var inputCompilationUnit = inputDocument.GetCompilationUnitRoot(); var emittedExterns = inputCompilationUnit .Externs .Select(x => x.WithoutTrivia()) .ToImmutableArray(); var emittedUsings = inputCompilationUnit .Usings .Select(x => x.WithoutTrivia()) .ToImmutableArray(); var emittedAttributeLists = ImmutableArray <AttributeListSyntax> .Empty; var emittedMembers = ImmutableArray <MemberDeclarationSyntax> .Empty; var memberNodes = inputDocument .GetRoot() .DescendantNodesAndSelf(n => n is CompilationUnitSyntax || n is NamespaceDeclarationSyntax || n is TypeDeclarationSyntax) .OfType <CSharpSyntaxNode>(); foreach (var memberNode in memberNodes) { var attributeData = GetAttributeData(compilation, inputSemanticModel, memberNode); var generators = FindCodeGenerators(attributeData, assemblyLoader); foreach (var generator in generators) { var context = new TransformationContext(memberNode, inputSemanticModel, compilation, projectDirectory, emittedUsings, emittedExterns); var richGenerator = generator as IRichCodeGenerator ?? new EnrichingCodeGeneratorProxy(generator); var emitted = await richGenerator.GenerateRichAsync(context, progress, CancellationToken.None); emittedExterns = emittedExterns.AddRange(emitted.Externs); emittedUsings = emittedUsings.AddRange(emitted.Usings); emittedAttributeLists = emittedAttributeLists.AddRange(emitted.AttributeLists); emittedMembers = emittedMembers.AddRange(emitted.Members); } } var compilationUnit = SyntaxFactory.CompilationUnit( SyntaxFactory.List(emittedExterns), SyntaxFactory.List(emittedUsings), SyntaxFactory.List(emittedAttributeLists), SyntaxFactory.List(emittedMembers)) .WithLeadingTrivia(SyntaxFactory.Comment(GeneratedByAToolPreamble)) .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) .NormalizeWhitespace(); return(compilationUnit.SyntaxTree); }
".Replace("\r\n", "\n").Replace("\n", Environment.NewLine); // normalize regardless of git checkout policy /// <summary> /// Produces a new document in response to any code generation attributes found in the specified document. /// </summary> /// <param name="compilation">The compilation to which the document belongs.</param> /// <param name="inputDocument">The document to scan for generator attributes.</param> /// <param name="assemblyLoader">A function that can load an assembly with the given name.</param> /// <param name="progress">Reports warnings and errors in code generation.</param> /// <returns>A task whose result is the generated document.</returns> public static async Task <SyntaxTree> TransformAsync(CSharpCompilation compilation, SyntaxTree inputDocument, Func <AssemblyName, Assembly> assemblyLoader, IProgress <Diagnostic> progress) { Requires.NotNull(compilation, nameof(compilation)); Requires.NotNull(inputDocument, nameof(inputDocument)); Requires.NotNull(assemblyLoader, nameof(assemblyLoader)); var inputSemanticModel = compilation.GetSemanticModel(inputDocument); var inputSyntaxTree = inputSemanticModel.SyntaxTree; var inputFileLevelUsingDirectives = inputSyntaxTree.GetRoot().ChildNodes().OfType <UsingDirectiveSyntax>(); var memberNodes = from syntax in inputSyntaxTree.GetRoot().DescendantNodes(n => n is CompilationUnitSyntax || n is NamespaceDeclarationSyntax || n is TypeDeclarationSyntax).OfType <MemberDeclarationSyntax>() select syntax; var emittedMembers = SyntaxFactory.List <MemberDeclarationSyntax>(); foreach (var memberNode in memberNodes) { var generators = FindCodeGenerators(inputSemanticModel, memberNode, assemblyLoader); foreach (var generator in generators) { var context = new TransformationContext(memberNode, inputSemanticModel, compilation); var generatedTypes = await generator.GenerateAsync(context, progress, CancellationToken.None); // Figure out ancestry for the generated type, including nesting types and namespaces. foreach (var ancestor in memberNode.Ancestors()) { var ancestorNamespace = ancestor as NamespaceDeclarationSyntax; var nestingClass = ancestor as ClassDeclarationSyntax; var nestingStruct = ancestor as StructDeclarationSyntax; if (ancestorNamespace != null) { generatedTypes = SyntaxFactory.SingletonList <MemberDeclarationSyntax>( ancestorNamespace .WithMembers(generatedTypes) .WithLeadingTrivia(SyntaxFactory.TriviaList()) .WithTrailingTrivia(SyntaxFactory.TriviaList())); } else if (nestingClass != null) { generatedTypes = SyntaxFactory.SingletonList <MemberDeclarationSyntax>( nestingClass .WithMembers(generatedTypes) .WithLeadingTrivia(SyntaxFactory.TriviaList()) .WithTrailingTrivia(SyntaxFactory.TriviaList())); } else if (nestingStruct != null) { generatedTypes = SyntaxFactory.SingletonList <MemberDeclarationSyntax>( nestingStruct .WithMembers(generatedTypes) .WithLeadingTrivia(SyntaxFactory.TriviaList()) .WithTrailingTrivia(SyntaxFactory.TriviaList())); } } emittedMembers = emittedMembers.AddRange(generatedTypes); } } // By default, retain all the using directives that came from the input file. var resultFileLevelUsingDirectives = SyntaxFactory.List(inputFileLevelUsingDirectives); var compilationUnit = SyntaxFactory.CompilationUnit() .WithUsings(resultFileLevelUsingDirectives) .WithMembers(emittedMembers) .WithLeadingTrivia(SyntaxFactory.Comment(GeneratedByAToolPreamble)) .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) .NormalizeWhitespace(); return(compilationUnit.SyntaxTree); }