async Task <Document> CreateStunt(IEnumerable <INamedTypeSymbol> symbols, SyntaxGenerator generator, StuntGenerator stunts, CancellationToken cancellationToken) { var(name, syntax) = stunts.CreateStunt(symbols, generator); // TODO: F# var extension = document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb"; var file = Path.Combine(Path.GetDirectoryName(document.Project.FilePath), naming.Namespace, name + extension); var folders = naming.Namespace.Split('.'); var stuntDoc = document.Project.Documents.FirstOrDefault(d => d.Name == Path.GetFileName(file) && d.Folders.SequenceEqual(folders)); if (stuntDoc == null) { if (document.Project.Solution.Workspace is AdhocWorkspace workspace) { stuntDoc = workspace.AddDocument(DocumentInfo .Create( DocumentId.CreateNewId(document.Project.Id), Path.GetFileName(file), folders: naming.Namespace.Split('.'), filePath: file)) .WithSyntaxRoot(syntax); } else { stuntDoc = document.Project.AddDocument( Path.GetFileName(file), syntax, folders, file); } } else { stuntDoc = stuntDoc.WithSyntaxRoot(syntax); } stuntDoc = await stunts.ApplyProcessors(stuntDoc, cancellationToken).ConfigureAwait(false); // This is somewhat expensive, but since we're adding it to the user' solution, we might // as well make it look great ;) stuntDoc = await Simplifier.ReduceAsync(stuntDoc).ConfigureAwait(false); if (document.Project.Language != LanguageNames.VisualBasic) { stuntDoc = await Formatter.FormatAsync(stuntDoc, Formatter.Annotation).ConfigureAwait(false); } syntax = await stuntDoc.GetSyntaxRootAsync().ConfigureAwait(false); return(stuntDoc.WithSyntaxRoot(syntax)); }
async Task <Document> CreateStunt(IEnumerable <INamedTypeSymbol> symbols, SyntaxGenerator generator, StuntGenerator stunts, CancellationToken cancellationToken) { var(name, syntax) = stunts.CreateStunt(symbols, generator); // TODO: F# var extension = document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb"; // The logical folder is always the split namespace, since generated code is // expected to be added as hidden linked files. var folders = naming.Namespace.Split('.'); if (!diagnostic.Properties.TryGetValue("Location", out var file) || string.IsNullOrEmpty(file)) { file = Path.Combine(Path.GetDirectoryName(document.Project.FilePath), Path.Combine(folders), name + extension); } var stuntDoc = document.Project.Documents.FirstOrDefault(d => d.Name == Path.GetFileName(file) && d.Folders.SequenceEqual(folders)); // NOTE: the environment variable tells us we're being run with AutoCodeFix enabled and // active, meaning we should generate files into the intermediate output path instead. var autoCodeFixEnabled = bool.TryParse(Environment.GetEnvironmentVariable("AutoCodeFix"), out var value) && value; // Update target file path if running from build-time codegen. if (stuntDoc == null && autoCodeFixEnabled) { // Get configured generator options to build the final path if (document.Project.AnalyzerOptions.GetCodeFixSettings().TryGetValue("IntermediateOutputPath", out var intermediateOutputPath)) { file = Path.Combine(intermediateOutputPath, Path.Combine(folders), name + ".g" + extension); } } if (stuntDoc == null) { if (document.Project.Solution.Workspace is AdhocWorkspace workspace) { stuntDoc = workspace.AddDocument(DocumentInfo .Create( DocumentId.CreateNewId(document.Project.Id), Path.GetFileName(file), folders: folders, filePath: file)) .WithSyntaxRoot(syntax); } else { // When running the generator from design-time, ensure the folder exists. // This is necessary since we link files into the Mocks/Stunts folder, // which becomes a "linked" folder itself, and when adding the document, // VS fails to so. if (!autoCodeFixEnabled) { var directory = Path.Combine(Path.GetDirectoryName(document.Project.FilePath), Path.Combine(folders)); Directory.CreateDirectory(directory); } stuntDoc = document.Project.AddDocument( Path.GetFileName(file), syntax, folders, file); } } else { stuntDoc = stuntDoc.WithSyntaxRoot(syntax); } stuntDoc = await stunts.ApplyProcessors(stuntDoc, cancellationToken).ConfigureAwait(false); // This is somewhat expensive, but with the formatting, the code doesn't even compile :/ stuntDoc = await Simplifier.ReduceAsync(stuntDoc).ConfigureAwait(false); if (document.Project.Language != LanguageNames.VisualBasic) { stuntDoc = await Formatter.FormatAsync(stuntDoc, Formatter.Annotation).ConfigureAwait(false); } syntax = await stuntDoc.GetSyntaxRootAsync().ConfigureAwait(false); stuntDoc = stuntDoc.WithSyntaxRoot(syntax); return(stuntDoc); }