Example #1
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);
        }
Example #2
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 #3
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);
        }