Example #1
0
        // routines related to tracking the editor state

        /// <summary>
        /// To be called whenever a file is opened in the editor.
        /// Does nothing if the given file is listed as to be ignored.
        /// Otherwise publishes suitable diagnostics for it.
        /// Invokes the given Action showError with a suitable message if the given file cannot be loaded.
        /// Invokes the given Action logError with a suitable message if the given file cannot be associated with a compilation unit,
        /// or if the given file is already listed as being open in the editor.
        /// Throws an ArgumentException if the uri of the given text document identifier is null or not an absolute file uri.
        /// Throws an ArgumentNullException if the given content is null.
        /// </summary>
        internal Task OpenFileAsync(TextDocumentItem textDocument,
                                    Action <string, MessageType> showError = null, Action <string, MessageType> logError = null)
        {
            if (!ValidFileUri(textDocument?.Uri))
            {
                throw new ArgumentException("invalid text document identifier");
            }
            if (textDocument.Text == null)
            {
                throw new ArgumentNullException(nameof(textDocument.Text));
            }
            _ = this.Projects.ManagerTaskAsync(textDocument.Uri, (manager, associatedWithProject) =>
            {
                if (IgnoreFile(textDocument.Uri))
                {
                    return;
                }
                var newManager = CompilationUnitManager.InitializeFileManager(textDocument.Uri, textDocument.Text, this.Publish, ex =>
                {
                    showError?.Invoke($"Failed to load file '{textDocument.Uri.LocalPath}'", MessageType.Error);
                    manager.LogException(ex);
                });

                // Currently it is not possible to handle both the behavior of VS and VS Code for changes on disk in a manner that will never fail.
                // To mitigate the impact of failures we choose to just log them as info.
                var file = this.OpenFiles.GetOrAdd(textDocument.Uri, newManager);
                if (file != newManager) // this may be the case (depending on the editor) e.g. when opening a version control diff ...
                {
                    showError?.Invoke($"Version control and opening multiple versions of the same file in the editor are currently not supported. \n" +
                                      $"Intellisense has been disable for the file '{textDocument.Uri.LocalPath}'. An editor restart is required to enable intellisense again.", MessageType.Error);
                    #if DEBUG
                    if (showError == null)
                    {
                        logError?.Invoke("Attempting to open a file that is already open in the editor.", MessageType.Error);
                    }
                    #endif

                    this.IgnoreEditorUpdatesFor(textDocument.Uri);
                    this.OpenFiles.TryRemove(textDocument.Uri, out FileContentManager _);
                    if (!associatedWithProject)
                    {
                        _ = manager.TryRemoveSourceFileAsync(textDocument.Uri);
                    }
                    this.Publish(new PublishDiagnosticParams {
                        Uri = textDocument.Uri, Diagnostics = new Diagnostic[0]
                    });
                    return;
                }

                if (!associatedWithProject)
                {
                    logError?.Invoke(
                        $"The file {textDocument.Uri.LocalPath} is not associated with a compilation unit. Only syntactic diagnostics are generated."
                        , MessageType.Info);
                }
                _ = manager.AddOrUpdateSourceFileAsync(file);
            });
            // reloading from disk in case we encountered a file already open error above
            return(this.Projects.SourceFileChangedOnDiskAsync(textDocument.Uri, GetOpenFile)); // NOTE: relies on that the manager task is indeed executed first!
        }
Example #2
0
        /// <summary>
        /// Used to reload the file content when a file is saved.
        /// Does nothing if the given file is listed as to be ignored.
        /// Expects to get the entire content of the file at the time of saving as argument.
        /// Throws an ArgumentException if the uri of the given text document identifier is null or not an absolute file uri.
        /// Throws an ArgumentNullException if the given content is null.
        /// </summary>
        internal Task SaveFileAsync(TextDocumentIdentifier textDocument, string fileContent)
        {
            if (!ValidFileUri(textDocument?.Uri))
            {
                throw new ArgumentException("invalid text document identifier");
            }
            if (fileContent == null)
            {
                throw new ArgumentNullException(nameof(fileContent));
            }
            return(this.Projects.ManagerTaskAsync(textDocument.Uri, (manager, __) =>
            {
                if (IgnoreFile(textDocument.Uri))
                {
                    return;
                }

                // Currently it is not possible to handle both the behavior of VS and VS Code for changes on disk in a manner that will never fail.
                // To mitigate the impact of failures we choose to ignore them silently and do our best to recover.
                if (!this.OpenFiles.TryGetValue(textDocument.Uri, out var file))
                {
                    file = CompilationUnitManager.InitializeFileManager(textDocument.Uri, fileContent, this.Publish, manager.LogException);
                    this.OpenFiles.TryAdd(textDocument.Uri, file);
                    _ = manager.AddOrUpdateSourceFileAsync(file);
                }
                else
                {
                    _ = manager.AddOrUpdateSourceFileAsync(file, fileContent);  // let's reload the file content on saving
                }
            }));
        }
