/// <summary> /// Returns a look-up with all Q# examples extracted from doc comments for each namespace. /// The key may be null if the extracted example is specified outside a namespace. /// </summary> public static ILookup <string, string> Extract(QsCompilation compilation) { var instance = new ExamplesInDocs(); instance.Apply(compilation); return(instance.SharedState.ToLookup(entry => entry.Item1, entry => entry.Item2)); }
// 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); }