public IMetadataProjectReference CompileProject( ICompilationProject project, ILibraryKey target, Func<ILibraryExport> referenceResolver, Func<IList<ResourceDescriptor>> resourcesResolver) { var export = referenceResolver(); if (export == null) { return null; } var incomingReferences = export.MetadataReferences; var incomingSourceReferences = export.SourceReferences; var compilationContext = _compiler.CompileProject( project, target, incomingReferences, incomingSourceReferences, resourcesResolver); if (compilationContext == null) { return null; } // Project reference return new FSharpProjectReference(compilationContext); }
public IList<ResourceDescriptor> GetResources(ICompilationProject project) { string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory); return project .Files.ResourceFiles .Where(res => IsResxResourceFile(res.Key)) .Select(resourceFile => { string resourceName; string rootNamespace; if (string.IsNullOrEmpty(resourceFile.Value)) { // No logical name, so use the file name resourceName = ResourcePathUtility.GetResourceName(root, resourceFile.Key); rootNamespace = project.Name; } else { resourceName = CreateCSharpManifestResourceName.EnsureResourceExtension(resourceFile.Value, resourceFile.Key); rootNamespace = null; } return new ResourceDescriptor() { Name = CreateCSharpManifestResourceName.CreateManifestName(resourceName, rootNamespace), StreamFactory = () => GetResourceStream(resourceFile.Key), }; }) .ToList(); }
public CompiledProjectMetadataReference(ICompilationProject project, string assemblyPath, string pdbPath) { Name = project.Name; ProjectPath = project.ProjectFilePath; Path = assemblyPath; _project = project; _assemblyPath = assemblyPath; _pdbPath = pdbPath; }
public IMetadataProjectReference CompileProject( ICompilationProject project, ILibraryKey target, Func<ILibraryExport> referenceResolver, Func<IList<ResourceDescriptor>> resourcesResolver) { // The target framework and configuration are assumed to be correct // in the design time process var task = _compiler.Compile(project.ProjectDirectory, target); return new DesignTimeProjectReference(project, task.Result); }
public IMetadataProjectReference CompileProject( ICompilationProject project, ILibraryKey target, Func <ILibraryExport> referenceResolver, Func <IList <ResourceDescriptor> > resourcesResolver) { // The target framework and configuration are assumed to be correct // in the design time process var task = _compiler.Compile(project.ProjectDirectory, target); return(new DesignTimeProjectReference(project, task.Result)); }
private IList <SyntaxTree> GetSyntaxTrees(ICompilationProject project, IEnumerable <string> sourceFiles, IEnumerable <ISourceReference> sourceReferences, CSharpParseOptions parseOptions, bool isMainAspect) { var trees = new List <SyntaxTree>(); var dirs = new HashSet <string>(); if (isMainAspect) { dirs.Add(project.ProjectDirectory); } foreach (var sourcePath in sourceFiles) { _watcher.WatchFile(sourcePath); var syntaxTree = CreateSyntaxTree(sourcePath, parseOptions); trees.Add(syntaxTree); } foreach (var sourceFileReference in sourceReferences.OfType <ISourceFileReference>()) { var sourcePath = sourceFileReference.Path; _watcher.WatchFile(sourcePath); var syntaxTree = CreateSyntaxTree(sourcePath, parseOptions); trees.Add(syntaxTree); } // Watch all directories var ctx = _cacheContextAccessor.Current; foreach (var d in dirs) { ctx?.Monitor(new FileWriteTimeCacheDependency(d)); // TODO: Make the file watcher hand out cache dependencies as well _watcher.WatchDirectory(d, ".cs"); } return(trees); }
internal CompilationContext( ICompilationProject project, FSharpProjectInfo fsproj, bool success, IEnumerable<FSharpCompilationMessage> messages, byte[] assembly, byte[] pdb, byte[] xml) { _project = project; _fsproj = fsproj; _success = success; _messages = messages.ToList(); _assembly = assembly; _pdb = pdb; _xml = xml; }
internal CompilationContext( ICompilationProject project, FSharpProjectInfo fsproj, bool success, IEnumerable <FSharpCompilationMessage> messages, byte[] assembly, byte[] pdb, byte[] xml) { _project = project; _fsproj = fsproj; _success = success; _messages = messages.ToList(); _assembly = assembly; _pdb = pdb; _xml = xml; }
public IList <ResourceDescriptor> GetResources(ICompilationProject project) { return(_providers .SelectMany(provider => provider.GetResources(project)) .ToList()); }
public DesignTimeProjectReference(ICompilationProject project, CompileResponse response) { _project = project; _response = response; }
private static CSharpCompilation ApplyVersionInfo(CSharpCompilation compilation, ICompilationProject project, CSharpParseOptions parseOptions) { const string assemblyFileVersionName = "System.Reflection.AssemblyFileVersionAttribute"; const string assemblyVersionName = "System.Reflection.AssemblyVersionAttribute"; const string assemblyInformationalVersion = "System.Reflection.AssemblyInformationalVersionAttribute"; var assemblyAttributes = compilation.Assembly.GetAttributes(); var foundAssemblyFileVersion = false; var foundAssemblyVersion = false; var foundAssemblyInformationalVersion = false; foreach (var assembly in assemblyAttributes) { string attributeName = assembly.AttributeClass.ToString(); if (string.Equals(attributeName, assemblyFileVersionName, StringComparison.Ordinal)) { foundAssemblyFileVersion = true; } else if (string.Equals(attributeName, assemblyVersionName, StringComparison.Ordinal)) { foundAssemblyVersion = true; } else if (string.Equals(attributeName, assemblyInformationalVersion, StringComparison.Ordinal)) { foundAssemblyInformationalVersion = true; } } var versionAttributes = new StringBuilder(); if (!foundAssemblyFileVersion) { versionAttributes.AppendLine($"[assembly:{assemblyFileVersionName}(\"{project.AssemblyFileVersion}\")]"); } if (!foundAssemblyVersion) { versionAttributes.AppendLine($"[assembly:{assemblyVersionName}(\"{RemovePrereleaseTag(project.Version)}\")]"); } if (!foundAssemblyInformationalVersion) { versionAttributes.AppendLine($"[assembly:{assemblyInformationalVersion}(\"{project.Version}\")]"); } if (versionAttributes.Length != 0) { compilation = compilation.AddSyntaxTrees(new[] { CSharpSyntaxTree.ParseText(versionAttributes.ToString(), parseOptions) }); } return(compilation); }
public CompilationContext CompileProject( ICompilationProject project, ILibraryKey target, IEnumerable <IMetadataReference> incomingReferences, IEnumerable <ISourceReference> incomingSourceReferences, Func <IList <ResourceDescriptor> > resourcesResolver) { var path = project.ProjectDirectory; var name = project.Name.TrimStart('/'); var isMainAspect = string.IsNullOrEmpty(target.Aspect); var isPreprocessAspect = string.Equals(target.Aspect, "preprocess", StringComparison.OrdinalIgnoreCase); if (!string.IsNullOrEmpty(target.Aspect)) { name += "!" + target.Aspect; } _watcher.WatchProject(path); _watcher.WatchFile(project.ProjectFilePath); if (_cacheContextAccessor.Current != null) { _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(project.ProjectFilePath)); if (isMainAspect) { // Monitor the trigger {projectName}_BuildOutputs var buildOutputsName = project.Name + "_BuildOutputs"; _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName)); } _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(project.Name + "_Dependencies")); } var exportedReferences = incomingReferences.Select(ConvertMetadataReference); Logger.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name); var sw = Stopwatch.StartNew(); var compilationSettings = project.GetCompilerOptions(target.TargetFramework, target.Configuration) .ToCompilationSettings(target.TargetFramework); var sourceFiles = Enumerable.Empty <String>(); if (isMainAspect) { sourceFiles = project.Files.SourceFiles; } else if (isPreprocessAspect) { sourceFiles = project.Files.PreprocessSourceFiles; } var parseOptions = new CSharpParseOptions(languageVersion: compilationSettings.LanguageVersion, preprocessorSymbols: compilationSettings.Defines); IList <SyntaxTree> trees = GetSyntaxTrees( project, sourceFiles, incomingSourceReferences, parseOptions, isMainAspect); var embeddedReferences = incomingReferences.OfType <IMetadataEmbeddedReference>() .ToDictionary(a => a.Name, ConvertMetadataReference); var references = new List <MetadataReference>(); references.AddRange(exportedReferences); var compilation = CSharpCompilation.Create( name, trees, references, compilationSettings.CompilationOptions); compilation = ApplyVersionInfo(compilation, project, parseOptions); var compilationContext = new CompilationContext( compilation, project, target.TargetFramework, target.Configuration, incomingReferences, () => resourcesResolver() .Select(res => new ResourceDescription( res.Name, res.StreamFactory, isPublic: true)) .ToList()); // Apply strong-name settings ApplyStrongNameSettings(compilationContext); if (isMainAspect && project.Files.PreprocessSourceFiles.Any()) { try { var modules = GetCompileModules(target).Modules; foreach (var m in modules) { compilationContext.Modules.Add(m); } } catch (Exception ex) { var compilationException = ex.InnerException as RoslynCompilationException; if (compilationException != null) { // Add diagnostics from the precompile step foreach (var diag in compilationException.Diagnostics) { compilationContext.Diagnostics.Add(diag); } Logger.TraceError("[{0}]: Failed loading meta assembly '{1}'", GetType().Name, name); } else { Logger.TraceError("[{0}]: Failed loading meta assembly '{1}':\n {2}", GetType().Name, name, ex); } } } if (compilationContext.Modules.Count > 0) { var precompSw = Stopwatch.StartNew(); foreach (var module in compilationContext.Modules) { module.BeforeCompile(compilationContext.BeforeCompileContext); } precompSw.Stop(); Logger.TraceInformation("[{0}]: Compile modules ran in in {1}ms", GetType().Name, precompSw.ElapsedMilliseconds); } sw.Stop(); Logger.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds); return(compilationContext); }
public CompilationContext CompileProject( ICompilationProject project, ILibraryKey target, IEnumerable<IMetadataReference> incomingReferences, IEnumerable<ISourceReference> incomingSourceReferences, Func<IList<ResourceDescriptor>> resourcesResolver) { var path = project.ProjectDirectory; var name = project.Name.TrimStart('/'); var isMainAspect = string.IsNullOrEmpty(target.Aspect); var isPreprocessAspect = string.Equals(target.Aspect, "preprocess", StringComparison.OrdinalIgnoreCase); if (!string.IsNullOrEmpty(target.Aspect)) { name += "!" + target.Aspect; } _watcher.WatchProject(path); _watcher.WatchFile(project.ProjectFilePath); if (_cacheContextAccessor.Current != null) { _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(project.ProjectFilePath)); if (isMainAspect) { // Monitor the trigger {projectName}_BuildOutputs var buildOutputsName = project.Name + "_BuildOutputs"; _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName)); } _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(project.Name + "_Dependencies")); } var exportedReferences = incomingReferences.Select(ConvertMetadataReference); Logger.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name); var sw = Stopwatch.StartNew(); var compilationSettings = project.GetCompilerOptions(target.TargetFramework, target.Configuration) .ToCompilationSettings(target.TargetFramework); var sourceFiles = Enumerable.Empty<String>(); if (isMainAspect) { sourceFiles = project.Files.SourceFiles; } else if (isPreprocessAspect) { sourceFiles = project.Files.PreprocessSourceFiles; } var parseOptions = new CSharpParseOptions(languageVersion: compilationSettings.LanguageVersion, preprocessorSymbols: compilationSettings.Defines); IList<SyntaxTree> trees = GetSyntaxTrees( project, sourceFiles, incomingSourceReferences, parseOptions, isMainAspect); var embeddedReferences = incomingReferences.OfType<IMetadataEmbeddedReference>() .ToDictionary(a => a.Name, ConvertMetadataReference); var references = new List<MetadataReference>(); references.AddRange(exportedReferences); var compilation = CSharpCompilation.Create( name, trees, references, compilationSettings.CompilationOptions); compilation = ApplyVersionInfo(compilation, project, parseOptions); var compilationContext = new CompilationContext( compilation, project, target.TargetFramework, target.Configuration, incomingReferences, () => resourcesResolver() .Select(res => new ResourceDescription( res.Name, res.StreamFactory, isPublic: true)) .ToList()); // Apply strong-name settings ApplyStrongNameSettings(compilationContext); if (isMainAspect && project.Files.PreprocessSourceFiles.Any()) { try { var modules = GetCompileModules(target).Modules; foreach (var m in modules) { compilationContext.Modules.Add(m); } } catch (Exception ex) { var compilationException = ex.InnerException as RoslynCompilationException; if (compilationException != null) { // Add diagnostics from the precompile step foreach (var diag in compilationException.Diagnostics) { compilationContext.Diagnostics.Add(diag); } Logger.TraceError("[{0}]: Failed loading meta assembly '{1}'", GetType().Name, name); } else { Logger.TraceError("[{0}]: Failed loading meta assembly '{1}':\n {2}", GetType().Name, name, ex); } } } if (compilationContext.Modules.Count > 0) { var precompSw = Stopwatch.StartNew(); foreach (var module in compilationContext.Modules) { module.BeforeCompile(compilationContext.BeforeCompileContext); } precompSw.Stop(); Logger.TraceInformation("[{0}]: Compile modules ran in in {1}ms", GetType().Name, precompSw.ElapsedMilliseconds); } sw.Stop(); Logger.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds); return compilationContext; }
private IList<SyntaxTree> GetSyntaxTrees(ICompilationProject project, IEnumerable<string> sourceFiles, IEnumerable<ISourceReference> sourceReferences, CSharpParseOptions parseOptions, bool isMainAspect) { var trees = new List<SyntaxTree>(); var dirs = new HashSet<string>(); if (isMainAspect) { dirs.Add(project.ProjectDirectory); } foreach (var sourcePath in sourceFiles) { _watcher.WatchFile(sourcePath); var syntaxTree = CreateSyntaxTree(sourcePath, parseOptions); trees.Add(syntaxTree); } foreach (var sourceFileReference in sourceReferences.OfType<ISourceFileReference>()) { var sourcePath = sourceFileReference.Path; _watcher.WatchFile(sourcePath); var syntaxTree = CreateSyntaxTree(sourcePath, parseOptions); trees.Add(syntaxTree); } // Watch all directories var ctx = _cacheContextAccessor.Current; foreach (var d in dirs) { ctx?.Monitor(new FileWriteTimeCacheDependency(d)); // TODO: Make the file watcher hand out cache dependencies as well _watcher.WatchDirectory(d, ".cs"); } return trees; }
public CompilationContext CompileProject( ICompilationProject project, ILibraryKey target, IEnumerable <IMetadataReference> incomingReferences, IEnumerable <ISourceReference> incomingSourceReferences, Func <IList <ResourceDescriptor> > resourcesResolver) { var path = project.ProjectDirectory; var name = project.Name; var fsproj = GetProjectInfo(path); _watcher.WatchProject(path); _watcher.WatchFile(project.ProjectFilePath); _watcher.WatchFile(fsproj.ProjectFilePath); foreach (var f in fsproj.Files) { _watcher.WatchFile(f); } if (_cacheContextAccessor.Current != null) { _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(fsproj.ProjectFilePath)); // Monitor the trigger {projectName}_BuildOutputs var buildOutputsName = project.Name + "_BuildOutputs"; _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName)); _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(project.Name + "_Dependencies")); } Logger.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name); var sw = Stopwatch.StartNew(); CompilationContext context; using (new ResolveHooker()) using (var files = new TempFiles()) { var outFileName = $"{name}.dll"; var outDir = files.CreateDir(); var outFile = Path.Combine(outDir, outFileName); var args = new List <string>(); args.Add("fsc.exe"); args.Add($"--out:{outFile}"); args.Add("--target:library"); args.Add("--noframework"); args.Add("--optimize-"); args.Add("--debug"); if (SupportsPdbGeneration) { args.Add($"--pdb:{Path.ChangeExtension(outFile, ".pdb")}"); } args.Add($"--doc:{Path.ChangeExtension(outFile, ".xml")}"); foreach (var source in fsproj.Files) { args.Add(source); } // These are the metadata references being used by your project. // Everything in your project.json is resolved and normailzed here: // - Project references // - Package references are turned into the appropriate assemblies // Each IMetadaReference maps to an assembly foreach (var reference in incomingReferences) { string fileName = null; var projectRef = reference as IMetadataProjectReference; if (projectRef != null) { var dir = files.CreateDir(); projectRef.EmitAssembly(dir); fileName = Path.Combine(dir, $"{projectRef.Name}.dll"); } var fileRef = reference as IMetadataFileReference; if (fileRef != null) { fileName = fileRef.Path; } else if (fileName == null) { throw new Exception($"Unknown reference type {reference.GetType()}"); } args.Add($"-r:{fileName}"); } //Console.WriteLine(string.Join(Environment.NewLine, args)); var scs = new SimpleSourceCodeServices(); var result = scs.Compile(args.ToArray()); var errors = result.Item1.Select(FSharpCompilationMessage.CompilationMessage); var resultCode = result.Item2; //System.Diagnostics.Debugger.Launch(); MemoryStream assembly = null; MemoryStream pdb = null; MemoryStream xml = null; if (resultCode == 0) { assembly = new MemoryStream(); xml = new MemoryStream(); using (var fs = File.OpenRead(outFile)) fs.CopyTo(assembly); var pdbFile = Path.ChangeExtension(outFile, ".pdb"); if (File.Exists(pdbFile)) { pdb = new MemoryStream(); using (var fs = File.OpenRead(pdbFile)) fs.CopyTo(pdb); } var xmlFile = Path.ChangeExtension(outFile, ".xml"); if (File.Exists(xmlFile)) { xml = new MemoryStream(); using (var fs = File.OpenRead(xmlFile)) fs.CopyTo(xml); } } context = new CompilationContext( project, fsproj, resultCode == 0, errors, assembly?.ToArray(), pdb?.ToArray(), xml?.ToArray()); assembly?.Dispose(); pdb?.Dispose(); xml?.Dispose(); } sw.Stop(); Logger.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds); return(context); }
public CompilationContext CompileProject( ICompilationProject project, ILibraryKey target, IEnumerable<IMetadataReference> incomingReferences, IEnumerable<ISourceReference> incomingSourceReferences, Func<IList<ResourceDescriptor>> resourcesResolver) { var path = project.ProjectDirectory; var name = project.Name; var fsproj = GetProjectInfo(path); _watcher.WatchProject(path); _watcher.WatchFile(project.ProjectFilePath); _watcher.WatchFile(fsproj.ProjectFilePath); foreach (var f in fsproj.Files) _watcher.WatchFile(f); if (_cacheContextAccessor.Current != null) { _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(fsproj.ProjectFilePath)); // Monitor the trigger {projectName}_BuildOutputs var buildOutputsName = project.Name + "_BuildOutputs"; _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName)); _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(project.Name + "_Dependencies")); } Logger.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name); var sw = Stopwatch.StartNew(); CompilationContext context; using (new ResolveHooker()) using (var files = new TempFiles()) { var outFileName = $"{name}.dll"; var outDir = files.CreateDir(); var outFile = Path.Combine(outDir, outFileName); var args = new List<string>(); args.Add("fsc.exe"); args.Add($"--out:{outFile}"); args.Add("--target:library"); args.Add("--noframework"); args.Add("--optimize-"); args.Add("--debug"); if (SupportsPdbGeneration) args.Add($"--pdb:{Path.ChangeExtension(outFile, ".pdb")}"); args.Add($"--doc:{Path.ChangeExtension(outFile, ".xml")}"); foreach (var source in fsproj.Files) args.Add(source); // These are the metadata references being used by your project. // Everything in your project.json is resolved and normailzed here: // - Project references // - Package references are turned into the appropriate assemblies // Each IMetadaReference maps to an assembly foreach (var reference in incomingReferences) { string fileName = null; var projectRef = reference as IMetadataProjectReference; if (projectRef != null) { var dir = files.CreateDir(); projectRef.EmitAssembly(dir); fileName = Path.Combine(dir, $"{projectRef.Name}.dll"); } var fileRef = reference as IMetadataFileReference; if (fileRef != null) fileName = fileRef.Path; else if (fileName == null) throw new Exception($"Unknown reference type {reference.GetType()}"); args.Add($"-r:{fileName}"); } //Console.WriteLine(string.Join(Environment.NewLine, args)); var scs = new SimpleSourceCodeServices(); var result = scs.Compile(args.ToArray()); var errors = result.Item1.Select(FSharpCompilationMessage.CompilationMessage); var resultCode = result.Item2; //System.Diagnostics.Debugger.Launch(); MemoryStream assembly = null; MemoryStream pdb = null; MemoryStream xml = null; if (resultCode == 0) { assembly = new MemoryStream(); xml = new MemoryStream(); using (var fs = File.OpenRead(outFile)) fs.CopyTo(assembly); var pdbFile = Path.ChangeExtension(outFile, ".pdb"); if (File.Exists(pdbFile)) { pdb = new MemoryStream(); using (var fs = File.OpenRead(pdbFile)) fs.CopyTo(pdb); } var xmlFile = Path.ChangeExtension(outFile, ".xml"); if (File.Exists(xmlFile)) { xml = new MemoryStream(); using (var fs = File.OpenRead(xmlFile)) fs.CopyTo(xml); } } context = new CompilationContext( project, fsproj, resultCode == 0, errors, assembly?.ToArray(), pdb?.ToArray(), xml?.ToArray()); assembly?.Dispose(); pdb?.Dispose(); xml?.Dispose(); } sw.Stop(); Logger.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds); return context; }
private static CSharpCompilation ApplyVersionInfo(CSharpCompilation compilation, ICompilationProject project, CSharpParseOptions parseOptions) { const string assemblyFileVersionName = "System.Reflection.AssemblyFileVersionAttribute"; const string assemblyVersionName = "System.Reflection.AssemblyVersionAttribute"; const string assemblyInformationalVersion = "System.Reflection.AssemblyInformationalVersionAttribute"; var assemblyAttributes = compilation.Assembly.GetAttributes(); var foundAssemblyFileVersion = false; var foundAssemblyVersion = false; var foundAssemblyInformationalVersion = false; foreach (var assembly in assemblyAttributes) { string attributeName = assembly.AttributeClass.ToString(); if (string.Equals(attributeName, assemblyFileVersionName, StringComparison.Ordinal)) { foundAssemblyFileVersion = true; } else if (string.Equals(attributeName, assemblyVersionName, StringComparison.Ordinal)) { foundAssemblyVersion = true; } else if (string.Equals(attributeName, assemblyInformationalVersion, StringComparison.Ordinal)) { foundAssemblyInformationalVersion = true; } } var versionAttributes = new StringBuilder(); if (!foundAssemblyFileVersion) { versionAttributes.AppendLine($"[assembly:{assemblyFileVersionName}(\"{project.AssemblyFileVersion}\")]"); } if (!foundAssemblyVersion) { versionAttributes.AppendLine($"[assembly:{assemblyVersionName}(\"{RemovePrereleaseTag(project.Version)}\")]"); } if (!foundAssemblyInformationalVersion) { versionAttributes.AppendLine($"[assembly:{assemblyInformationalVersion}(\"{project.Version}\")]"); } if (versionAttributes.Length != 0) { compilation = compilation.AddSyntaxTrees(new[] { CSharpSyntaxTree.ParseText(versionAttributes.ToString(), parseOptions) }); } return compilation; }