Example #3
0
        /// <summary>
        /// Loads the Q# data structures in a referenced assembly given the Uri to that assembly,
        /// and returns the loaded content as out parameter.
        /// Returns false if some of the content could not be loaded successfully,
        /// possibly because the referenced assembly has been compiled with an older compiler version.
        /// If onDeserializationException is specified, invokes the given action on any exception thrown during deserialization.
        /// Throws the corresponding exceptions if the information cannot be extracted.
        /// </summary>
        /// <exception cref="FileNotFoundException"><paramref name="asm"/> does not exist.</exception>
        /// <exception cref="ArgumentException"><paramref name="asm"/> is not an absolute file URI.</exception>
        public static bool LoadReferencedAssembly(Uri asm, out References.Headers headers, bool ignoreDllResources = false, Action <Exception>?onDeserializationException = null)
        {
            var id = CompilationUnitManager.GetFileId(asm);

            if (!File.Exists(asm.LocalPath))
            {
                throw new FileNotFoundException($"The file '{asm.LocalPath}' given to the assembly loader does not exist.");
            }

            using var stream       = File.OpenRead(asm.LocalPath);
            using var assemblyFile = new PEReader(stream);
            if (ignoreDllResources || !FromResource(assemblyFile, out var compilation, onDeserializationException))
            {
                PerformanceTracking.TaskStart(PerformanceTracking.Task.HeaderAttributesLoading);
                var attributes = LoadHeaderAttributes(assemblyFile);
                PerformanceTracking.TaskEnd(PerformanceTracking.Task.HeaderAttributesLoading);
                PerformanceTracking.TaskStart(PerformanceTracking.Task.ReferenceHeadersCreation);
                headers = new References.Headers(id, attributes);
                PerformanceTracking.TaskEnd(PerformanceTracking.Task.ReferenceHeadersCreation);
                return(ignoreDllResources || !attributes.Any()); // just means we have no references
            }
            PerformanceTracking.TaskStart(PerformanceTracking.Task.ReferenceHeadersCreation);
            headers = new References.Headers(id, compilation?.Namespaces ?? ImmutableArray <QsNamespace> .Empty);
            PerformanceTracking.TaskEnd(PerformanceTracking.Task.ReferenceHeadersCreation);
            return(true);
        }
        private QsCompilation CreateCompilation(params string[] fileNames)
        {
            var mgr   = new CompilationUnitManager();
            var files = CreateFileManager(fileNames);

            mgr.AddOrUpdateSourceFilesAsync(files).Wait();
            return(mgr.Build().BuiltCompilation);
        }
Example #5
0
        /// <summary>
        /// Compiles the given code.
        /// If the operations defined in this code are already defined
        /// in existing Snippets, those Snippets are skipped.
        /// If successful, this updates the AssemblyInfo
        /// with the new operations found in the Snippet.
        /// If errors are found during compilation, a `CompilationErrorsException` is triggered
        /// with the list of errors found.
        /// If successful, the list of snippets is updated to include those that were part of the
        /// compilation and it will return a new Snippet with the warnings and Q# elements
        /// reported by the compiler.
        /// </summary>
        public Snippet Compile(string code)
        {
            if (string.IsNullOrWhiteSpace(code))
            {
                throw new ArgumentNullException(nameof(code));
            }

            var duration = Stopwatch.StartNew();

            // We add exactly one line of boilerplate code at the beginning of each snippet,
            // so tell the logger to subtract one from all displayed line numbers.
            var logger = new QSharpLogger(Logger, lineNrOffset: -1);

            try
            {
                var snippets = SelectSnippetsToCompile(code).ToArray();
                var assembly = Compiler.BuildSnippets(snippets, _metadata.Value, logger, Path.Combine(Workspace.CacheFolder, "__snippets__.dll"));

                if (logger.HasErrors)
                {
                    throw new CompilationErrorsException(logger.Errors.ToArray());
                }

                foreach (var entry in Compiler.IdentifyOpenedNamespaces(code))
                {
                    Compiler.AutoOpenNamespaces[entry.Key] = entry.Value;
                }

                // populate the original snippet with the results of the compilation:
                Snippet populate(Snippet s) =>
                new Snippet()
                {
                    id       = string.IsNullOrWhiteSpace(s.id) ? Guid.NewGuid().ToString() : s.id,
                    code     = s.code,
                    warnings = logger.Logs
                               .Where(m => m.Source == CompilationUnitManager.GetFileId(s.Uri).Value)
                               .Select(logger.Format)
                               .ToArray(),
                    Elements = assembly?.SyntaxTree?
                               .SelectMany(ns => ns.Elements)
                               .Where(c => c.SourceFile() == CompilationUnitManager.GetFileId(s.Uri).Value)
                               .ToArray()
                };

                AssemblyInfo = assembly;
                Items        = snippets.Select(populate).ToArray();

                return(Items.Last());
            }
            finally
            {
                duration.Stop();
                var status   = logger.HasErrors ? "error" : "ok";
                var errorIds = logger.ErrorIds.ToArray();
                SnippetCompiled?.Invoke(this, new SnippetCompiledEventArgs(status, errorIds, Compiler.AutoOpenNamespaces.Keys.ToArray(), duration.Elapsed));
            }
        }
Example #6
0
        /// <summary>
        /// Builds the corresponding .net core assembly from the code in the given files.
        /// </summary>
        public AssemblyInfo BuildFiles(string[] files, CompilerMetadata metadatas, QSharpLogger logger, string dllName)
        {
            var syntaxTree = BuildQsSyntaxTree(files, metadatas.QsMetadatas, logger);

            Uri FileUri(string f) => CompilationUnitManager.TryGetUri(NonNullable <string> .New(f), out var uri) ? uri : null;

            var assembly = BuildAssembly(files.Select(FileUri).ToArray(), syntaxTree, metadatas.RoslynMetadatas, logger, dllName);

            return(assembly);
        }
Example #7
0
        /// <summary>
        /// Compiles the given code.
        /// If the operations defined in this code are already defined
        /// in existing Snippets, those Snippets are skipped.
        /// If successful, this updates the AssemblyInfo
        /// with the new operations found in the Snippet.
        /// If errors are found during compilation, a `CompilationErrorsException` is triggered
        /// with the list of errors found.
        /// If successful, the list of snippets is updated to include those that were part of the
        /// compilation and it will return a new Snippet with the warnings and Q# elements
        /// reported by the compiler.
        /// </summary>
        public Snippet Compile(string code)
        {
            if (string.IsNullOrWhiteSpace(code))
            {
                throw new ArgumentNullException(nameof(code));
            }

            var duration = Stopwatch.StartNew();
            var logger   = new QSharpLogger(Logger);

            try
            {
                var snippets = SelectSnippetsToCompile(code).ToArray();
                var assembly = Compiler.BuildSnippets(snippets, _metadata.Value, logger, Path.Combine(Workspace.CacheFolder, "__snippets__.dll"));

                if (logger.HasErrors)
                {
                    throw new CompilationErrorsException(logger.Errors.ToArray());
                }

                // populate the original snippet with the results of the compilation:
                Snippet populate(Snippet s) =>
                new Snippet()
                {
                    id       = string.IsNullOrWhiteSpace(s.id) ? Guid.NewGuid().ToString() : s.id,
                    code     = s.code,
                    warnings = logger.Logs
                               .Where(m => m.Source == CompilationUnitManager.GetFileId(s.Uri).Value)
                               .Select(logger.Format)
                               .ToArray(),
                    Elements = assembly?.SyntaxTree?
                               .SelectMany(ns => ns.Elements)
                               .Where(c => c.SourceFile() == CompilationUnitManager.GetFileId(s.Uri).Value)
                               .ToArray()
                };

                AssemblyInfo = assembly;
                Items        = snippets.Select(populate).ToArray();

                return(Items.Last());
            }
            finally
            {
                duration.Stop();
                var status   = logger.HasErrors ? "error" : "ok";
                var errorIds = logger.ErrorIds.ToArray();
                SnippetCompiled?.Invoke(this, new SnippetCompiledEventArgs(status, errorIds, duration.Elapsed));
            }
        }
Example #8
0
        private FileContentManager InitializeFileManager(IEnumerable <string> examples, QsCompilation compilation, string nsName = null)
        {
            var(pre, post) = ($"namespace {nsName ?? DefaultNamespaceName}{{ {Environment.NewLine}", $"{Environment.NewLine}}}");
            var openDirs = String.Join(Environment.NewLine,
                                       OpenedForTesting
                                       .Where(nsName => ContainsNamespace(compilation, nsName))
                                       .Select(nsName => $"open {nsName};"));

            string WrapInNamespace(string example) => pre + openDirs + example + post;

            examples = examples.Where(ex => !String.IsNullOrWhiteSpace(ex));
            var sourceCode = String.Join(Environment.NewLine, examples.Select(WrapInNamespace));

            var sourceName = NonNullable <string> .New(Path.GetFullPath($"{nsName}{CodeSource}"));

            return(CompilationUnitManager.TryGetUri(sourceName, out var sourceUri)
                ? CompilationUnitManager.InitializeFileManager(sourceUri, sourceCode)
                : null);
        }
Example #9
0
        /// <summary>
        /// Loads the Q# data structures in a referenced assembly given the Uri to that assembly,
        /// and returns the loaded content as out parameter.
        /// Returns false if some of the content could not be loaded successfully,
        /// possibly because the referenced assembly has been compiled with an older compiler version.
        /// Throws an ArgumentNullException if the given uri is null.
        /// Throws a FileNotFoundException if no file with the given name exists.
        /// Throws the corresponding exceptions if the information cannot be extracted.
        /// </summary>
        public static bool LoadReferencedAssembly(Uri asm, out References.Headers headers, bool ignoreDllResources = false)
        {
            if (asm == null)
            {
                throw new ArgumentNullException(nameof(asm));
            }
            if (!CompilationUnitManager.TryGetFileId(asm, out var id) || !File.Exists(asm.LocalPath))
            {
                throw new FileNotFoundException($"the uri '{asm}' given to the assembly loader is invalid or the file does not exist");
            }

            using var stream       = File.OpenRead(asm.LocalPath);
            using var assemblyFile = new PEReader(stream);
            if (ignoreDllResources || !FromResource(assemblyFile, out var syntaxTree))
            {
                var attributes = LoadHeaderAttributes(assemblyFile);
                headers = new References.Headers(id, attributes);
                return(ignoreDllResources || !attributes.Any()); // just means we have no references
            }
            headers = new References.Headers(id, syntaxTree?.Namespaces ?? ImmutableArray <QsNamespace> .Empty);
            return(true);
        }
Example #10
0
        /// <summary>
        /// Returns the workspace edit that describes the changes to be done if the symbol at the given position - if any - is renamed to the given name.
        /// Returns null if no symbol exists at the specified position,
        /// or if some parameters are unspecified (null),
        /// or if the specified position is not a valid position within the file.
        /// </summary>
        public static WorkspaceEdit?Rename(this FileContentManager file, CompilationUnit compilation, Position position, string newName)
        {
            if (newName == null || file == null)
            {
                return(null);
            }
            var found = file.TryGetReferences(compilation, position, out var declLocation, out var locations);

            if (!found)
            {
                return(null);
            }

            if (declLocation != null)
            {
                locations = new[] { declLocation }.Concat(locations);
            }
            var changes = locations.ToLookup(loc => loc.Uri, loc => new TextEdit {
                Range = loc.Range, NewText = newName
            });

            return(new WorkspaceEdit
            {
                DocumentChanges = changes
                                  .Select(change => new TextDocumentEdit
                {
                    TextDocument = new VersionedTextDocumentIdentifier {
                        Uri = change.Key, Version = 1
                    },                                                                                        // setting version to null here won't work in VS Code ...
                    Edits = change.ToArray()
                })
                                  .ToArray(),

                Changes = changes.ToDictionary(
                    items => CompilationUnitManager.GetFileId(items.Key),
                    items => items.ToArray())
            });
        }
Example #11
0
        /// <summary>
        /// Builds the corresponding .net core assembly from the Q# syntax tree.
        /// </summary>
        private static AssemblyInfo BuildAssembly(Uri[] fileNames, QsCompiler.SyntaxTree.QsNamespace[] syntaxTree, IEnumerable <MetadataReference> references, QSharpLogger logger, string targetDll)
        {
            if (logger.HasErrors)
            {
                return(null);
            }

            logger.LogDebug($"Compiling the following Q# files: {string.Join(",", fileNames.Select(f => f.LocalPath))}");

            try
            {
                // Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees:
                var trees = new List <SyntaxTree>();
                NonNullable <string> GetFileId(Uri uri) => CompilationUnitManager.TryGetFileId(uri, out var id) ? id : NonNullable <string> .New(uri.AbsolutePath);

                foreach (var file in fileNames)
                {
                    var sourceFile = GetFileId(file);
                    var code       = SimulationCode.generate(sourceFile, syntaxTree);
                    var tree       = CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8);
                    trees.Add(tree);
                    logger.LogDebug($"Generated the following C# code for {sourceFile.Value}:\n=============\n{code}\n=============\n");
                }

                // Compile the C# syntax trees:
                var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug);

                var compilation = CSharpCompilation.Create(
                    Path.GetFileNameWithoutExtension(targetDll),
                    trees,
                    references,
                    options);

                // Generate the assembly from the C# compilation:
                using (var ms = new MemoryStream())
                {
                    EmitResult result = compilation.Emit(ms);

                    if (!result.Success)
                    {
                        IEnumerable <Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                                                                                     diagnostic.IsWarningAsError ||
                                                                                     diagnostic.Severity == DiagnosticSeverity.Error);

                        logger.LogError("IQS000", "Could not compile Roslyn dll from working folder.");

                        foreach (Diagnostic diagnostic in failures)
                        {
                            logger.LogError(diagnostic.Id, diagnostic.GetMessage());
                        }

                        return(null);
                    }
                    else
                    {
                        logger.LogDebug($"Assembly successfully generated. Caching at {targetDll}.");
                        var data = ms.ToArray();

                        try
                        {
                            File.WriteAllBytes(targetDll, data);
                        }
                        catch (Exception e)
                        {
                            logger.LogError("IQS001", $"Unable to save assembly cache: {e.Message}.");
                        }

                        return(new AssemblyInfo(Assembly.Load(data), targetDll, syntaxTree));
                    }
                }
            }
            catch (Exception e)
            {
                logger.LogError("IQS002", $"Unexpected error compiling assembly: {e.Message}.");
                return(null);
            }
        }
Example #12
0
        /// <summary>
        /// Builds the corresponding .net core assembly from the Q# syntax tree.
        /// </summary>
        private AssemblyInfo BuildAssembly(ImmutableDictionary <Uri, string> sources, CompilerMetadata metadata, QSharpLogger logger, string dllName)
        {
            logger.LogDebug($"Compiling the following Q# files: {string.Join(",", sources.Keys.Select(f => f.LocalPath))}");

            var qsCompilation = this.UpdateCompilation(sources, metadata.QsMetadatas, logger);

            if (logger.HasErrors)
            {
                return(null);
            }

            try
            {
                // Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees:
                var trees = new List <SyntaxTree>();
                NonNullable <string> GetFileId(Uri uri) => CompilationUnitManager.TryGetFileId(uri, out var id) ? id : NonNullable <string> .New(uri.AbsolutePath);

                foreach (var file in sources.Keys)
                {
                    var sourceFile = GetFileId(file);
                    var code       = SimulationCode.generate(sourceFile, CodegenContext.Create(qsCompilation.Namespaces));
                    var tree       = CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8);
                    trees.Add(tree);
                    logger.LogDebug($"Generated the following C# code for {sourceFile.Value}:\n=============\n{code}\n=============\n");
                }

                // Compile the C# syntax trees:
                var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug);

                var compilation = CSharpCompilation.Create(
                    Path.GetFileNameWithoutExtension(dllName),
                    trees,
                    metadata.RoslynMetadatas,
                    options);

                // Generate the assembly from the C# compilation:
                using (var ms = new MemoryStream())
                    using (var bsonStream = new MemoryStream())
                    {
                        using var writer = new BsonDataWriter(bsonStream)
                              {
                                  CloseOutput = false
                              };
                        var fromSources = qsCompilation.Namespaces.Select(ns => FilterBySourceFile.Apply(ns, s => s.Value.EndsWith(".qs")));
                        Json.Serializer.Serialize(writer, new QsCompilation(fromSources.ToImmutableArray(), qsCompilation.EntryPoints));

                        var resourceDescription = new ResourceDescription
                                                  (
                            resourceName: QsCompiler.ReservedKeywords.DotnetCoreDll.ResourceName,
                            dataProvider: () => new MemoryStream(bsonStream.ToArray()),
                            isPublic: true
                                                  );


                        var result = compilation.Emit(ms, manifestResources: new[] { resourceDescription });

                        if (!result.Success)
                        {
                            IEnumerable <Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                                                                                         diagnostic.IsWarningAsError ||
                                                                                         diagnostic.Severity == DiagnosticSeverity.Error);

                            logger.LogError("IQS000", "Could not compile Roslyn dll from working folder.");

                            foreach (Diagnostic diagnostic in failures)
                            {
                                logger.LogError(diagnostic.Id, diagnostic.GetMessage());
                            }

                            return(null);
                        }
                        else
                        {
                            logger.LogDebug($"Assembly successfully generated. Caching at {dllName}.");
                            var data = ms.ToArray();

                            try
                            {
                                File.WriteAllBytes(dllName, data);
                            }
                            catch (Exception e)
                            {
                                logger.LogError("IQS001", $"Unable to save assembly cache: {e.Message}.");
                            }

                            return(new AssemblyInfo(Assembly.Load(data), dllName, fromSources.ToArray()));
                        }
                    }
            }
            catch (Exception e)
            {
                logger.LogError("IQS002", $"Unexpected error compiling assembly: {e.Message}.");
                return(null);
            }
        }
Example #13
0
        // interface methods

        public bool Transformation(QsCompilation compilation, out QsCompilation transformed)
        {
            transformed = FilterSourceFiles.Apply(compilation);
            var manager = new CompilationUnitManager();

            // get source code from examples

            var fileManagers = ExamplesInDocs.Extract(transformed)
                               .Select(g => InitializeFileManager(g, compilation, g.Key))
                               .Where(m => m != null).ToImmutableHashSet();

            manager.AddOrUpdateSourceFilesAsync(fileManagers, suppressVerification: true);
            var sourceFiles = fileManagers.Select(m => m.FileName).ToImmutableHashSet();

            bool IsGeneratedSourceFile(NonNullable <string> source) => sourceFiles.Contains(source);

            // get everything contained in the compilation as references

            var refName = NonNullable <string> .New(Path.GetFullPath(ReferenceSource));

            var refHeaders = new References.Headers(refName, DllToQs.Rename(compilation).Namespaces);
            var refDict    = new Dictionary <NonNullable <string>, References.Headers> {
                { refName, refHeaders }
            };
            var references = new References(refDict.ToImmutableDictionary());

            manager.UpdateReferencesAsync(references);

            // compile the examples in the doc comments and add any diagnostics to the list of generated diagnostics

            var built       = manager.Build();
            var diagnostics = built.Diagnostics();

            this.Diagnostics.AddRange(diagnostics.Select(d => IRewriteStep.Diagnostic.Create(d, IRewriteStep.Stage.Transformation)));
            if (diagnostics.Any(d => d.Severity == VS.DiagnosticSeverity.Error))
            {
                return(false);
            }

            // add the extracted namespace elements from doc comments to the transformed compilation

            var toBeAdded = built.BuiltCompilation.Namespaces.ToImmutableDictionary(
                ns => ns.Name,
                ns => FilterBySourceFile.Apply(ns, IsGeneratedSourceFile));
            var namespaces = compilation.Namespaces.Select(ns =>
                                                           toBeAdded.TryGetValue(ns.Name, out var add)
                ? new QsNamespace(ns.Name, ns.Elements.AddRange(add.Elements), ns.Documentation)
                : ns);
            var addedNamespaces = toBeAdded.Values.Where(add => !compilation.Namespaces.Any(ns => ns.Name.Value == add.Name.Value));

            transformed = new QsCompilation(namespaces.Concat(addedNamespaces).ToImmutableArray(), compilation.EntryPoints);

            // mark all newly created callables that take unit as argument as unit tests to run on the QuantumSimulator and ResourcesEstimator

            bool IsSuitableForUnitTest(QsCallable c) => IsGeneratedSourceFile(c.SourceFile) && c.Signature.ArgumentType.Resolution.IsUnitType;

            var qsimAtt = AttributeUtils.BuildAttribute(BuiltIn.Test.FullName, AttributeUtils.StringArgument(Constants.QuantumSimulator));
            var restAtt = AttributeUtils.BuildAttribute(BuiltIn.Test.FullName, AttributeUtils.StringArgument(Constants.ResourcesEstimator));

            transformed = AttributeUtils.AddToCallables(transformed, (qsimAtt, IsSuitableForUnitTest), (restAtt, IsSuitableForUnitTest));
            return(true);
        }