From 4fbd6b9c6b03a93f84bf898d52d14ccffe58156e Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 26 Aug 2020 11:14:19 -0700 Subject: [PATCH 01/74] Added devcontainer.json to allow remote development. --- .devcontainer/devcontainer.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..73c8b18d65 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "image": "mcr.microsoft.com/dotnet/core/sdk:3.1-focal", + "extensions": [ + "ms-dotnettools.csharp", + "Ionide.Ionide-fsharp", + "ms-vscode.powershell", + "quantum.quantum-devkit-vscode", + "ms-vscode.cpptools" + ], + "settings": { + "terminal.integrated.shell.linux": "/usr/bin/pwsh" + } +} From 53861cafb91e250e437aa52372430d5ddee9f8a9 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 00:18:07 -0700 Subject: [PATCH 02/74] Allow bootstrap to support -Verbose. --- bootstrap.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bootstrap.ps1 b/bootstrap.ps1 index 824748cb51..6a269ed091 100644 --- a/bootstrap.ps1 +++ b/bootstrap.ps1 @@ -1,3 +1,4 @@ +[CmdletBinding()] param( [string] $AssemblyVersion = $Env:ASSEMBLY_VERSION, @@ -68,6 +69,7 @@ If ($Env:SEMVER_VERSION -eq $null) { $Env:SEMVER_VERSION ="$SemverVersion" } If ($Env:VSVSIX_VERSION -eq $null) { $Env:VSVSIX_VERSION ="$VsVsixVersion" } Write-Host "##vso[task.setvariable variable=VsVsix.Version]$VsVsixVersion" +Write-Host "##[info]Finding NuSpec references..." Push-Location (Join-Path $PSScriptRoot 'src/QsCompiler/Compiler') .\FindNuspecReferences.ps1; Pop-Location From 5769ee9f1f0c4ba22a689336a69e083840a13452 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 00:18:19 -0700 Subject: [PATCH 03/74] Add and verify manifest. --- build/build.ps1 | 3 +++ build/manifest.ps1 | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 build/manifest.ps1 diff --git a/build/build.ps1 b/build/build.ps1 index 2d28dce3dc..b94d461ba8 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -121,6 +121,9 @@ if ($Env:ENABLE_VSIX -ne "false") { Write-Host "##vso[task.logissue type=warning;]VSIX building skipped due to ENABLE_VSIX variable." } +Write-Host "##[info]Verifying manifest..." +& (Join-Path $PSScriptRoot "manifest.ps1") + if (-not $all_ok) { throw "Building failed. Check the logs." exit 1 diff --git a/build/manifest.ps1 b/build/manifest.ps1 new file mode 100644 index 0000000000..341ba6efbc --- /dev/null +++ b/build/manifest.ps1 @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +#!/usr/bin/env pwsh +#Requires -PSEdition Core + +& "$PSScriptRoot/set-env.ps1" + +@{ + Packages = @( + "Microsoft.Quantum.Compiler", + "Microsoft.Quantum.Compiler.CommandLine", + "Microsoft.Quantum.ProjectTemplates", + "Microsoft.Quantum.Sdk", + "Microsoft.Quantum.DocumentationGenerator" + ); + Assemblies = @( + "./src/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompilationManager.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCore.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDataStructures.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsLanguageServer.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsSyntaxProcessor.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTextProcessor.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll" + ) | ForEach-Object { Get-Item (Join-Path $PSScriptRoot ".." $_) }; +} | Write-Output; From e693f0521bbc0849665845c58342b8bcfeff9fa2 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 00:18:42 -0700 Subject: [PATCH 04/74] Copy documentation generator from runtime. --- src/DocumentationGenerator/DocgenStep.cs | 78 ++++++ .../DocumentationGenerator.csproj | 29 ++ src/DocumentationGenerator/Extensions.cs | 247 ++++++++++++++++++ .../ProcessDocComments.cs | 230 ++++++++++++++++ 4 files changed, 584 insertions(+) create mode 100644 src/DocumentationGenerator/DocgenStep.cs create mode 100644 src/DocumentationGenerator/DocumentationGenerator.csproj create mode 100644 src/DocumentationGenerator/Extensions.cs create mode 100644 src/DocumentationGenerator/ProcessDocComments.cs diff --git a/src/DocumentationGenerator/DocgenStep.cs b/src/DocumentationGenerator/DocgenStep.cs new file mode 100644 index 0000000000..182f8bbacf --- /dev/null +++ b/src/DocumentationGenerator/DocgenStep.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.Quantum.QsCompiler; +using Microsoft.Quantum.QsCompiler.Experimental; +using Microsoft.Quantum.QsCompiler.SyntaxTree; + + +namespace Microsoft.Quantum.Documentation +{ + public class DocumentationGenerationStep : IRewriteStep + { + private readonly List Diagnostics; + + public DocumentationGenerationStep() + { + this.AssemblyConstants = new Dictionary(); // will be populated by the Q# compiler + this.Diagnostics = new List(); // collects diagnostics that will be displayed to the user + } + + public string Name => "DocumentationGeneration"; + public int Priority => 0; // only compared within this dll + + public IDictionary AssemblyConstants { get; } + public IEnumerable GeneratedDiagnostics => this.Diagnostics; + + public bool ImplementsPreconditionVerification => true; + public bool ImplementsTransformation => true; + public bool ImplementsPostconditionVerification => false; + + + public bool PreconditionVerification(QsCompilation compilation) + { + var preconditionPassed = true; // nothing to check + if (preconditionPassed) + { + // Diagnostics with severity Info or lower usually won't be displayed to the user. + // If the severity is Error or Warning the diagnostic is shown to the user like any other compiler diagnostic, + // and if the Source property is set to the absolute path of an existing file, + // the user will be directed to the file when double clicking the diagnostics. + this.Diagnostics.Add(new IRewriteStep.Diagnostic + { + Severity = DiagnosticSeverity.Info, + Message = $"Precondition for {this.Name} was {(preconditionPassed ? "satisfied" : "not satisfied")}.", + Stage = IRewriteStep.Stage.PreconditionVerification + }); + + foreach (var item in AssemblyConstants) + { + this.Diagnostics.Add(new IRewriteStep.Diagnostic + { + Severity = DiagnosticSeverity.Info, + Message = $"Got assembly constant \"{item.Key}\" = \"{item.Value}\".", + Stage = IRewriteStep.Stage.PreconditionVerification + }); + } + } + return preconditionPassed; + } + + public bool Transformation(QsCompilation compilation, out QsCompilation transformed) + { + transformed = new ProcessDocComments( + AssemblyConstants.TryGetValue("OutputPath", out var path) + ? path + : null + ).OnCompilation(compilation); + return true; + } + + public bool PostconditionVerification(QsCompilation compilation) => + throw new NotImplementedException(); + } +} diff --git a/src/DocumentationGenerator/DocumentationGenerator.csproj b/src/DocumentationGenerator/DocumentationGenerator.csproj new file mode 100644 index 0000000000..0f190d69ac --- /dev/null +++ b/src/DocumentationGenerator/DocumentationGenerator.csproj @@ -0,0 +1,29 @@ + + + + + netstandard2.1 + Microsoft.Quantum.DocumentationGenerator + + + + Microsoft + Experimental documentation generation tool for Q#. + Microsoft.Quantum.DocumentationGenerator + See: https://docs.microsoft.com/en-us/quantum/relnotes/ + MIT + https://github.com/microsoft/qsharp-runtime + https://secure.gravatar.com/avatar/bd1f02955b2853ba0a3b1cdc2434e8ec.png + Quantum Q# Qsharp + true + + + + + + + + + + + diff --git a/src/DocumentationGenerator/Extensions.cs b/src/DocumentationGenerator/Extensions.cs new file mode 100644 index 0000000000..ab7bbb8ff3 --- /dev/null +++ b/src/DocumentationGenerator/Extensions.cs @@ -0,0 +1,247 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.Quantum.QsCompiler; +using Microsoft.Quantum.QsCompiler.DataTypes; +using Microsoft.Quantum.QsCompiler.SyntaxTokens; +using Microsoft.Quantum.QsCompiler.SyntaxTree; +using Microsoft.Quantum.QsCompiler.Transformations.Core; +using Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput; +using YamlDotNet.Serialization; +using Range = Microsoft.Quantum.QsCompiler.DataTypes.Range; + +#nullable enable + +namespace Microsoft.Quantum.Documentation +{ + internal interface IAttributeBuilder + { + public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute); + public QsNullable Location { get; } + + public T Build(); + } + + internal class Callable : IAttributeBuilder + { + private QsCallable callable; + internal Callable(QsCallable callable) + { + this.callable = callable; + } + + public QsNullable Location => callable.Location; + + public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute) => + new Callable(callable.AddAttribute(attribute)); + + public QsCallable Build() => callable; + } + + internal class Udt : IAttributeBuilder + { + private QsCustomType type; + internal Udt(QsCustomType type) + { + this.type = type; + } + + public QsNullable Location => type.Location; + + public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute) => + new Udt(type.AddAttribute(attribute)); + + public QsCustomType Build() => type; + } + + internal static class Extensions + { + internal static IAttributeBuilder AttributeBuilder( + this QsCallable callable + ) => new Callable(callable); + internal static IAttributeBuilder AttributeBuilder( + this QsCustomType type + ) => new Udt(type); + + internal static IAttributeBuilder WithAttribute( + this IAttributeBuilder builder, string @namespace, string name, + TypedExpression input + ) => + builder.AddAttribute( + new QsDeclarationAttribute( + QsNullable.NewValue( + new UserDefinedType( + NonNullable.New(@namespace), + NonNullable.New(name), + QsNullable.Null + ) + ), + input, + builder.Location.Item.Offset, + QsComments.Empty + ) + ); + + private static IAttributeBuilder WithDocumentationAttribute( + this IAttributeBuilder builder, string attributeName, + TypedExpression input + ) => builder.WithAttribute("Microsoft.Quantum.Documentation", attributeName, input); + + private static TypedExpression AsLiteralExpression(this string literal) => + SyntaxGenerator.StringLiteral( + NonNullable.New(literal), + ImmutableArray.Empty + ); + + internal static IAttributeBuilder MaybeWithSimpleDocumentationAttribute( + this IAttributeBuilder builder, string attributeName, string? value + ) => + value == null || value.Trim().Length == 0 + ? builder + : builder.WithDocumentationAttribute( + attributeName, value.AsLiteralExpression() + ); + + internal static IAttributeBuilder WithListOfDocumentationAttributes( + this IAttributeBuilder builder, string attributeName, IEnumerable items + ) => + items + .Aggregate( + builder, + (acc, item) => acc.WithDocumentationAttribute( + attributeName, item.AsLiteralExpression() + ) + ); + + internal static IAttributeBuilder WithDocumentationAttributesFromDictionary( + this IAttributeBuilder builder, string attributeName, IDictionary items + ) => + items + .Aggregate( + builder, + (acc, item) => acc.WithDocumentationAttribute( + attributeName, + // The following populates all of the metadata needed for a + // Q# literal of type (String, String). + new TypedExpression( + QsExpressionKind.NewValueTuple( + ImmutableArray.Create( + item.Key.AsLiteralExpression(), + item.Value.AsLiteralExpression() + ) + ), + ImmutableArray, ResolvedType>>.Empty, + ResolvedType.New( + QsTypeKind.NewTupleType( + ImmutableArray.Create( + ResolvedType.New(QsTypeKind.String), + ResolvedType.New(QsTypeKind.String) + ) + ) + ), + new InferredExpressionInformation(false, false), + QsNullable.Null + ) + ) + ); + + internal static string ToSyntax(this ResolvedType type) => + SyntaxTreeToQsharp.Default.ToCode(type); + + internal static string ToSyntax(this QsTypeItem item) => + item switch + { + QsTypeItem.Anonymous anon => anon.Item.ToSyntax(), + QsTypeItem.Named named => $"{named.Item.VariableName.Value} : {named.Item.Type.ToSyntax()}" + }; + + internal static string ToSyntax(this QsTuple items) => + items switch + { + QsTuple.QsTuple tuple => $@"({ + String.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) + })", + QsTuple.QsTupleItem item => item.Item.ToSyntax() + }; + + internal static string ToSyntax(this QsTuple> items) => + items switch + { + QsTuple>.QsTuple tuple => $@"({ + String.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) + })", + QsTuple>.QsTupleItem item => item.Item.ToSyntax() + }; + + internal static string ToSyntax(this LocalVariableDeclaration symbol) => + $@"{symbol.VariableName switch + { + QsLocalSymbol.ValidName name => name.Item.Value, + _ => "{{invalid}}" + }} : {symbol.Type.ToSyntax()}"; + + internal static string ToSyntax(this QsCustomType type) => + $@"newtype {type.FullName.Name.Value} = { + String.Join(",", type.TypeItems.ToSyntax()) + };"; + + internal static string ToSyntax(this ResolvedCharacteristics characteristics) => + characteristics.SupportedFunctors.ValueOr(null) switch + { + null => "", + { Count: 0 } => "", + var functors => $@" is {String.Join(" + ", + functors.Select(functor => functor.Tag switch + { + QsFunctor.Tags.Adjoint => "Adj", + QsFunctor.Tags.Controlled => "Ctl" + }) + )}" + }; + + internal static string ToSyntax(this QsCallable callable) + { + var kind = callable.Kind.Tag switch + { + QsCallableKind.Tags.Function => "function", + QsCallableKind.Tags.Operation => "operation", + QsCallableKind.Tags.TypeConstructor => "function" + }; + var modifiers = callable.Modifiers.Access.Tag switch + { + AccessModifier.Tags.DefaultAccess => "", + AccessModifier.Tags.Internal => "internal " + }; + var typeParameters = callable.Signature.TypeParameters switch + { + { Length: 0 } => "", + var typeParams => $@"<{ + String.Join(", ", typeParams.Select( + param => param switch + { + QsLocalSymbol.ValidName name => $"'{name.Item.Value}", + _ => "{invalid}" + } + )) + }>" + }; + var input = callable.ArgumentTuple.ToSyntax(); + var output = callable.Signature.ReturnType.ToSyntax(); + var characteristics = callable.Signature.Information.Characteristics.ToSyntax(); + return $"{modifiers}{kind} {callable.FullName.Name.Value}{typeParameters}{input} : {output}{characteristics}"; + } + + internal static string MaybeWithSection(this string document, string name, string? contents) => + contents == null || contents.Trim().Length == 0 + ? document + : $"{document}\n\n## {name}\n\n{contents}"; + + internal static string WithYamlHeader(this string document, object header) => + $"---\n{new SerializerBuilder().Build().Serialize(header)}---\n{document}"; + } + +} diff --git a/src/DocumentationGenerator/ProcessDocComments.cs b/src/DocumentationGenerator/ProcessDocComments.cs new file mode 100644 index 0000000000..5520c3bcc4 --- /dev/null +++ b/src/DocumentationGenerator/ProcessDocComments.cs @@ -0,0 +1,230 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Quantum.QsCompiler; +using Microsoft.Quantum.QsCompiler.DataTypes; +using Microsoft.Quantum.QsCompiler.Documentation; +using Microsoft.Quantum.QsCompiler.SyntaxTokens; +using Microsoft.Quantum.QsCompiler.SyntaxTree; +using Microsoft.Quantum.QsCompiler.Transformations.Core; +using Newtonsoft.Json.Linq; + +using Range = Microsoft.Quantum.QsCompiler.DataTypes.Range; + +#nullable enable + +namespace Microsoft.Quantum.Documentation +{ + public class ProcessDocComments + : SyntaxTreeTransformation + { + public class TransformationState + { } + + private string? OutputPath; + + public ProcessDocComments( + string? outputPath = null + ) + : base(new TransformationState()) + { + OutputPath = outputPath; + // If the output path is not null, make sure the directory exists. + if (outputPath != null && !Directory.Exists(outputPath)) + { + Directory.CreateDirectory(outputPath); + } + + // We provide our own custom namespace transformation, and expression kind transformation. + this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, outputPath); + } + + public QsCompilation OnCompilation(QsCompilation compilation) => + new QsCompilation( + compilation.Namespaces + .Select(this.Namespaces.OnNamespace) + .ToImmutableArray(), + compilation.EntryPoints + ); + + private class NamespaceTransformation + : NamespaceTransformation + { + private string? outputPath; + internal NamespaceTransformation(ProcessDocComments parent, string? outputPath) + : base(parent) + { this.outputPath = outputPath; } + + private static QsCallable AddSummaryAttribute(QsCallable callable, string summary) => + callable.AddAttribute( + new QsDeclarationAttribute( + QsNullable.NewValue( + new UserDefinedType( + NonNullable.New("Microsoft.Quantum.Documentation"), + NonNullable.New("Summary"), + QsNullable.Null + ) + ), + SyntaxGenerator.StringLiteral(NonNullable.New(summary), ImmutableArray.Empty), + callable.Location.Item.Offset, + QsComments.Empty + ) + ); + + private async Task MaybeWriteOutput(QsCustomType type, DocComment docComment) + { + if (outputPath == null) return; + + // Make a new Markdown document for the type declaration. + var title = $"{type.FullName.Name.Value} user defined type"; + var header = new Dictionary + { + ["uid"] = type.FullName.ToString(), + ["title"] = title, + ["ms.date"] = DateTime.Today.ToString(), + ["ms.topic"] = "article" + }; + var document = $@" +Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) + +# {title} + +{docComment.Summary} + +```Q# +{type.ToSyntax()} +``` + +" + .MaybeWithSection("Description", docComment.Description) + .MaybeWithSection("Remarks", docComment.Remarks) + .MaybeWithSection("References", docComment.References) + .MaybeWithSection( + "See Also", + String.Join("\n", docComment.SeeAlso.Select( + seeAlso => $"- {seeAlso}" + )) + ) + .WithYamlHeader(header); + + // Open a file to write the new doc to. + await File.WriteAllTextAsync( + Path.Join(outputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), + document + ); + } + + private async Task MaybeWriteOutput(QsCallable callable, DocComment docComment) + { + if (outputPath == null) return; + + // Make a new Markdown document for the type declaration. + var title = $@"{callable.FullName.Name.Value} { + callable.Kind.Tag switch + { + QsCallableKind.Tags.Function => "function", + QsCallableKind.Tags.Operation => "operation", + QsCallableKind.Tags.TypeConstructor => "type constructor" + } + }"; + var header = new Dictionary + { + ["uid"] = callable.FullName.ToString(), + ["title"] = title, + ["ms.date"] = DateTime.Today.ToString(), + ["ms.topic"] = "article" + }; + var document = $@" +Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) + +# {title} + +{docComment.Summary} + +```Q# +{callable.ToSyntax()} +``` +" + .MaybeWithSection("Description", docComment.Description) + .MaybeWithSection("Remarks", docComment.Remarks) + .MaybeWithSection("References", docComment.References) + .MaybeWithSection( + "See Also", + String.Join("\n", docComment.SeeAlso.Select( + seeAlso => $"- {seeAlso}" + )) + ) + .MaybeWithSection( + "Input", + String.Join("\n", docComment.Input.Select( + item => $"### {item.Key}\n\n{item.Value}\n\n" + )) + ) + .MaybeWithSection("Output", docComment.Output) + .MaybeWithSection("Type Parameters", + String.Join("\n", docComment.TypeParameters.Select( + item => $"### {item.Key}\n\n{item.Value}\n\n" + )) + ) + .WithYamlHeader(header); + + // Open a file to write the new doc to. + await File.WriteAllTextAsync( + Path.Join(outputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), + document + ); + } + + public override QsCustomType OnTypeDeclaration(QsCustomType type) + { + type = base.OnTypeDeclaration(type); + var docComment = new DocComment( + type.Documentation, type.FullName.Name.Value, + deprecated: false, // FIXME: support deprecated attributes + replacement: null // FIXME + ); + + MaybeWriteOutput(type, docComment).Wait(); + + return type + .AttributeBuilder() + .MaybeWithSimpleDocumentationAttribute("Summary", docComment.Summary) + .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description) + .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks) + .MaybeWithSimpleDocumentationAttribute("References", docComment.References) + .WithListOfDocumentationAttributes("See Also", docComment.SeeAlso) + .Build(); + } + + public override QsCallable OnCallableDeclaration(QsCallable callable) + { + callable = base.OnCallableDeclaration(callable); + var docComment = new DocComment( + callable.Documentation, callable.FullName.Name.Value, + deprecated: false, // FIXME: support deprecated attributes + replacement: null // FIXME + ); + + MaybeWriteOutput(callable, docComment).Wait(); + + return callable + .AttributeBuilder() + .MaybeWithSimpleDocumentationAttribute("Summary", docComment.Summary) + .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description) + .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks) + .MaybeWithSimpleDocumentationAttribute("References", docComment.References) + .WithListOfDocumentationAttributes("See Also", docComment.SeeAlso) + .MaybeWithSimpleDocumentationAttribute("Output", docComment.Output) + .WithDocumentationAttributesFromDictionary("Input", docComment.Input) + .WithDocumentationAttributesFromDictionary("TypeParameter", docComment.TypeParameters) + .Build(); + } + } + } +} From c606d67f349e3835eee9799d66b8adb9911009b1 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 00:19:57 -0700 Subject: [PATCH 05/74] Add to solution and pack. --- QsCompiler.sln | 19 ++++++++++++++++++- build/pack.ps1 | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/QsCompiler.sln b/QsCompiler.sln index 3a192b074e..2a94cd82b8 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28809.33 MinimumVisualStudioVersion = 10.0.40219.1 @@ -46,6 +46,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B4A9484D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library2", "src\QsCompiler\TestTargets\Libraries\Library2\Library2.csproj", "{E7E019AB-42F8-48AB-B80C-D33351F2C96A}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A4A3C7BF-19AD-4916-A4D8-6572C1A11AFC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentationGenerator", "src\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -272,6 +276,18 @@ Global {E7E019AB-42F8-48AB-B80C-D33351F2C96A}.Release|x64.Build.0 = Release|Any CPU {E7E019AB-42F8-48AB-B80C-D33351F2C96A}.Release|x86.ActiveCfg = Release|Any CPU {E7E019AB-42F8-48AB-B80C-D33351F2C96A}.Release|x86.Build.0 = Release|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Debug|x64.ActiveCfg = Debug|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Debug|x64.Build.0 = Debug|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Debug|x86.ActiveCfg = Debug|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Debug|x86.Build.0 = Debug|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Release|Any CPU.Build.0 = Release|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Release|x64.ActiveCfg = Release|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Release|x64.Build.0 = Release|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Release|x86.ActiveCfg = Release|Any CPU + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -286,6 +302,7 @@ Global {D2E36476-A65F-4310-9C4C-B721BCC47B00} = {6077A717-50BF-4F87-B439-CA549AF6A4AE} {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} {E7E019AB-42F8-48AB-B80C-D33351F2C96A} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} + {11311F0C-78CA-43A3-9C84-D7EA0AE9748C} = {A4A3C7BF-19AD-4916-A4D8-6572C1A11AFC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B921C36B-4574-4025-8FE3-E5BD2D3D2B81} diff --git a/build/pack.ps1 b/build/pack.ps1 index fdf7526fe9..b3f468bace 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -213,6 +213,7 @@ Publish-One '../src/QuantumSdk/Tools/BuildConfiguration/BuildConfiguration.cspro Pack-One '../src/QsCompiler/Compiler/Compiler.csproj' '-IncludeReferencedProjects' Pack-One '../src/QsCompiler/CommandLineTool/CommandLineTool.csproj' '-IncludeReferencedProjects' +Pack-One '../src/DocumentationGenerator/DocumentationGenerator.csproj' '-IncludeReferencedProjects' Pack-One '../src/ProjectTemplates/Microsoft.Quantum.ProjectTemplates.nuspec' Pack-One '../src/QuantumSdk/QuantumSdk.nuspec' From b48148ee1d8f420530f573100c7c60f6ad16f766 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 00:28:27 -0700 Subject: [PATCH 06/74] Add rest of assemblies to manifest. --- build/manifest.ps1 | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 341ba6efbc..396227b99b 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -6,6 +6,22 @@ & "$PSScriptRoot/set-env.ps1" +if ("$Env:ENABLE_VSIX" -ne "false") { + $VsixAssemblies = @( + "./src/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompilationManager.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCore.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDataStructures.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsLanguageServer.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsSyntaxProcessor.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTextProcessor.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll" + "./src/VisualStudioExtension/QsharpVSIX/bin/$Env:BUILD_CONFIGURATION/Microsoft.Quantum.VisualStudio.Extension.dll" + ); +} else { + $VsixAssemblies = @(); +} + @{ Packages = @( "Microsoft.Quantum.Compiler", @@ -14,14 +30,11 @@ "Microsoft.Quantum.Sdk", "Microsoft.Quantum.DocumentationGenerator" ); - Assemblies = @( + Assemblies = $VsixAssemblies + @( "./src/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompilationManager.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCore.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDataStructures.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsLanguageServer.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsSyntaxProcessor.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTextProcessor.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll" + "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompiler.dll", + "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDocumentationParser.dll", + "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/qsc.dll", + "./src/QuantumSdk/Tools/BuildConfiguration/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/publish/Microsoft.Quantum.Sdk.BuildConfiguration.dll" ) | ForEach-Object { Get-Item (Join-Path $PSScriptRoot ".." $_) }; } | Write-Output; From 4f30e9faa9a9fe9901c9687c4495b6d263ed3367 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 08:39:10 -0700 Subject: [PATCH 07/74] Fix signing step. --- QsCompiler.sln | 2 +- build/manifest.ps1 | 2 +- build/pack.ps1 | 2 +- src/{ => QsCompiler}/DocumentationGenerator/DocgenStep.cs | 0 .../DocumentationGenerator/DocumentationGenerator.csproj | 0 src/{ => QsCompiler}/DocumentationGenerator/Extensions.cs | 0 .../DocumentationGenerator/ProcessDocComments.cs | 0 7 files changed, 3 insertions(+), 3 deletions(-) rename src/{ => QsCompiler}/DocumentationGenerator/DocgenStep.cs (100%) rename src/{ => QsCompiler}/DocumentationGenerator/DocumentationGenerator.csproj (100%) rename src/{ => QsCompiler}/DocumentationGenerator/Extensions.cs (100%) rename src/{ => QsCompiler}/DocumentationGenerator/ProcessDocComments.cs (100%) diff --git a/QsCompiler.sln b/QsCompiler.sln index 2a94cd82b8..5acb4ebf89 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -48,7 +48,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library2", "src\QsCompiler\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A4A3C7BF-19AD-4916-A4D8-6572C1A11AFC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentationGenerator", "src\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentationGenerator", "src\QsCompiler\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 396227b99b..7fbc65cee1 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -8,7 +8,7 @@ if ("$Env:ENABLE_VSIX" -ne "false") { $VsixAssemblies = @( - "./src/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", + "./src/QsCompiler/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompilationManager.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCore.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDataStructures.dll", diff --git a/build/pack.ps1 b/build/pack.ps1 index b3f468bace..e51e781bb9 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -213,7 +213,7 @@ Publish-One '../src/QuantumSdk/Tools/BuildConfiguration/BuildConfiguration.cspro Pack-One '../src/QsCompiler/Compiler/Compiler.csproj' '-IncludeReferencedProjects' Pack-One '../src/QsCompiler/CommandLineTool/CommandLineTool.csproj' '-IncludeReferencedProjects' -Pack-One '../src/DocumentationGenerator/DocumentationGenerator.csproj' '-IncludeReferencedProjects' +Pack-One '../src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj' '-IncludeReferencedProjects' Pack-One '../src/ProjectTemplates/Microsoft.Quantum.ProjectTemplates.nuspec' Pack-One '../src/QuantumSdk/QuantumSdk.nuspec' diff --git a/src/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs similarity index 100% rename from src/DocumentationGenerator/DocgenStep.cs rename to src/QsCompiler/DocumentationGenerator/DocgenStep.cs diff --git a/src/DocumentationGenerator/DocumentationGenerator.csproj b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj similarity index 100% rename from src/DocumentationGenerator/DocumentationGenerator.csproj rename to src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj diff --git a/src/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs similarity index 100% rename from src/DocumentationGenerator/Extensions.cs rename to src/QsCompiler/DocumentationGenerator/Extensions.cs diff --git a/src/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs similarity index 100% rename from src/DocumentationGenerator/ProcessDocComments.cs rename to src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs From a45e74c09ec72d8c12ac4821e2f06772be2763df Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 10:03:29 -0700 Subject: [PATCH 08/74] Fix paths in documentation generator. --- .../DocumentationGenerator/DocumentationGenerator.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj index 0f190d69ac..28f2f16c71 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj @@ -1,5 +1,5 @@ - + netstandard2.1 @@ -19,11 +19,11 @@ - + - + From a280145bd44f6f6774c8dc67a48c4fbeb1d5457b Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 10:09:46 -0700 Subject: [PATCH 09/74] Fix manifest. --- build/manifest.ps1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 7fbc65cee1..3744c7e9f2 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -6,9 +6,8 @@ & "$PSScriptRoot/set-env.ps1" -if ("$Env:ENABLE_VSIX" -ne "false") { +if ("$Env:ENABLE_VSIX" -eq "true") { $VsixAssemblies = @( - "./src/QsCompiler/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompilationManager.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCore.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDataStructures.dll", @@ -31,7 +30,7 @@ if ("$Env:ENABLE_VSIX" -ne "false") { "Microsoft.Quantum.DocumentationGenerator" ); Assemblies = $VsixAssemblies + @( - "./src/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.DocumentationGenerator.dll", + "./src/QsCompiler/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netstandard2.1/Microsoft.Quantum.DocumentationGenerator.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompiler.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDocumentationParser.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/qsc.dll", From 9b03857882ac9a6db453def6d39b7981309e0129 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 10:38:43 -0700 Subject: [PATCH 10/74] Fix manifest again. --- build/manifest.ps1 | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 3744c7e9f2..609d107698 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -6,7 +6,9 @@ & "$PSScriptRoot/set-env.ps1" -if ("$Env:ENABLE_VSIX" -eq "true") { +if ($Env:ENABLE_VSIX -ne "false") { + # The language server is only built if either the VS2019 or VS Code extension + # is enabled. $VsixAssemblies = @( "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompilationManager.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCore.dll", @@ -14,13 +16,20 @@ if ("$Env:ENABLE_VSIX" -eq "true") { "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsLanguageServer.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsSyntaxProcessor.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTextProcessor.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll" - "./src/VisualStudioExtension/QsharpVSIX/bin/$Env:BUILD_CONFIGURATION/Microsoft.Quantum.VisualStudio.Extension.dll" + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll", ); + + # The VS2019 extension itself is only built if msbuild is present. + if (Get-Command msbuild -ErrorAction SilentlyContinue) { + $VsixAssemblies += @( + "./src/VisualStudioExtension/QsharpVSIX/bin/$Env:BUILD_CONFIGURATION/Microsoft.Quantum.VisualStudio.Extension.dll" + ); + } } else { $VsixAssemblies = @(); } + @{ Packages = @( "Microsoft.Quantum.Compiler", From f8f5c4a7daccf3da5617a5123906e7e778e123d7 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 11:14:32 -0700 Subject: [PATCH 11/74] Fix error in manifest. --- build/manifest.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 609d107698..758c89465e 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -16,7 +16,7 @@ if ($Env:ENABLE_VSIX -ne "false") { "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsLanguageServer.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsSyntaxProcessor.dll", "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTextProcessor.dll", - "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll", + "./src/QsCompiler/LanguageServer/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsTransformations.dll" ); # The VS2019 extension itself is only built if msbuild is present. From 065ad1464657fdd7d7277229b8fb6373b7a39ee4 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 11:14:52 -0700 Subject: [PATCH 12/74] Start supporting deprecated attributes. --- .../DocumentationGenerator/Extensions.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index ab7bbb8ff3..075ba198fc 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.Quantum.QsCompiler; using Microsoft.Quantum.QsCompiler.DataTypes; @@ -242,6 +244,43 @@ internal static string MaybeWithSection(this string document, string name, strin internal static string WithYamlHeader(this string document, object header) => $"---\n{new SerializerBuilder().Build().Serialize(header)}---\n{document}"; + + internal static bool IsDeprecated(this QsCallable callable, out string? replacement) => + callable.Attributes.IsDeprecated(out replacement); + + internal static bool IsDeprecated(this QsCustomType type, out string? replacement) => + type.Attributes.IsDeprecated(out replacement); + + internal static bool IsDeprecated(this IEnumerable attributes, [NotNullWhen(true)] out string? replacement) + { + var deprecationAttribute = attributes.SingleOrDefault(attribute => + { + if (attribute.TypeId.IsValue) + { + var attrType = attribute.TypeId.Item; + if (attrType.Namespace.Value == "Microsoft.Quantum.Core" && attrType.Name.Value == "Deprecated") + { + return true; + } + } + + return false; + }); + + if (deprecationAttribute == null) + { + replacement = null; + return false; + } + else + { + var arg = deprecationAttribute.Argument.Expression as QsExpressionKind.StringLiteral; + Debug.Assert(arg != null, "Argument to deprecated attribute was not a string literal."); + replacement = arg.Item1.Value; + return true; + } + + } } } From 6fd7c5ae6b0127dae04fe09c17726942b435f5b8 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 11:47:03 -0700 Subject: [PATCH 13/74] One more manifest fix. --- build/manifest.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 758c89465e..f9e97b7321 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -43,6 +43,6 @@ if ($Env:ENABLE_VSIX -ne "false") { "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompiler.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDocumentationParser.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/qsc.dll", - "./src/QuantumSdk/Tools/BuildConfiguration/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/publish/Microsoft.Quantum.Sdk.BuildConfiguration.dll" + "./src/QuantumSdk/Tools/$Env:BUILD_CONFIGURATION/bin/Release/netcoreapp3.1/Microsoft.Quantum.Sdk.BuildConfiguration.dll" ) | ForEach-Object { Get-Item (Join-Path $PSScriptRoot ".." $_) }; } | Write-Output; From 89f4e54ef7737e48dab62e771587c9e61714bb08 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 11:47:15 -0700 Subject: [PATCH 14/74] Remove dead code. --- .../ProcessDocComments.cs | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 5520c3bcc4..0a9106b921 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -61,22 +61,6 @@ internal NamespaceTransformation(ProcessDocComments parent, string? outputPath) : base(parent) { this.outputPath = outputPath; } - private static QsCallable AddSummaryAttribute(QsCallable callable, string summary) => - callable.AddAttribute( - new QsDeclarationAttribute( - QsNullable.NewValue( - new UserDefinedType( - NonNullable.New("Microsoft.Quantum.Documentation"), - NonNullable.New("Summary"), - QsNullable.Null - ) - ), - SyntaxGenerator.StringLiteral(NonNullable.New(summary), ImmutableArray.Empty), - callable.Location.Item.Offset, - QsComments.Empty - ) - ); - private async Task MaybeWriteOutput(QsCustomType type, DocComment docComment) { if (outputPath == null) return; @@ -184,10 +168,16 @@ await File.WriteAllTextAsync( public override QsCustomType OnTypeDeclaration(QsCustomType type) { type = base.OnTypeDeclaration(type); + // If the UDT didn't come from a Q# source file, then it + // came in from a reference, and shouldn't be documented in this + // project. + if (!type.SourceFile.Value.EndsWith(".qs")) return type; + + var isDeprecated = type.IsDeprecated(out var replacement); var docComment = new DocComment( type.Documentation, type.FullName.Name.Value, - deprecated: false, // FIXME: support deprecated attributes - replacement: null // FIXME + deprecated: isDeprecated, + replacement: replacement ); MaybeWriteOutput(type, docComment).Wait(); @@ -205,10 +195,16 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) public override QsCallable OnCallableDeclaration(QsCallable callable) { callable = base.OnCallableDeclaration(callable); + // If the callable didn't come from a Q# source file, then it + // came in from a reference, and shouldn't be documented in this + // project. + if (!callable.SourceFile.Value.EndsWith(".qs")) return callable; + + var isDeprecated = callable.IsDeprecated(out var replacement); var docComment = new DocComment( callable.Documentation, callable.FullName.Name.Value, - deprecated: false, // FIXME: support deprecated attributes - replacement: null // FIXME + deprecated: isDeprecated, + replacement: replacement ); MaybeWriteOutput(callable, docComment).Wait(); From 9e4863c92fa76eb3938ff4d3ed101d46369bbfa9 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 11:47:25 -0700 Subject: [PATCH 15/74] Begin nullable enable for doccomment. --- src/QsCompiler/DocumentationParser/DocComment.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/DocumentationParser/DocComment.cs b/src/QsCompiler/DocumentationParser/DocComment.cs index 32f2cbad71..5ea8a52650 100644 --- a/src/QsCompiler/DocumentationParser/DocComment.cs +++ b/src/QsCompiler/DocumentationParser/DocComment.cs @@ -1,6 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#nullable enable + using System; using System.Collections.Generic; using System.IO; @@ -99,7 +101,7 @@ public class DocComment /// The name of the element /// Flag indicating whether or not the element had a Deprecated attribute /// The name of the replacement element for deprecated elements, if given - public DocComment(IEnumerable docComments, string name, bool deprecated, string replacement) + public DocComment(IEnumerable docComments, string name, bool deprecated, string? replacement) { static string GetHeadingText(HeadingBlock heading) { From 44842756bf9255cd394b32a803960ca2bd3a309f Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 13:25:10 -0700 Subject: [PATCH 16/74] One more manifest fix. --- build/build.ps1 | 6 ++++-- build/manifest.ps1 | 2 +- build/pack.ps1 | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/build/build.ps1 b/build/build.ps1 index b94d461ba8..a9d5ce10e3 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -121,8 +121,10 @@ if ($Env:ENABLE_VSIX -ne "false") { Write-Host "##vso[task.logissue type=warning;]VSIX building skipped due to ENABLE_VSIX variable." } -Write-Host "##[info]Verifying manifest..." -& (Join-Path $PSScriptRoot "manifest.ps1") +# NB: In other repos, we check the manifest here. That can cause problems +# in our case, however, as some assemblies are only produced during +# packing and publishing. Thus, as an exception, we verify the manifest +# only in pack.ps1. if (-not $all_ok) { throw "Building failed. Check the logs." diff --git a/build/manifest.ps1 b/build/manifest.ps1 index f9e97b7321..c92d4ee016 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -43,6 +43,6 @@ if ($Env:ENABLE_VSIX -ne "false") { "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompiler.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDocumentationParser.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/qsc.dll", - "./src/QuantumSdk/Tools/$Env:BUILD_CONFIGURATION/bin/Release/netcoreapp3.1/Microsoft.Quantum.Sdk.BuildConfiguration.dll" + "./src/QuantumSdk/Tools/BuildConfiguration/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/publish/Microsoft.Quantum.Sdk.BuildConfiguration.dll" ) | ForEach-Object { Get-Item (Join-Path $PSScriptRoot ".." $_) }; } | Write-Output; diff --git a/build/pack.ps1 b/build/pack.ps1 index e51e781bb9..4d27e7cac9 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -231,6 +231,9 @@ if ($Env:ENABLE_VSIX -ne "false") { Write-Host "##vso[task.logissue type=warning;]VSIX packing skipped due to ENABLE_VSIX variable." } +Write-Host "##[info]Verifying manifest..." +& (Join-Path $PSScriptRoot "manifest.ps1") + if (-not $all_ok) { throw "Packing failed. Check the logs." exit 1 From 342c2fcfb084e6e0ac63bc0ec66bb8eaea59d228 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 13:25:24 -0700 Subject: [PATCH 17/74] Support examples and named items as attributes. --- .../ProcessDocComments.cs | 9 ++- .../DocumentationParser/DocComment.cs | 69 ++++++++++++------- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 0a9106b921..2b4e7f2611 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -188,7 +188,9 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description) .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks) .MaybeWithSimpleDocumentationAttribute("References", docComment.References) - .WithListOfDocumentationAttributes("See Also", docComment.SeeAlso) + .WithListOfDocumentationAttributes("SeeAlso", docComment.SeeAlso) + .WithListOfDocumentationAttributes("Example", docComment.Examples) + .WithDocumentationAttributesFromDictionary("NamedItem", docComment.NamedItems) .Build(); } @@ -215,9 +217,10 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description) .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks) .MaybeWithSimpleDocumentationAttribute("References", docComment.References) - .WithListOfDocumentationAttributes("See Also", docComment.SeeAlso) - .MaybeWithSimpleDocumentationAttribute("Output", docComment.Output) + .WithListOfDocumentationAttributes("SeeAlso", docComment.SeeAlso) + .WithListOfDocumentationAttributes("Example", docComment.Examples) .WithDocumentationAttributesFromDictionary("Input", docComment.Input) + .MaybeWithSimpleDocumentationAttribute("Output", docComment.Output) .WithDocumentationAttributesFromDictionary("TypeParameter", docComment.TypeParameters) .Build(); } diff --git a/src/QsCompiler/DocumentationParser/DocComment.cs b/src/QsCompiler/DocumentationParser/DocComment.cs index 5ea8a52650..8b789cd109 100644 --- a/src/QsCompiler/DocumentationParser/DocComment.cs +++ b/src/QsCompiler/DocumentationParser/DocComment.cs @@ -4,7 +4,9 @@ #nullable enable using System; +using System.Linq; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; @@ -28,20 +30,20 @@ public class DocComment /// The summary description of the item. /// This should be one paragraph of plain text. /// - public string Summary { get; private set; } + public string Summary { get; private set; } = ""; /// /// The (rest of the) full description of the item. /// This should not duplicate the summary, but rather follow it. /// - public string Description { get; private set; } + public string Description { get; private set; } = ""; /// /// The short hover information for the item. /// This should be one paragraph of plain text. /// Currently this is the first paragraph of the summary field. /// - public string ShortSummary { get; private set; } + public string ShortSummary { get; private set; } = ""; /// /// The full markdown-formatted hover information for the item. @@ -53,45 +55,69 @@ public class DocComment /// The full markdown-formatted on-line documentation for the item. /// Currently this consists of the summary field followed by the description field. /// - public string Documentation { get; private set; } + public string Documentation { get; private set; } = ""; /// /// The inputs to the item, as a list of symbol/description pairs. /// This is only populated for functions and operations. /// public Dictionary Input { get; private set; } + = new Dictionary(); /// /// The output from the item. /// This is only populated for functions and operations. /// - public string Output { get; private set; } + public string Output { get; private set; } = ""; /// /// The type parameters for the item, as a list of symbol/description pairs. /// This is only populated for functions and operations. /// - public Dictionary TypeParameters { get; private set; } + public Dictionary TypeParameters { get; private set; } = + new Dictionary(); /// - /// An example of using the item. + /// Descriptions of each named item for the item being documented, + /// as a dictionary from identifiers for each named item to the + /// corresponding description. /// - public string Example { get; private set; } + /// + /// Only applicable when the item being documented is a UDT. + /// + public Dictionary NamedItems { get; private set; } = + new Dictionary(); + + /// + /// All examples of using the named item, concatenated as a single Markdown + /// document. + /// + [Obsolete("Please use Examples instead.")] + public string Example => string.Join( + "\n\n", + this.Examples + ); + + /// + /// A list of examples of using the item. + /// + public ImmutableList Examples { get; private set; } = ImmutableList.Empty; /// /// Additional commentary about the item. /// - public string Remarks { get; private set; } + public string Remarks { get; private set; } = ""; /// /// A list of links to other documentation related to this item. /// - public List SeeAlso { get; private set; } + public List SeeAlso { get; private set; } = + new List(); /// /// Reference material about the item. /// - public string References { get; private set; } + public string References { get; private set; } = ""; /// /// Constructs a DocComment instance from the documentation comments @@ -246,18 +272,6 @@ static void ParseMapSection(IEnumerable blocks, Dictionary(); - this.Output = ""; - this.TypeParameters = new Dictionary(); - this.Example = ""; - this.Remarks = ""; - this.SeeAlso = new List(); - this.References = ""; - var deprecationSummary = string.IsNullOrWhiteSpace(replacement) ? DiagnosticItem.Message(WarningCode.DeprecationWithoutRedirect, new string[] { name }) : DiagnosticItem.Message(WarningCode.DeprecationWithRedirect, new string[] { name, "@\"" + replacement.ToLowerInvariant() + "\"" }); @@ -311,14 +325,17 @@ static void ParseMapSection(IEnumerable blocks, Dictionary 0 && this.Example == "") + if (examples.Count > 0 && this.Examples.IsEmpty) { - this.Example = ToMarkdown(examples); + this.Examples = this.Examples.Add(ToMarkdown(examples)); } this.Remarks = ToMarkdown(remarks); break; From 3830a57826b18204cecfca7986dcacbdacea321f Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 13:27:32 -0700 Subject: [PATCH 18/74] Add named items to Markdown output as well. --- src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 2b4e7f2611..f7e7aff6f9 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -86,6 +86,12 @@ private async Task MaybeWriteOutput(QsCustomType type, DocComment docComment) ``` " + .MaybeWithSection( + "Named Items", + String.Join("\n", docComment.NamedItems.Select( + item => $"### {item.Key}\n\n{item.Value}\n\n" + )) + ) .MaybeWithSection("Description", docComment.Description) .MaybeWithSection("Remarks", docComment.Remarks) .MaybeWithSection("References", docComment.References) From b56c07e215d86881525574efab21d0a35f1eec49 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 14:15:07 -0700 Subject: [PATCH 19/74] Add links to input kinds. --- .../DocumentationGenerator/Extensions.cs | 60 +++++++++++++++++++ .../ProcessDocComments.cs | 8 ++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index 075ba198fc..8ee553c821 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Quantum.QsCompiler; using Microsoft.Quantum.QsCompiler.DataTypes; using Microsoft.Quantum.QsCompiler.SyntaxTokens; @@ -15,6 +16,12 @@ using Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput; using YamlDotNet.Serialization; using Range = Microsoft.Quantum.QsCompiler.DataTypes.Range; +using ResolvedTypeKind = Microsoft.Quantum.QsCompiler.SyntaxTokens.QsTypeKind< + Microsoft.Quantum.QsCompiler.SyntaxTree.ResolvedType, + Microsoft.Quantum.QsCompiler.SyntaxTree.UserDefinedType, + Microsoft.Quantum.QsCompiler.SyntaxTree.QsTypeParameter, + Microsoft.Quantum.QsCompiler.SyntaxTree.CallableInformation +>; #nullable enable @@ -281,6 +288,59 @@ internal static bool IsDeprecated(this IEnumerable attri } } + + internal static Dictionary ToDictionaryOfDeclarations(this QsTuple> items) => + items.InputDeclarations().ToDictionary( + declaration => declaration.Item1, + declaration => declaration.Item2 + ); + + private static List<(string, ResolvedType)> InputDeclarations(this QsTuple> items) => items switch + { + QsTuple>.QsTuple tuple => + tuple.Item.SelectMany( + item => item.InputDeclarations() + ) + .ToList(), + QsTuple>.QsTupleItem item => + new List<(string, ResolvedType)> + { + ( + item.Item.VariableName switch + { + QsLocalSymbol.ValidName name => name.Item.Value, + _ => "__invalid__" + }, + item.Item.Type + ) + } + }; + + internal static string ToMarkdownLink(this ResolvedType type) => type.Resolution switch + { + ResolvedTypeKind.ArrayType array => $"{array.Item.ToMarkdownLink()}[]", + ResolvedTypeKind.Function function => + $"{function.Item1.ToMarkdownLink()} -> {function.Item2.ToMarkdownLink()}", + ResolvedTypeKind.Operation operation => "TODO", + ResolvedTypeKind.TupleType tuple => "TODO", + ResolvedTypeKind.UserDefinedType udt => udt.Item.ToMarkdownLink(), + _ => type.Resolution.Tag switch + { + ResolvedTypeKind.Tags.BigInt => "BigInt", + ResolvedTypeKind.Tags.Bool => "Bool", + ResolvedTypeKind.Tags.Double => "Double", + ResolvedTypeKind.Tags.Int => "Int", + ResolvedTypeKind.Tags.Pauli => "Pauli", + ResolvedTypeKind.Tags.Qubit => "Qubit", + ResolvedTypeKind.Tags.Range => "Range", + ResolvedTypeKind.Tags.String => "String", + ResolvedTypeKind.Tags.UnitType => "Unit", + _ => "__invalid__" + } + }; + + internal static string ToMarkdownLink(this UserDefinedType type) => + $"[{type.Name.Value}](xref:{type.Namespace.Value}.{type.Name.Value})"; } } diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index f7e7aff6f9..6a1e0663c7 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -114,6 +114,8 @@ private async Task MaybeWriteOutput(QsCallable callable, DocComment docComment) { if (outputPath == null) return; + var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); + // Make a new Markdown document for the type declaration. var title = $@"{callable.FullName.Name.Value} { callable.Kind.Tag switch @@ -153,7 +155,11 @@ private async Task MaybeWriteOutput(QsCallable callable, DocComment docComment) .MaybeWithSection( "Input", String.Join("\n", docComment.Input.Select( - item => $"### {item.Key}\n\n{item.Value}\n\n" + item => + { + var hasInput = inputDeclarations.TryGetValue(item.Key, out var inputType); + return $"### {item.Key}{(hasInput ? $" : {inputType.ToMarkdownLink()}" : "")}\n\n{item.Value}\n\n"; + } )) ) .MaybeWithSection("Output", docComment.Output) From 9c993f30e8462e146c596efb1d6835e6e107749c Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 27 Aug 2020 15:57:18 -0700 Subject: [PATCH 20/74] Use AttributeUtils. --- .../DocumentationGenerator/Extensions.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index 8ee553c821..15ae3ab775 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -12,6 +12,7 @@ using Microsoft.Quantum.QsCompiler.DataTypes; using Microsoft.Quantum.QsCompiler.SyntaxTokens; using Microsoft.Quantum.QsCompiler.SyntaxTree; +using Microsoft.Quantum.QsCompiler.Transformations; using Microsoft.Quantum.QsCompiler.Transformations.Core; using Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput; using YamlDotNet.Serialization; @@ -81,17 +82,12 @@ internal static IAttributeBuilder WithAttribute( TypedExpression input ) => builder.AddAttribute( - new QsDeclarationAttribute( - QsNullable.NewValue( - new UserDefinedType( - NonNullable.New(@namespace), - NonNullable.New(name), - QsNullable.Null - ) + AttributeUtils.BuildAttribute( + new QsQualifiedName( + NonNullable.New(@namespace), + NonNullable.New(name) ), - input, - builder.Location.Item.Offset, - QsComments.Empty + input ) ); From 238441a955883191ce5f2c4ee795764c8050a2f5 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 28 Aug 2020 10:40:01 -0700 Subject: [PATCH 21/74] Pack DocumentationGenerator with dotnet instead of nuget. --- build/pack.ps1 | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/build/pack.ps1 b/build/pack.ps1 index 4d27e7cac9..409b755d58 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -54,6 +54,30 @@ function Pack-One() { } } +function Pack-Dotnet() { + Param($project, $option1 = "", $option2 = "", $option3 = "") + if ("" -ne "$Env:ASSEMBLY_CONSTANTS") { + $args = @("/property:DefineConstants=$Env:ASSEMBLY_CONSTANTS"); + } else { + $args = @(); + } + dotnet pack (Join-Path $PSScriptRoot $project) ` + -o $Env:NUGET_OUTDIR ` + -c $Env:BUILD_CONFIGURATION ` + -v detailed ` + @args ` + /property:Version=$Env:ASSEMBLY_VERSION ` + /property:PackageVersion=$Env:NUGET_VERSION ` + $option1 ` + $option2 ` + $option3 + + if ($LastExitCode -ne 0) { + Write-Host "##vso[task.logissue type=error;]Failed to pack $project." + $script:all_ok = $False + } +} + ## # Q# Language Server (self-contained) ## @@ -213,7 +237,7 @@ Publish-One '../src/QuantumSdk/Tools/BuildConfiguration/BuildConfiguration.cspro Pack-One '../src/QsCompiler/Compiler/Compiler.csproj' '-IncludeReferencedProjects' Pack-One '../src/QsCompiler/CommandLineTool/CommandLineTool.csproj' '-IncludeReferencedProjects' -Pack-One '../src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj' '-IncludeReferencedProjects' +Pack-Dotnet '../src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj' Pack-One '../src/ProjectTemplates/Microsoft.Quantum.ProjectTemplates.nuspec' Pack-One '../src/QuantumSdk/QuantumSdk.nuspec' From 0592d02c86d5d4458cd513755f62a14fdfd1d82e Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 28 Aug 2020 15:16:38 -0700 Subject: [PATCH 22/74] Support adding types to named items. --- .../DocumentationGenerator/DocgenStep.cs | 3 + .../DocumentationWriter.cs | 168 ++++++++++++++++++ .../DocumentationGenerator/Extensions.cs | 25 +++ .../DocumentationParser/DocComment.cs | 2 +- 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs diff --git a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs index 182f8bbacf..cd6ec9fc8a 100644 --- a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs +++ b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs @@ -67,6 +67,9 @@ public bool Transformation(QsCompilation compilation, out QsCompilation transfor transformed = new ProcessDocComments( AssemblyConstants.TryGetValue("OutputPath", out var path) ? path + : null, + AssemblyConstants.TryGetValue("DocumentationPackageName", out var packageName) + ? packageName : null ).OnCompilation(compilation); return true; diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs new file mode 100644 index 0000000000..9c61c2b8a4 --- /dev/null +++ b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Linq; +using Microsoft.Quantum.QsCompiler; +using Microsoft.Quantum.QsCompiler.DataTypes; +using Microsoft.Quantum.QsCompiler.Documentation; +using Microsoft.Quantum.QsCompiler.SyntaxTokens; +using Microsoft.Quantum.QsCompiler.SyntaxTree; + +namespace Microsoft.Quantum.Documentation +{ + + public class DocumentationWriter + { + private readonly string outputPath; + public string OutputPath => outputPath; + + private readonly string? packageName; + public string? PackageName => packageName; + private readonly string PackageLink; + + public DocumentationWriter(string outputPath, string? packageName) + { + this.outputPath = outputPath; + this.packageName = packageName; + + // If the output path is not null, make sure the directory exists. + if (outputPath != null && !Directory.Exists(outputPath)) + { + Directory.CreateDirectory(outputPath); + } + + PackageLink = PackageName == null + ? "" + : $"Package: [{PackageName}](https://nuget.org/packages/{PackageName})\n"; + } + + public async Task WriteOutput(QsCustomType type, DocComment docComment) + { + var namedItemDeclarations = type.TypeItems.ToDictionaryOfDeclarations(); + // Make a new Markdown document for the type declaration. + var title = $"{type.FullName.Name.Value} user defined type"; + var header = new Dictionary + { + ["uid"] = type.FullName.ToString(), + ["title"] = title, + ["ms.date"] = DateTime.Today.ToString(), + ["ms.topic"] = "article" + }; + var document = $@" +Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) +{PackageLink} + +# {title} + +{docComment.Summary} + +```Q# +{type.ToSyntax()} +``` + +" + .MaybeWithSection( + "Named Items", + string.Join("\n", docComment.NamedItems.Select( + item => + { + var hasName = namedItemDeclarations.TryGetValue(item.Key, out var itemType); + return $"### {item.Key}{(hasName ? $" : {itemType.ToMarkdownLink()}" : "")}\n\n{item.Value}\n\n";; + } + )) + ) + .MaybeWithSection("Description", docComment.Description) + .MaybeWithSection("Remarks", docComment.Remarks) + .MaybeWithSection("References", docComment.References) + .MaybeWithSection( + "See Also", + string.Join("\n", docComment.SeeAlso.Select( + seeAlso => $"- {seeAlso}" + )) + ) + .WithYamlHeader(header); + + // Open a file to write the new doc to. + await File.WriteAllTextAsync( + Path.Join(outputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), + document + ); + } + + + + public async Task WriteOutput(QsCallable callable, DocComment docComment) + { + var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); + + // Make a new Markdown document for the type declaration. + var title = $@"{callable.FullName.Name.Value} { + callable.Kind.Tag switch + { + QsCallableKind.Tags.Function => "function", + QsCallableKind.Tags.Operation => "operation", + QsCallableKind.Tags.TypeConstructor => "type constructor" + } + }"; + var header = new Dictionary + { + ["uid"] = callable.FullName.ToString(), + ["title"] = title, + ["ms.date"] = DateTime.Today.ToString(), + ["ms.topic"] = "article" + }; + var document = $@" +Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) +{PackageLink} + +# {title} + +{docComment.Summary} + +```Q# +{callable.ToSyntax()} +``` +" + .MaybeWithSection("Description", docComment.Description) + .MaybeWithSection( + "Input", + String.Join("\n", docComment.Input.Select( + item => + { + var hasInput = inputDeclarations.TryGetValue(item.Key, out var inputType); + return $"### {item.Key}{(hasInput ? $" : {inputType.ToMarkdownLink()}" : "")}\n\n{item.Value}\n\n"; + } + )) + ) + .MaybeWithSection("Output", docComment.Output) + .MaybeWithSection("Type Parameters", + String.Join("\n", docComment.TypeParameters.Select( + item => $"### {item.Key}\n\n{item.Value}\n\n" + )) + ) + .MaybeWithSection("Remarks", docComment.Remarks) + .MaybeWithSection("References", docComment.References) + .MaybeWithSection( + "See Also", + String.Join("\n", docComment.SeeAlso.Select( + seeAlso => $"- [{seeAlso}](xref:{seeAlso})" + )) + ) + .WithYamlHeader(header); + + // Open a file to write the new doc to. + await File.WriteAllTextAsync( + Path.Join(outputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), + document + ); + } + + } + +} diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index 15ae3ab775..76bdd185fe 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -291,6 +291,31 @@ internal static Dictionary ToDictionaryOfDeclarations(this declaration => declaration.Item2 ); + internal static Dictionary ToDictionaryOfDeclarations(this QsTuple typeItems) => + typeItems.TypeDeclarations().ToDictionary( + declaration => declaration.Item1, + declaration => declaration.Item2 + ); + + private static List<(string, ResolvedType)> TypeDeclarations(this QsTuple typeItems) => typeItems switch + { + QsTuple.QsTuple tuple => + tuple.Item.SelectMany( + item => item.TypeDeclarations() + ) + .ToList(), + QsTuple.QsTupleItem item => item.Item switch + { + QsTypeItem.Anonymous _ => new List<(string, ResolvedType)>(), + QsTypeItem.Named named => + new List<(string, ResolvedType)> + {( + named.Item.VariableName.Value, + named.Item.Type + )} + } + }; + private static List<(string, ResolvedType)> InputDeclarations(this QsTuple> items) => items switch { QsTuple>.QsTuple tuple => diff --git a/src/QsCompiler/DocumentationParser/DocComment.cs b/src/QsCompiler/DocumentationParser/DocComment.cs index 8b789cd109..0cdada643e 100644 --- a/src/QsCompiler/DocumentationParser/DocComment.cs +++ b/src/QsCompiler/DocumentationParser/DocComment.cs @@ -342,7 +342,7 @@ static void ParseMapSection(IEnumerable blocks, Dictionary Date: Tue, 1 Sep 2020 13:54:52 -0700 Subject: [PATCH 23/74] Use new DocumentationWriter class. --- .../ProcessDocComments.cs | 142 ++---------------- 1 file changed, 12 insertions(+), 130 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 6a1e0663c7..35632f12b1 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -27,22 +27,20 @@ public class ProcessDocComments public class TransformationState { } - private string? OutputPath; + private readonly DocumentationWriter? writer; public ProcessDocComments( - string? outputPath = null + string? outputPath = null, + string? packageName = null ) : base(new TransformationState()) { - OutputPath = outputPath; - // If the output path is not null, make sure the directory exists. - if (outputPath != null && !Directory.Exists(outputPath)) - { - Directory.CreateDirectory(outputPath); - } + writer = outputPath == null + ? null + : new DocumentationWriter(outputPath, packageName); // We provide our own custom namespace transformation, and expression kind transformation. - this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, outputPath); + this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, writer); } public QsCompilation OnCompilation(QsCompilation compilation) => @@ -56,126 +54,10 @@ public QsCompilation OnCompilation(QsCompilation compilation) => private class NamespaceTransformation : NamespaceTransformation { - private string? outputPath; - internal NamespaceTransformation(ProcessDocComments parent, string? outputPath) + private DocumentationWriter? writer; + internal NamespaceTransformation(ProcessDocComments parent, DocumentationWriter? writer) : base(parent) - { this.outputPath = outputPath; } - - private async Task MaybeWriteOutput(QsCustomType type, DocComment docComment) - { - if (outputPath == null) return; - - // Make a new Markdown document for the type declaration. - var title = $"{type.FullName.Name.Value} user defined type"; - var header = new Dictionary - { - ["uid"] = type.FullName.ToString(), - ["title"] = title, - ["ms.date"] = DateTime.Today.ToString(), - ["ms.topic"] = "article" - }; - var document = $@" -Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) - -# {title} - -{docComment.Summary} - -```Q# -{type.ToSyntax()} -``` - -" - .MaybeWithSection( - "Named Items", - String.Join("\n", docComment.NamedItems.Select( - item => $"### {item.Key}\n\n{item.Value}\n\n" - )) - ) - .MaybeWithSection("Description", docComment.Description) - .MaybeWithSection("Remarks", docComment.Remarks) - .MaybeWithSection("References", docComment.References) - .MaybeWithSection( - "See Also", - String.Join("\n", docComment.SeeAlso.Select( - seeAlso => $"- {seeAlso}" - )) - ) - .WithYamlHeader(header); - - // Open a file to write the new doc to. - await File.WriteAllTextAsync( - Path.Join(outputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), - document - ); - } - - private async Task MaybeWriteOutput(QsCallable callable, DocComment docComment) - { - if (outputPath == null) return; - - var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); - - // Make a new Markdown document for the type declaration. - var title = $@"{callable.FullName.Name.Value} { - callable.Kind.Tag switch - { - QsCallableKind.Tags.Function => "function", - QsCallableKind.Tags.Operation => "operation", - QsCallableKind.Tags.TypeConstructor => "type constructor" - } - }"; - var header = new Dictionary - { - ["uid"] = callable.FullName.ToString(), - ["title"] = title, - ["ms.date"] = DateTime.Today.ToString(), - ["ms.topic"] = "article" - }; - var document = $@" -Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) - -# {title} - -{docComment.Summary} - -```Q# -{callable.ToSyntax()} -``` -" - .MaybeWithSection("Description", docComment.Description) - .MaybeWithSection("Remarks", docComment.Remarks) - .MaybeWithSection("References", docComment.References) - .MaybeWithSection( - "See Also", - String.Join("\n", docComment.SeeAlso.Select( - seeAlso => $"- {seeAlso}" - )) - ) - .MaybeWithSection( - "Input", - String.Join("\n", docComment.Input.Select( - item => - { - var hasInput = inputDeclarations.TryGetValue(item.Key, out var inputType); - return $"### {item.Key}{(hasInput ? $" : {inputType.ToMarkdownLink()}" : "")}\n\n{item.Value}\n\n"; - } - )) - ) - .MaybeWithSection("Output", docComment.Output) - .MaybeWithSection("Type Parameters", - String.Join("\n", docComment.TypeParameters.Select( - item => $"### {item.Key}\n\n{item.Value}\n\n" - )) - ) - .WithYamlHeader(header); - - // Open a file to write the new doc to. - await File.WriteAllTextAsync( - Path.Join(outputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), - document - ); - } + { this.writer = writer; } public override QsCustomType OnTypeDeclaration(QsCustomType type) { @@ -192,7 +74,7 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) replacement: replacement ); - MaybeWriteOutput(type, docComment).Wait(); + writer?.WriteOutput(type, docComment)?.Wait(); return type .AttributeBuilder() @@ -221,7 +103,7 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) replacement: replacement ); - MaybeWriteOutput(callable, docComment).Wait(); + writer?.WriteOutput(callable, docComment)?.Wait(); return callable .AttributeBuilder() From e85182923614859116baf05e6e72e54bed76cac2 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 1 Sep 2020 13:55:26 -0700 Subject: [PATCH 24/74] Add nuget.exe to devcontainer. --- .devcontainer/Dockerfile | 14 ++++++++++++++ .devcontainer/devcontainer.json | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..5c43e2c4de --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,14 @@ +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-focal + +# Mono is required to run pack.ps1, so we install it here. +RUN apt-get -y update && \ + apt-get -y install dirmngr gnupg apt-transport-https ca-certificates && \ + apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \ + sh -c 'echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" > /etc/apt/sources.list.d/mono-official-stable.list' && \ + apt-get -y update && \ + apt-get -y install mono-complete && \ + apt-get clean && rm -rf /var/lib/apt/lists/ +# We can now get Mono itself. +RUN curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe && \ + # Create as alias for nuget + echo "alias nuget=\"mono /usr/local/bin/nuget.exe\"" >> /root/.bash_aliases diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 73c8b18d65..499eadac33 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "image": "mcr.microsoft.com/dotnet/core/sdk:3.1-focal", + "dockerFile": "./Dockerfile", "extensions": [ "ms-dotnettools.csharp", "Ionide.Ionide-fsharp", From 8ade23ee6db2a1e079d5cd6d2b93a21e4723c89b Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 09:36:57 -0700 Subject: [PATCH 25/74] Add properties for new docgen package. --- src/QsCompiler/DocumentationGenerator/DocgenStep.cs | 4 ++-- .../DocumentationGenerator.csproj | 7 +++++++ .../DocumentationGenerator.props | 10 ++++++++++ src/QuantumSdk/Sdk/Sdk.targets | 2 ++ 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props diff --git a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs index cd6ec9fc8a..eb931f0c35 100644 --- a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs +++ b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs @@ -65,10 +65,10 @@ public bool PreconditionVerification(QsCompilation compilation) public bool Transformation(QsCompilation compilation, out QsCompilation transformed) { transformed = new ProcessDocComments( - AssemblyConstants.TryGetValue("OutputPath", out var path) + AssemblyConstants.TryGetValue("DocsOutputPath", out var path) ? path : null, - AssemblyConstants.TryGetValue("DocumentationPackageName", out var packageName) + AssemblyConstants.TryGetValue("PackageId", out var packageName) ? packageName : null ).OnCompilation(compilation); diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj index 28f2f16c71..49ccafe53f 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj @@ -26,4 +26,11 @@ + + + true + build\Microsoft.Quantum.DocumentationGenerator.props + + + diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props new file mode 100644 index 0000000000..84c18151ba --- /dev/null +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props @@ -0,0 +1,10 @@ + + + + + + $(MSBuildThisFileDirectory)/../lib/netstandard2.1/Microsoft.Quantum.DocumentationGenerator.dll + + + + diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 5440be1925..0ae57ef14f 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -81,6 +81,8 @@ <_QscCommandPredefinedAssemblyProperties Condition="$(DefaultSimulator) != ''">$(_QscCommandPredefinedAssemblyProperties) DefaultSimulator:$(DefaultSimulator) <_QscCommandPredefinedAssemblyProperties Condition="$(ExecutionTarget) != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) <_QscCommandPredefinedAssemblyProperties Condition="$(ExposeReferencesViaTestNames)">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true + <_QscCommandPredefinedAssemblyProperties Condition="$(PackageId) != ''">$(_QscCommandPredefinedAssemblyProperties) PackageId:$(PackageId) + <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandDocsFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) From a32e0bcdfef861c7ee00cc15dea049351d7b7f6d Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 12:33:51 -0700 Subject: [PATCH 26/74] Add op, fn md links. --- src/QsCompiler/DocumentationGenerator/Extensions.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index 76bdd185fe..3f59e736d5 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -342,8 +342,13 @@ internal static Dictionary ToDictionaryOfDeclarations(this ResolvedTypeKind.ArrayType array => $"{array.Item.ToMarkdownLink()}[]", ResolvedTypeKind.Function function => $"{function.Item1.ToMarkdownLink()} -> {function.Item2.ToMarkdownLink()}", - ResolvedTypeKind.Operation operation => "TODO", - ResolvedTypeKind.TupleType tuple => "TODO", + ResolvedTypeKind.Operation operation => + $@"{operation.Item1.Item1.ToMarkdownLink()} => {operation.Item1.Item2.ToMarkdownLink()} { + operation.Item2.Characteristics.ToSyntax() + }", + ResolvedTypeKind.TupleType tuple => "(" + String.Join(",", + tuple.Item.Select(ToMarkdownLink) + ) + ")", ResolvedTypeKind.UserDefinedType udt => udt.Item.ToMarkdownLink(), _ => type.Resolution.Tag switch { From b68e1a60d29484c7c9fbb18bf8d7e562f1b6fdcd Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 12:34:01 -0700 Subject: [PATCH 27/74] Fix targets XML. --- src/QuantumSdk/Sdk/Sdk.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 0ae57ef14f..d68b72e82f 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -82,7 +82,7 @@ <_QscCommandPredefinedAssemblyProperties Condition="$(ExecutionTarget) != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) <_QscCommandPredefinedAssemblyProperties Condition="$(ExposeReferencesViaTestNames)">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true <_QscCommandPredefinedAssemblyProperties Condition="$(PackageId) != ''">$(_QscCommandPredefinedAssemblyProperties) PackageId:$(PackageId) - <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) + <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandDocsFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) From 90843064baa1622c64ecedd6ca4b9089294b5dbb Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 13:11:46 -0700 Subject: [PATCH 28/74] One more XML fix. --- src/QuantumSdk/Sdk/Sdk.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index d68b72e82f..09006c6fc7 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -82,7 +82,7 @@ <_QscCommandPredefinedAssemblyProperties Condition="$(ExecutionTarget) != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) <_QscCommandPredefinedAssemblyProperties Condition="$(ExposeReferencesViaTestNames)">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true <_QscCommandPredefinedAssemblyProperties Condition="$(PackageId) != ''">$(_QscCommandPredefinedAssemblyProperties) PackageId:$(PackageId) - <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) + <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandDocsFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) From a96e698c28279b5a4917424e2e64d521c614d7e9 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 20:46:10 -0700 Subject: [PATCH 29/74] Fix props. --- .../DocumentationGenerator/DocumentationGenerator.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props index 84c18151ba..d45e9d379f 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props @@ -2,9 +2,9 @@ - + $(MSBuildThisFileDirectory)/../lib/netstandard2.1/Microsoft.Quantum.DocumentationGenerator.dll - + From 564058872cf16c1813bbe9aa9172467bb1617079 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 20:47:14 -0700 Subject: [PATCH 30/74] Started work on processing namespace comments. --- .../DocumentationGenerator/Extensions.cs | 14 ++++++++++++ .../ProcessDocComments.cs | 22 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index 3f59e736d5..539a935835 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -367,6 +367,20 @@ internal static Dictionary ToDictionaryOfDeclarations(this internal static string ToMarkdownLink(this UserDefinedType type) => $"[{type.Name.Value}](xref:{type.Namespace.Value}.{type.Name.Value})"; + + internal static bool IsInCompilationUnit(this QsNamespaceElement element) => + element switch + { + QsNamespaceElement.QsCallable callable => callable.Item.IsInCompilationUnit(), + QsNamespaceElement.QsCustomType type => type.Item.IsInCompilationUnit(), + _ => false + }; + + internal static bool IsInCompilationUnit(this QsCallable callable) => + callable.SourceFile.Value.EndsWith(".qs"); + + internal static bool IsInCompilationUnit(this QsCustomType type) => + type.SourceFile.Value.EndsWith(".qs"); } } diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 35632f12b1..064dd81a19 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -59,13 +59,31 @@ internal NamespaceTransformation(ProcessDocComments parent, DocumentationWriter? : base(parent) { this.writer = writer; } + public override QsNamespace OnNamespace(QsNamespace ns) + { + ns = base.OnNamespace(ns); + if (ns.Elements.Any(element => element.IsInCompilationUnit())) + { + // Concatenate everything into one documentation comment. + var comment = String.Join("\n", + ns.Documentation.SelectMany(group => group) + ); + if (comment.Trim().Length != 0) + { + // TODO + } + } + + return ns; + } + public override QsCustomType OnTypeDeclaration(QsCustomType type) { type = base.OnTypeDeclaration(type); // If the UDT didn't come from a Q# source file, then it // came in from a reference, and shouldn't be documented in this // project. - if (!type.SourceFile.Value.EndsWith(".qs")) return type; + if (!type.IsInCompilationUnit()) return type; var isDeprecated = type.IsDeprecated(out var replacement); var docComment = new DocComment( @@ -94,7 +112,7 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) // If the callable didn't come from a Q# source file, then it // came in from a reference, and shouldn't be documented in this // project. - if (!callable.SourceFile.Value.EndsWith(".qs")) return callable; + if (!callable.IsInCompilationUnit()) return callable; var isDeprecated = callable.IsDeprecated(out var replacement); var docComment = new DocComment( From 2655b8fa46e4faf15cbbe9e27fd76c3cb722c2ce Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 3 Sep 2020 21:48:54 -0700 Subject: [PATCH 31/74] Start writing out namespaces. --- .../DocumentationWriter.cs | 73 ++++++++++++++++--- .../ProcessDocComments.cs | 9 +-- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs index 9c61c2b8a4..bf3ac24fdb 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs +++ b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs @@ -41,6 +41,42 @@ public DocumentationWriter(string outputPath, string? packageName) ? "" : $"Package: [{PackageName}](https://nuget.org/packages/{PackageName})\n"; } + + public async Task WriteOutput(QsNamespace ns, DocComment docComment) + { + var name = ns.Name.Value; + var uid = name; + var title = $"{name} namespace"; + var header = new Dictionary + { + // DocFX metadata + ["uid"] = name, + ["title"] = title, + + // docs.ms metadata + ["ms.date"] = DateTime.Today.ToString(), + ["ms.topic"] = "article", + + // Q# metadata + ["qsharp.kind"] = "udt", + ["qsharp.name"] = name, + ["qsharp.summary"] = docComment.Summary + }; + var document = $@" +# {title} + +{docComment.Summary} + +" + .MaybeWithSection("Description", docComment.Description) + .WithYamlHeader(header); + + // Open a file to write the new doc to. + await File.WriteAllTextAsync( + Path.Join(outputPath, $"{name.ToLowerInvariant()}.md"), + document + ); + } public async Task WriteOutput(QsCustomType type, DocComment docComment) { @@ -49,10 +85,19 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) var title = $"{type.FullName.Name.Value} user defined type"; var header = new Dictionary { + // DocFX metadata ["uid"] = type.FullName.ToString(), ["title"] = title, + + // docs.ms metadata ["ms.date"] = DateTime.Today.ToString(), - ["ms.topic"] = "article" + ["ms.topic"] = "article", + + // Q# metadata + ["qsharp.kind"] = "udt", + ["qsharp.namespace"] = type.FullName.Namespace.Value, + ["qsharp.name"] = type.FullName.Name.Value, + ["qsharp.summary"] = docComment.Summary }; var document = $@" Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) @@ -102,20 +147,28 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); // Make a new Markdown document for the type declaration. - var title = $@"{callable.FullName.Name.Value} { - callable.Kind.Tag switch - { - QsCallableKind.Tags.Function => "function", - QsCallableKind.Tags.Operation => "operation", - QsCallableKind.Tags.TypeConstructor => "type constructor" - } - }"; + var kind = callable.Kind.Tag switch + { + QsCallableKind.Tags.Function => "function", + QsCallableKind.Tags.Operation => "operation", + QsCallableKind.Tags.TypeConstructor => "type constructor" + }; + var title = $@"{callable.FullName.Name.Value} {kind}"; var header = new Dictionary { + // DocFX metadata ["uid"] = callable.FullName.ToString(), ["title"] = title, + + // docs.ms metadata ["ms.date"] = DateTime.Today.ToString(), - ["ms.topic"] = "article" + ["ms.topic"] = "article", + + // Q# metadata + ["qsharp.kind"] = kind, + ["qsharp.namespace"] = callable.FullName.Namespace.Value, + ["qsharp.name"] = callable.FullName.Name.Value, + ["qsharp.summary"] = docComment.Summary }; var document = $@" Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 064dd81a19..34bc8ccf0e 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -65,13 +65,10 @@ public override QsNamespace OnNamespace(QsNamespace ns) if (ns.Elements.Any(element => element.IsInCompilationUnit())) { // Concatenate everything into one documentation comment. - var comment = String.Join("\n", - ns.Documentation.SelectMany(group => group) + var comment = new DocComment( + ns.Documentation.SelectMany(group => group).SelectMany(comments => comments) ); - if (comment.Trim().Length != 0) - { - // TODO - } + writer?.WriteOutput(ns, comment)?.Wait(); } return ns; From 9674b3539ecb7d70f19584d71643f4a48adca508 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 11:33:55 -0700 Subject: [PATCH 32/74] Use new generator by default. --- src/QuantumSdk/Sdk/Sdk.props | 5 +++++ src/QuantumSdk/Sdk/Sdk.targets | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/QuantumSdk/Sdk/Sdk.props b/src/QuantumSdk/Sdk/Sdk.props index 5b96ae2dd5..6c22202b64 100644 --- a/src/QuantumSdk/Sdk/Sdk.props +++ b/src/QuantumSdk/Sdk/Sdk.props @@ -34,6 +34,11 @@ + + + + + diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 09006c6fc7..4966dc220c 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -70,7 +70,7 @@ <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe <_QscCommandOutputFlag>--output "$(GeneratedFilesOutputPath)" - <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration)">--doc "$(QsharpDocsOutputPath)" + <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration) AND 'QsharpDocGenerationMode' == 'yaml')">--doc "$(QsharpDocsOutputPath)" <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" <_QscCommandReferencesFlag Condition="@(ResolvedQsharpReferences->Count()) > 0">--references "@(ResolvedQsharpReferences,'" "')" <_QscCommandLoadFlag Condition="@(_PrioritizedResolvedQscReferences->Count()) > 0">--load "@(_PrioritizedResolvedQscReferences,'" "')" From ec79473e1710a29d14e2021a5667677cc4702754 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 11:37:11 -0700 Subject: [PATCH 33/74] Allow overriding documentation package ids for metapkgs. --- src/QsCompiler/DocumentationGenerator/DocgenStep.cs | 2 +- src/QuantumSdk/Sdk/Sdk.targets | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs index eb931f0c35..bd209f35b5 100644 --- a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs +++ b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs @@ -68,7 +68,7 @@ public bool Transformation(QsCompilation compilation, out QsCompilation transfor AssemblyConstants.TryGetValue("DocsOutputPath", out var path) ? path : null, - AssemblyConstants.TryGetValue("PackageId", out var packageName) + AssemblyConstants.TryGetValue("DocsPackageId", out var packageName) ? packageName : null ).OnCompilation(compilation); diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 4966dc220c..15eb69868a 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -81,7 +81,7 @@ <_QscCommandPredefinedAssemblyProperties Condition="$(DefaultSimulator) != ''">$(_QscCommandPredefinedAssemblyProperties) DefaultSimulator:$(DefaultSimulator) <_QscCommandPredefinedAssemblyProperties Condition="$(ExecutionTarget) != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) <_QscCommandPredefinedAssemblyProperties Condition="$(ExposeReferencesViaTestNames)">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true - <_QscCommandPredefinedAssemblyProperties Condition="$(PackageId) != ''">$(_QscCommandPredefinedAssemblyProperties) PackageId:$(PackageId) + <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsPackageId) != ''">$(_QscCommandPredefinedAssemblyProperties) DocsPackageId:$(QsharpDocsPackageId) <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" From 9c8ce7d79b854720ba62a59fb82a80e08108efd6 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 12:57:00 -0700 Subject: [PATCH 34/74] Fix bug with namespace kind. --- src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs index bf3ac24fdb..9949800710 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs +++ b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs @@ -58,7 +58,7 @@ public async Task WriteOutput(QsNamespace ns, DocComment docComment) ["ms.topic"] = "article", // Q# metadata - ["qsharp.kind"] = "udt", + ["qsharp.kind"] = "namespace", ["qsharp.name"] = name, ["qsharp.summary"] = docComment.Summary }; From ebbca8a60c3c7802b724c9d230a8d178b7894410 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 12:57:10 -0700 Subject: [PATCH 35/74] Add utility to merge documentation post-build. --- utilities/summarize_documentation/Pipfile | 14 +++ .../summarize_documentation/Pipfile.lock | 97 +++++++++++++++ utilities/summarize_documentation/README.md | 11 ++ .../summarize_documentation.py | 112 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 utilities/summarize_documentation/Pipfile create mode 100644 utilities/summarize_documentation/Pipfile.lock create mode 100644 utilities/summarize_documentation/README.md create mode 100644 utilities/summarize_documentation/summarize_documentation.py diff --git a/utilities/summarize_documentation/Pipfile b/utilities/summarize_documentation/Pipfile new file mode 100644 index 0000000000..eae5da0d20 --- /dev/null +++ b/utilities/summarize_documentation/Pipfile @@ -0,0 +1,14 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +python-frontmatter = "*" +click = "*" +ruamel-yaml = "*" + +[requires] +python_version = "3.7" diff --git a/utilities/summarize_documentation/Pipfile.lock b/utilities/summarize_documentation/Pipfile.lock new file mode 100644 index 0000000000..0271b8e9a0 --- /dev/null +++ b/utilities/summarize_documentation/Pipfile.lock @@ -0,0 +1,97 @@ +{ + "_meta": { + "hash": { + "sha256": "6b20a9b061f99b98de67c2ed4ebb91994e4f4646aeb8bb6295505dceda0a3335" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", + "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" + ], + "index": "pypi", + "version": "==7.1.2" + }, + "python-frontmatter": { + "hashes": [ + "sha256:a7dcdfdaf498d488dce98bfa9452f8b70f803a923760ceab1ebd99291d98d28a", + "sha256:a9c2e90fc38e9f0c68d8b82299040f331ca3b8525ac7fa5f6beffef52b26c426" + ], + "index": "pypi", + "version": "==0.5.0" + }, + "pyyaml": { + "hashes": [ + "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", + "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", + "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", + "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", + "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", + "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", + "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", + "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", + "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", + "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", + "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" + ], + "version": "==5.3.1" + }, + "ruamel-yaml": { + "hashes": [ + "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5", + "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e" + ], + "index": "pypi", + "version": "==0.16.12" + }, + "ruamel.yaml.clib": { + "hashes": [ + "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b", + "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91", + "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc", + "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7", + "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7", + "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6", + "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6", + "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0", + "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62", + "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99", + "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5", + "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026", + "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2", + "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1", + "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b", + "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e", + "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c", + "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988", + "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f", + "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1", + "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", + "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f" + ], + "markers": "python_version < '3.9' and platform_python_implementation == 'CPython'", + "version": "==0.2.2" + }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" + } + }, + "develop": {} +} diff --git a/utilities/summarize_documentation/README.md b/utilities/summarize_documentation/README.md new file mode 100644 index 0000000000..9dfe93ee19 --- /dev/null +++ b/utilities/summarize_documentation/README.md @@ -0,0 +1,11 @@ +# summarize_documentation + +This utility summarizes Markdown documentation gathered from one or more compilation units, +producing namespace and TOC files from the gathered documentation. + +For example: + +```bash +$ pipenv install +$ pipenv run python obj/qsharp/docs/*.md obj/qsharp/docs +``` diff --git a/utilities/summarize_documentation/summarize_documentation.py b/utilities/summarize_documentation/summarize_documentation.py new file mode 100644 index 0000000000..985c419646 --- /dev/null +++ b/utilities/summarize_documentation/summarize_documentation.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# -*- coding: utf8 -*- +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +from collections import defaultdict +from dataclasses import dataclass, asdict +from pathlib import Path +import glob + +import click +import frontmatter +import ruamel.yaml as yaml + +namespace_comment = "### YamlMime:QSharpNamespace" +warning_comment = """ +# This file is automatically generated. +# Please do not modify this file manually, or your changes may be lost when +# documentation is rebuilt. +""" + +@dataclass(frozen=True) +class NamespaceItem: + summary: str = "" + name: str = "" + namespace: str = "" + uid: str = "" + kind: str = "" + +@dataclass +class Namespace: + summary: str = "" + uid: str = "" + name: str = "" + items = set() + +def items_of_kind(items, kind): + return [ + { + "uid": item.uid, + "summary": item.summary + } + for item in + sorted( + (item for item in items if item.kind == kind), + key=(lambda item: item.uid) + ) + ] + +@click.command() +@click.argument("sources") +@click.argument("output_path") +def main(sources : str, output_path : str): + namespaces = defaultdict(Namespace) + output_path = Path(output_path) + for source in glob.glob(sources): + print(source) + with open(source, 'r', encoding='utf8') as f: + header, _ = frontmatter.parse(f.read()) + if header['qsharp.kind'] == 'namespace': + namespaces[header['qsharp.name']].summary = header['qsharp.summary'] + namespaces[header['qsharp.name']].name = header['qsharp.name'] + namespaces[header['qsharp.name']].uid = header['uid'] + else: + namespaces[header['qsharp.namespace']].items.add(NamespaceItem( + summary=header['qsharp.summary'], + name=header['qsharp.name'], + namespace=header['qsharp.namespace'], + uid=header["uid"], + kind=header["qsharp.kind"] + )) + + for namespace_name, namespace in namespaces.items(): + uid = namespace.uid or namespace_name + name = namespace.name or namespace_name + namespace_page = { + "uid": uid, + "name": name, + "summary": namespace.summary, + "operations": items_of_kind(namespace.items, "operation"), + "functions": items_of_kind(namespace.items, "function"), + "newtypes": items_of_kind(namespace.items, "udt") + } + + with open(output_path / f"{name.lower()}.yml", "w", encoding="utf8") as f: + f.write(namespace_comment + warning_comment + yaml.dump(namespace_page)) + + toc_page = [ + { + "uid": namespace.name, + "name": namespace_name, + "items": [ + { + "name": item.name, + "uid": item.uid + } + for item in sorted( + namespace.items, + key=lambda item: item.uid + ) + ] + } + for namespace_name, namespace in sorted( + namespaces.items(), + key=lambda pair: pair[0] + ) + ] + with open(output_path / "toc.yml", "w", encoding="utf8") as f: + f.write(warning_comment + yaml.dump(toc_page)) + +if __name__ == "__main__": + main() From 88f7e2d47cde0c341999ec9f45656ef8f3b3db76 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 13:33:12 -0700 Subject: [PATCH 36/74] Added some more API documentation. --- .../DocumentationGenerator/Extensions.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index 539a935835..ea40942fac 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -28,6 +28,10 @@ namespace Microsoft.Quantum.Documentation { + // The next several types allow for adding attributes to + // callables and UDTs with a single API, so that the extension + // methods in this file can be written once for both kinds of + // AST items. internal interface IAttributeBuilder { public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute); @@ -77,6 +81,16 @@ internal static IAttributeBuilder AttributeBuilder( this QsCustomType type ) => new Udt(type); + /// + /// Given an attribute builder, returns a new copy of that builder + /// with one additional attribute. + /// + /// The type of AST item decorated by the attribute builder. + /// The attribute builder to which the new attribute should be added. + /// The Q# namespace containing the new attribute. + /// The name of the Q# UDT for the new attribute. + /// The input to the Q# UDT's type constructor function for the given attribute. + /// A new attribute builder with the new attribute added. internal static IAttributeBuilder WithAttribute( this IAttributeBuilder builder, string @namespace, string name, TypedExpression input @@ -102,6 +116,16 @@ private static TypedExpression AsLiteralExpression(this string literal) => ImmutableArray.Empty ); + /// + /// Given an attribute builder, either returns it unmodified, + /// or returns a new copy of the attribute builder with a new + /// string-valued documentation attribute added. + /// + /// The type of AST item decorated by the attribute builder. + /// The attribute builder to which the new attribute should be added. + /// The name of the Q# UDT for the new attribute. + /// The value of the new attribute to be added, or null if no attribute is to be added. + /// A new attribute builder with the new attribute added, or if is null. internal static IAttributeBuilder MaybeWithSimpleDocumentationAttribute( this IAttributeBuilder builder, string attributeName, string? value ) => @@ -111,6 +135,15 @@ internal static IAttributeBuilder MaybeWithSimpleDocumentationAttribute( attributeName, value.AsLiteralExpression() ); + /// + /// Given an attribute builder, returns a new attribute builder with + /// an attribute added for each string in a given collection. + /// + /// The type of AST item decorated by the attribute builder. + /// The attribute builder to which the new attributes should be added. + /// The name of the Q# UDT for the new attributes. + /// The values of the new attributes to be added. + /// A new attribute builder with the one new attribute added for each element of . internal static IAttributeBuilder WithListOfDocumentationAttributes( this IAttributeBuilder builder, string attributeName, IEnumerable items ) => From c318c625a8434a7265ad66cfdb5d9062f1fc1f57 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 13:33:19 -0700 Subject: [PATCH 37/74] Fix MSBuild files. --- src/QuantumSdk/Sdk/Sdk.props | 2 +- src/QuantumSdk/Sdk/Sdk.targets | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QuantumSdk/Sdk/Sdk.props b/src/QuantumSdk/Sdk/Sdk.props index 6c22202b64..61daf32b6a 100644 --- a/src/QuantumSdk/Sdk/Sdk.props +++ b/src/QuantumSdk/Sdk/Sdk.props @@ -36,7 +36,7 @@ - + diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 15eb69868a..a198e4a4ee 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -70,7 +70,7 @@ <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe <_QscCommandOutputFlag>--output "$(GeneratedFilesOutputPath)" - <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration) AND 'QsharpDocGenerationMode' == 'yaml')">--doc "$(QsharpDocsOutputPath)" + <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration) AND ('QsharpDocGenerationMode' == 'yaml')">--doc "$(QsharpDocsOutputPath)" <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" <_QscCommandReferencesFlag Condition="@(ResolvedQsharpReferences->Count()) > 0">--references "@(ResolvedQsharpReferences,'" "')" <_QscCommandLoadFlag Condition="@(_PrioritizedResolvedQscReferences->Count()) > 0">--load "@(_PrioritizedResolvedQscReferences,'" "')" From 376f115bb11aeb49a023bf086db1b7aad3784269 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 4 Sep 2020 20:48:16 -0700 Subject: [PATCH 38/74] Mix documentation properties. --- .../DefaultItems.props.v.template | 3 +++ src/QuantumSdk/Sdk/Sdk.props | 20 +++++++++---------- src/QuantumSdk/Sdk/Sdk.targets | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template b/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template index 6a5a926646..650b312e4e 100644 --- a/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template +++ b/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template @@ -34,6 +34,9 @@ true true false + $(PackageId) + + markdown false dotnet "$(MSBuildThisFileDirectory)../tools/utils/Microsoft.Quantum.Sdk.BuildConfiguration.dll" $(DefaultQscBuildConfigExe) diff --git a/src/QuantumSdk/Sdk/Sdk.props b/src/QuantumSdk/Sdk/Sdk.props index 61daf32b6a..fafb27c1b0 100644 --- a/src/QuantumSdk/Sdk/Sdk.props +++ b/src/QuantumSdk/Sdk/Sdk.props @@ -23,12 +23,12 @@ - - + + - - - + + + @@ -36,18 +36,18 @@ - + - - + + diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index a198e4a4ee..5c1faaee8a 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -70,7 +70,7 @@ <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe <_QscCommandOutputFlag>--output "$(GeneratedFilesOutputPath)" - <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration) AND ('QsharpDocGenerationMode' == 'yaml')">--doc "$(QsharpDocsOutputPath)" + <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration) AND ('$(QsharpDocGenerationMode)' == 'yaml')">--doc "$(QsharpDocsOutputPath)" <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" <_QscCommandReferencesFlag Condition="@(ResolvedQsharpReferences->Count()) > 0">--references "@(ResolvedQsharpReferences,'" "')" <_QscCommandLoadFlag Condition="@(_PrioritizedResolvedQscReferences->Count()) > 0">--load "@(_PrioritizedResolvedQscReferences,'" "')" From ed3433f6f04195387f6f122e354ab0e9ccfa70c7 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 28 Sep 2020 16:20:18 -0700 Subject: [PATCH 39/74] Addressing feedback. --- .../DocumentationGenerator/DocgenStep.cs | 1 - .../DocumentationGenerator.csproj | 9 +- .../DocumentationWriter.cs | 2 - utilities/summarize_documentation/Pipfile | 14 --- .../summarize_documentation/Pipfile.lock | 97 ------------------- .../summarize_documentation/requirements.txt | 3 + 6 files changed, 11 insertions(+), 115 deletions(-) delete mode 100644 utilities/summarize_documentation/Pipfile delete mode 100644 utilities/summarize_documentation/Pipfile.lock create mode 100644 utilities/summarize_documentation/requirements.txt diff --git a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs index bd209f35b5..b803094e84 100644 --- a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs +++ b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs @@ -9,7 +9,6 @@ using Microsoft.Quantum.QsCompiler.Experimental; using Microsoft.Quantum.QsCompiler.SyntaxTree; - namespace Microsoft.Quantum.Documentation { public class DocumentationGenerationStep : IRewriteStep diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj index 49ccafe53f..f7f4d268a6 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj @@ -4,6 +4,8 @@ netstandard2.1 Microsoft.Quantum.DocumentationGenerator + enable + nullable @@ -19,7 +21,8 @@ - + + @@ -33,4 +36,8 @@ + + + + diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs index 9949800710..d212b38520 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs +++ b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#nullable enable - using System; using System.Collections.Generic; using System.IO; diff --git a/utilities/summarize_documentation/Pipfile b/utilities/summarize_documentation/Pipfile deleted file mode 100644 index eae5da0d20..0000000000 --- a/utilities/summarize_documentation/Pipfile +++ /dev/null @@ -1,14 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -python-frontmatter = "*" -click = "*" -ruamel-yaml = "*" - -[requires] -python_version = "3.7" diff --git a/utilities/summarize_documentation/Pipfile.lock b/utilities/summarize_documentation/Pipfile.lock deleted file mode 100644 index 0271b8e9a0..0000000000 --- a/utilities/summarize_documentation/Pipfile.lock +++ /dev/null @@ -1,97 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "6b20a9b061f99b98de67c2ed4ebb91994e4f4646aeb8bb6295505dceda0a3335" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "click": { - "hashes": [ - "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", - "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" - ], - "index": "pypi", - "version": "==7.1.2" - }, - "python-frontmatter": { - "hashes": [ - "sha256:a7dcdfdaf498d488dce98bfa9452f8b70f803a923760ceab1ebd99291d98d28a", - "sha256:a9c2e90fc38e9f0c68d8b82299040f331ca3b8525ac7fa5f6beffef52b26c426" - ], - "index": "pypi", - "version": "==0.5.0" - }, - "pyyaml": { - "hashes": [ - "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", - "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", - "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", - "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", - "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", - "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", - "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", - "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", - "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", - "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", - "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" - ], - "version": "==5.3.1" - }, - "ruamel-yaml": { - "hashes": [ - "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5", - "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e" - ], - "index": "pypi", - "version": "==0.16.12" - }, - "ruamel.yaml.clib": { - "hashes": [ - "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b", - "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91", - "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc", - "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7", - "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7", - "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6", - "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6", - "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0", - "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62", - "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99", - "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5", - "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026", - "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2", - "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1", - "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b", - "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e", - "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c", - "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988", - "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f", - "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1", - "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", - "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f" - ], - "markers": "python_version < '3.9' and platform_python_implementation == 'CPython'", - "version": "==0.2.2" - }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" - } - }, - "develop": {} -} diff --git a/utilities/summarize_documentation/requirements.txt b/utilities/summarize_documentation/requirements.txt new file mode 100644 index 0000000000..d55d361a5e --- /dev/null +++ b/utilities/summarize_documentation/requirements.txt @@ -0,0 +1,3 @@ +python-frontmatter +click +ruamel-yaml \ No newline at end of file From 7e2455e44680f62a8186ae7cc9c012551f31a060 Mon Sep 17 00:00:00 2001 From: Chris Granade Date: Wed, 7 Oct 2020 19:09:09 -0700 Subject: [PATCH 40/74] Apply suggestions from code review Co-authored-by: bettinaheim <34236215+bettinaheim@users.noreply.github.com> --- src/QsCompiler/DocumentationGenerator/DocgenStep.cs | 2 -- src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs | 3 +-- src/QsCompiler/DocumentationGenerator/Extensions.cs | 4 +--- src/QuantumSdk/Sdk/Sdk.props | 4 +++- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs index b803094e84..418ccf0a0d 100644 --- a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs +++ b/src/QsCompiler/DocumentationGenerator/DocgenStep.cs @@ -3,10 +3,8 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.Quantum.QsCompiler; -using Microsoft.Quantum.QsCompiler.Experimental; using Microsoft.Quantum.QsCompiler.SyntaxTree; namespace Microsoft.Quantum.Documentation diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs index d212b38520..ff65d0338c 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs +++ b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs @@ -17,8 +17,7 @@ namespace Microsoft.Quantum.Documentation public class DocumentationWriter { - private readonly string outputPath; - public string OutputPath => outputPath; + public string OutputPath { get; } private readonly string? packageName; public string? PackageName => packageName; diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index ea40942fac..ca6fc1e710 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -7,13 +7,11 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Quantum.QsCompiler; using Microsoft.Quantum.QsCompiler.DataTypes; using Microsoft.Quantum.QsCompiler.SyntaxTokens; using Microsoft.Quantum.QsCompiler.SyntaxTree; using Microsoft.Quantum.QsCompiler.Transformations; -using Microsoft.Quantum.QsCompiler.Transformations.Core; using Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput; using YamlDotNet.Serialization; using Range = Microsoft.Quantum.QsCompiler.DataTypes.Range; @@ -42,7 +40,7 @@ internal interface IAttributeBuilder internal class Callable : IAttributeBuilder { - private QsCallable callable; + private readonly QsCallable callable; internal Callable(QsCallable callable) { this.callable = callable; diff --git a/src/QuantumSdk/Sdk/Sdk.props b/src/QuantumSdk/Sdk/Sdk.props index fafb27c1b0..461bae521d 100644 --- a/src/QuantumSdk/Sdk/Sdk.props +++ b/src/QuantumSdk/Sdk/Sdk.props @@ -36,7 +36,9 @@ - + From 02a79e307f970d850c6c352693b1ed624c881c01 Mon Sep 17 00:00:00 2001 From: Chris Granade Date: Wed, 7 Oct 2020 19:14:12 -0700 Subject: [PATCH 41/74] Update src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj --- .../DocumentationGenerator/DocumentationGenerator.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj index f7f4d268a6..9d89600c2a 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj @@ -14,7 +14,7 @@ Microsoft.Quantum.DocumentationGenerator See: https://docs.microsoft.com/en-us/quantum/relnotes/ MIT - https://github.com/microsoft/qsharp-runtime + https://github.com/microsoft/qsharp-compiler https://secure.gravatar.com/avatar/bd1f02955b2853ba0a3b1cdc2434e8ec.png Quantum Q# Qsharp true From 5a389c92f2b9e01bb3d3c6f192df47d1fb8ec9d7 Mon Sep 17 00:00:00 2001 From: Chris Granade Date: Wed, 7 Oct 2020 19:14:29 -0700 Subject: [PATCH 42/74] Update src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs --- src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs index ff65d0338c..a1b015ca5d 100644 --- a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs +++ b/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs @@ -6,10 +6,7 @@ using System.IO; using System.Threading.Tasks; using System.Linq; -using Microsoft.Quantum.QsCompiler; -using Microsoft.Quantum.QsCompiler.DataTypes; using Microsoft.Quantum.QsCompiler.Documentation; -using Microsoft.Quantum.QsCompiler.SyntaxTokens; using Microsoft.Quantum.QsCompiler.SyntaxTree; namespace Microsoft.Quantum.Documentation From e772ffc46f42b15b709f61b0a234b907fd5a3af9 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 8 Oct 2020 14:59:26 -0700 Subject: [PATCH 43/74] Addressing feedback. --- .devcontainer/README.md | 21 ++ QsCompiler.sln | 10 +- ...cgenStep.cs => DocumentationGeneration.cs} | 49 ++-- .../DocumentationGenerator/Extensions.cs | 218 +++++++++++------- .../ProcessDocComments.cs | 8 - 5 files changed, 186 insertions(+), 120 deletions(-) create mode 100644 .devcontainer/README.md rename src/QsCompiler/DocumentationGenerator/{DocgenStep.cs => DocumentationGeneration.cs} (70%) diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000000..1428c4eb39 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,21 @@ +# Remote Development Container for Visual Studio Code (preview) # + +This folder defines a _development container_ for the Quantum Development Kit to get up and running with your development environment for contributing to the Q# compiler. + +## What is a Development Container? ## + +Visual Studio Code allows for using [Docker](https://docs.microsoft.com/dotnet/standard/microservices-architecture/container-docker-introduction/docker-defined) to quickly define development environments, including all the compilers, command-line tools, libraries, and programming platforms you need to get up and running quickly. +Using the definitions provided in this folder, Visual Studio Code can use Docker to automatically install the correct version of the Quantum Development Kit as well as other software you might want to use with Q#, such as Python and Jupyter Notebook --- all into an isolated container that doesn't affect the rest of the software you have on your system. + +Next steps: +- [Visual Studio Code: Developing inside a container](https://code.visualstudio.com/docs/remote/containers) + +## Getting Started ## + +To use this development container, follow the installation instructions on the [Visual Studio Code site](https://code.visualstudio.com/docs/remote/containers#_installation) to prepare your machine to use development containers such as this one. +Once you have done so, clone the [**microsoft/quantum**](https://github.com/microsoft/quantum) repository and open the folder in Visual Studio Code. +You should be prompted to reopen the folder for remote development in the development container; if not, make sure that you have the right extension installed from above. + +Once you follow the prompt, Visual Studio Code will automatically configure your development container by installing the Quantum Development Kit into a new image, including installing the .NET Core SDK, project templates, Jupyter Notebook support, and the Python host package. +This process will take a few moments, but once it's complete, you can then open a new shell as normal in Visual Studio Code; this shell will open a command line in your new development container. +The Q# compiler will then be available in the `/workspace/qsharp-compiler/` folder of your development container, so you can easily build different parts of the compiler by using `dotnet build`. diff --git a/QsCompiler.sln b/QsCompiler.sln index 5acb4ebf89..79e9fe225c 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28809.33 MinimumVisualStudioVersion = 10.0.40219.1 @@ -44,11 +45,9 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Optimizations", "src\QsComp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B4A9484D-31FC-4A27-9E26-4C8DE3E02D77}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library2", "src\QsCompiler\TestTargets\Libraries\Library2\Library2.csproj", "{E7E019AB-42F8-48AB-B80C-D33351F2C96A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library2", "src\QsCompiler\TestTargets\Libraries\Library2\Library2.csproj", "{E7E019AB-42F8-48AB-B80C-D33351F2C96A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A4A3C7BF-19AD-4916-A4D8-6572C1A11AFC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentationGenerator", "src\QsCompiler\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentationGenerator", "src\QsCompiler\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -302,7 +301,6 @@ Global {D2E36476-A65F-4310-9C4C-B721BCC47B00} = {6077A717-50BF-4F87-B439-CA549AF6A4AE} {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} {E7E019AB-42F8-48AB-B80C-D33351F2C96A} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} - {11311F0C-78CA-43A3-9C84-D7EA0AE9748C} = {A4A3C7BF-19AD-4916-A4D8-6572C1A11AFC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B921C36B-4574-4025-8FE3-E5BD2D3D2B81} diff --git a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs b/src/QsCompiler/DocumentationGenerator/DocumentationGeneration.cs similarity index 70% rename from src/QsCompiler/DocumentationGenerator/DocgenStep.cs rename to src/QsCompiler/DocumentationGenerator/DocumentationGeneration.cs index b803094e84..16a873102c 100644 --- a/src/QsCompiler/DocumentationGenerator/DocgenStep.cs +++ b/src/QsCompiler/DocumentationGenerator/DocumentationGeneration.cs @@ -11,27 +11,45 @@ namespace Microsoft.Quantum.Documentation { - public class DocumentationGenerationStep : IRewriteStep + /// + /// Rewrite step that generates API documentation from documentation + /// comments in the Q# source files being compiled. + /// + public class DocumentationGeneration : IRewriteStep { - private readonly List Diagnostics; + private readonly List diagnostics; - public DocumentationGenerationStep() + /// + /// Initializes a new instance of the class. + /// + public DocumentationGeneration() { this.AssemblyConstants = new Dictionary(); // will be populated by the Q# compiler - this.Diagnostics = new List(); // collects diagnostics that will be displayed to the user + this.diagnostics = new List(); // collects diagnostics that will be displayed to the user } + /// public string Name => "DocumentationGeneration"; + + /// public int Priority => 0; // only compared within this dll + /// public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => this.Diagnostics; + /// + public IEnumerable GeneratedDiagnostics => this.diagnostics; + + /// public bool ImplementsPreconditionVerification => true; + + /// public bool ImplementsTransformation => true; - public bool ImplementsPostconditionVerification => false; + /// + public bool ImplementsPostconditionVerification => false; + /// public bool PreconditionVerification(QsCompilation compilation) { var preconditionPassed = true; // nothing to check @@ -41,33 +59,24 @@ public bool PreconditionVerification(QsCompilation compilation) // If the severity is Error or Warning the diagnostic is shown to the user like any other compiler diagnostic, // and if the Source property is set to the absolute path of an existing file, // the user will be directed to the file when double clicking the diagnostics. - this.Diagnostics.Add(new IRewriteStep.Diagnostic + this.diagnostics.Add(new IRewriteStep.Diagnostic { Severity = DiagnosticSeverity.Info, Message = $"Precondition for {this.Name} was {(preconditionPassed ? "satisfied" : "not satisfied")}.", - Stage = IRewriteStep.Stage.PreconditionVerification + Stage = IRewriteStep.Stage.PreconditionVerification, }); - - foreach (var item in AssemblyConstants) - { - this.Diagnostics.Add(new IRewriteStep.Diagnostic - { - Severity = DiagnosticSeverity.Info, - Message = $"Got assembly constant \"{item.Key}\" = \"{item.Value}\".", - Stage = IRewriteStep.Stage.PreconditionVerification - }); - } } + return preconditionPassed; } public bool Transformation(QsCompilation compilation, out QsCompilation transformed) { transformed = new ProcessDocComments( - AssemblyConstants.TryGetValue("DocsOutputPath", out var path) + this.AssemblyConstants.TryGetValue("DocsOutputPath", out var path) ? path : null, - AssemblyConstants.TryGetValue("DocsPackageId", out var packageName) + this.AssemblyConstants.TryGetValue("DocsPackageId", out var packageName) ? packageName : null ).OnCompilation(compilation); diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/QsCompiler/DocumentationGenerator/Extensions.cs index ea40942fac..60b306137c 100644 --- a/src/QsCompiler/DocumentationGenerator/Extensions.cs +++ b/src/QsCompiler/DocumentationGenerator/Extensions.cs @@ -165,24 +165,11 @@ this IAttributeBuilder builder, string attributeName, IDictionary.NewValueTuple( - ImmutableArray.Create( - item.Key.AsLiteralExpression(), - item.Value.AsLiteralExpression() - ) - ), - ImmutableArray, ResolvedType>>.Empty, - ResolvedType.New( - QsTypeKind.NewTupleType( - ImmutableArray.Create( - ResolvedType.New(QsTypeKind.String), - ResolvedType.New(QsTypeKind.String) - ) - ) - ), - new InferredExpressionInformation(false, false), - QsNullable.Null + SyntaxGenerator.TupleLiteral( + ImmutableArray.Create( + item.Key.AsLiteralExpression(), + item.Value.AsLiteralExpression() + ) ) ) ); @@ -190,44 +177,80 @@ this IAttributeBuilder builder, string attributeName, IDictionary SyntaxTreeToQsharp.Default.ToCode(type); - internal static string ToSyntax(this QsTypeItem item) => + internal static T WithSideEffect(this T value, Action effect) + { + effect(); + return value; + } + + internal static string ToSyntax(this QsTypeItem item, Action? onDiagnostic = null) => item switch { QsTypeItem.Anonymous anon => anon.Item.ToSyntax(), - QsTypeItem.Named named => $"{named.Item.VariableName.Value} : {named.Item.Type.ToSyntax()}" + QsTypeItem.Named named => $"{named.Item.VariableName.Value} : {named.Item.Type.ToSyntax()}", + _ => "__UNKNOWN__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for type item {item}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }; - - internal static string ToSyntax(this QsTuple items) => + + internal static string ToSyntax(this QsTuple items, Action? onDiagnostic = null) => items switch { QsTuple.QsTuple tuple => $@"({ String.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) })", - QsTuple.QsTupleItem item => item.Item.ToSyntax() + QsTuple.QsTupleItem item => item.Item.ToSyntax(), + _ => "__UNKNOWN__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for type items {items}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }; - internal static string ToSyntax(this QsTuple> items) => + internal static string ToSyntax( + this QsTuple> items, + Action? onDiagnostic = null + ) => items switch { QsTuple>.QsTuple tuple => $@"({ - String.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) + string.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) })", - QsTuple>.QsTupleItem item => item.Item.ToSyntax() + QsTuple>.QsTupleItem item => item.Item.ToSyntax(), + _ => "__UNKNOWN__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for tuple items {items}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }; - internal static string ToSyntax(this LocalVariableDeclaration symbol) => + internal static string ToSyntax(this LocalVariableDeclaration symbol, Action? onDiagnostic = null) => $@"{symbol.VariableName switch { QsLocalSymbol.ValidName name => name.Item.Value, - _ => "{{invalid}}" + _ => "__INVALID__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for local symbol {symbol}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }} : {symbol.Type.ToSyntax()}"; - internal static string ToSyntax(this QsCustomType type) => + internal static string ToSyntax(this QsCustomType type, Action? onDiagnostic = null) => $@"newtype {type.FullName.Name.Value} = { - String.Join(",", type.TypeItems.ToSyntax()) + string.Join(",", type.TypeItems.ToSyntax(onDiagnostic)) };"; - internal static string ToSyntax(this ResolvedCharacteristics characteristics) => + internal static string ToSyntax(this ResolvedCharacteristics characteristics, Action? onDiagnostic = null) => characteristics.SupportedFunctors.ValueOr(null) switch { null => "", @@ -236,40 +259,67 @@ internal static string ToSyntax(this ResolvedCharacteristics characteristics) => functors.Select(functor => functor.Tag switch { QsFunctor.Tags.Adjoint => "Adj", - QsFunctor.Tags.Controlled => "Ctl" + QsFunctor.Tags.Controlled => "Ctl", + _ => "__UNKNOWN__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for characteristic {functor}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }) )}" }; - internal static string ToSyntax(this QsCallable callable) + internal static string ToSyntax(this QsCallable callable, Action? onDiagnostic = null) { var kind = callable.Kind.Tag switch { QsCallableKind.Tags.Function => "function", QsCallableKind.Tags.Operation => "operation", - QsCallableKind.Tags.TypeConstructor => "function" + QsCallableKind.Tags.TypeConstructor => "function", + _ => "__UNKNOWN__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for type callable kind {callable.Kind}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }; var modifiers = callable.Modifiers.Access.Tag switch { AccessModifier.Tags.DefaultAccess => "", - AccessModifier.Tags.Internal => "internal " + AccessModifier.Tags.Internal => "internal ", + _ => "__UNKNOWN__".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for access modifier {callable.Modifiers.Access}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), }; var typeParameters = callable.Signature.TypeParameters switch { { Length: 0 } => "", var typeParams => $@"<{ - String.Join(", ", typeParams.Select( + string.Join(", ", typeParams.Select( param => param switch { QsLocalSymbol.ValidName name => $"'{name.Item.Value}", - _ => "{invalid}" + _ => "{invalid}".WithSideEffect( + () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Message = $"Failed to generate syntax for type parameter {param}.", + Severity = CodeAnalysis.DiagnosticSeverity.Error, + }) + ), } )) - }>" + }>", }; - var input = callable.ArgumentTuple.ToSyntax(); + var input = callable.ArgumentTuple.ToSyntax(onDiagnostic); var output = callable.Signature.ReturnType.ToSyntax(); - var characteristics = callable.Signature.Information.Characteristics.ToSyntax(); + var characteristics = callable.Signature.Information.Characteristics.ToSyntax(onDiagnostic); return $"{modifiers}{kind} {callable.FullName.Name.Value}{typeParameters}{input} : {output}{characteristics}"; } @@ -281,41 +331,34 @@ internal static string MaybeWithSection(this string document, string name, strin internal static string WithYamlHeader(this string document, object header) => $"---\n{new SerializerBuilder().Build().Serialize(header)}---\n{document}"; - internal static bool IsDeprecated(this QsCallable callable, out string? replacement) => - callable.Attributes.IsDeprecated(out replacement); - - internal static bool IsDeprecated(this QsCustomType type, out string? replacement) => - type.Attributes.IsDeprecated(out replacement); - - internal static bool IsDeprecated(this IEnumerable attributes, [NotNullWhen(true)] out string? replacement) + internal static bool IsDeprecated(this QsCallable callable, out string? replacement) { - var deprecationAttribute = attributes.SingleOrDefault(attribute => + var redirect = SymbolResolution.TryFindRedirect(callable.Attributes); + if (redirect.IsNull) { - if (attribute.TypeId.IsValue) - { - var attrType = attribute.TypeId.Item; - if (attrType.Namespace.Value == "Microsoft.Quantum.Core" && attrType.Name.Value == "Deprecated") - { - return true; - } - } - + replacement = null; return false; - }); + } + else + { + replacement = redirect.Item; + return true; + } + } - if (deprecationAttribute == null) + internal static bool IsDeprecated(this QsCustomType type, [NotNullWhen(true)] out string? replacement) + { + var redirect = SymbolResolution.TryFindRedirect(type.Attributes); + if (redirect.IsNull) { replacement = null; return false; } else { - var arg = deprecationAttribute.Argument.Expression as QsExpressionKind.StringLiteral; - Debug.Assert(arg != null, "Argument to deprecated attribute was not a string literal."); - replacement = arg.Item1.Value; + replacement = redirect.Item; return true; } - } internal static Dictionary ToDictionaryOfDeclarations(this QsTuple> items) => @@ -340,13 +383,15 @@ internal static Dictionary ToDictionaryOfDeclarations(this QsTuple.QsTupleItem item => item.Item switch { QsTypeItem.Anonymous _ => new List<(string, ResolvedType)>(), - QsTypeItem.Named named => - new List<(string, ResolvedType)> - {( - named.Item.VariableName.Value, - named.Item.Type - )} - } + QsTypeItem.Named named => + new List<(string, ResolvedType)> + {( + named.Item.VariableName.Value, + named.Item.Type + )}, + _ => throw new ArgumentException($"Type item {item} is neither anonymous nor named.", nameof(typeItems)), + }, + _ => throw new ArgumentException($"Type items {typeItems} aren't a tuple of type items.", nameof(typeItems)), }; private static List<(string, ResolvedType)> InputDeclarations(this QsTuple> items) => items switch @@ -363,11 +408,12 @@ internal static Dictionary ToDictionaryOfDeclarations(this item.Item.VariableName switch { QsLocalSymbol.ValidName name => name.Item.Value, - _ => "__invalid__" + _ => "__invalid__", }, item.Item.Type ) - } + }, + _ => throw new Exception() }; internal static string ToMarkdownLink(this ResolvedType type) => type.Resolution switch @@ -379,23 +425,23 @@ internal static Dictionary ToDictionaryOfDeclarations(this $@"{operation.Item1.Item1.ToMarkdownLink()} => {operation.Item1.Item2.ToMarkdownLink()} { operation.Item2.Characteristics.ToSyntax() }", - ResolvedTypeKind.TupleType tuple => "(" + String.Join(",", + ResolvedTypeKind.TupleType tuple => "(" + string.Join(",", tuple.Item.Select(ToMarkdownLink) ) + ")", ResolvedTypeKind.UserDefinedType udt => udt.Item.ToMarkdownLink(), _ => type.Resolution.Tag switch - { - ResolvedTypeKind.Tags.BigInt => "BigInt", - ResolvedTypeKind.Tags.Bool => "Bool", - ResolvedTypeKind.Tags.Double => "Double", - ResolvedTypeKind.Tags.Int => "Int", - ResolvedTypeKind.Tags.Pauli => "Pauli", - ResolvedTypeKind.Tags.Qubit => "Qubit", - ResolvedTypeKind.Tags.Range => "Range", - ResolvedTypeKind.Tags.String => "String", - ResolvedTypeKind.Tags.UnitType => "Unit", - _ => "__invalid__" - } + { + ResolvedTypeKind.Tags.BigInt => "BigInt", + ResolvedTypeKind.Tags.Bool => "Bool", + ResolvedTypeKind.Tags.Double => "Double", + ResolvedTypeKind.Tags.Int => "Int", + ResolvedTypeKind.Tags.Pauli => "Pauli", + ResolvedTypeKind.Tags.Qubit => "Qubit", + ResolvedTypeKind.Tags.Range => "Range", + ResolvedTypeKind.Tags.String => "String", + ResolvedTypeKind.Tags.UnitType => "Unit", + _ => "__invalid__", + }, }; internal static string ToMarkdownLink(this UserDefinedType type) => @@ -406,7 +452,7 @@ internal static bool IsInCompilationUnit(this QsNamespaceElement element) => { QsNamespaceElement.QsCallable callable => callable.Item.IsInCompilationUnit(), QsNamespaceElement.QsCustomType type => type.Item.IsInCompilationUnit(), - _ => false + _ => false, }; internal static bool IsInCompilationUnit(this QsCallable callable) => diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs index 34bc8ccf0e..6f34fe20da 100644 --- a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs +++ b/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs @@ -43,14 +43,6 @@ public ProcessDocComments( this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, writer); } - public QsCompilation OnCompilation(QsCompilation compilation) => - new QsCompilation( - compilation.Namespaces - .Select(this.Namespaces.OnNamespace) - .ToImmutableArray(), - compilation.EntryPoints - ); - private class NamespaceTransformation : NamespaceTransformation { From 2c6f9a6decaf681e3131984a866909f664be8cbf Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 8 Oct 2020 15:05:35 -0700 Subject: [PATCH 44/74] Move documentation pipeline components into single folder. --- QsCompiler.sln | 4 ++-- build/manifest.ps1 | 2 +- build/pack.ps1 | 2 +- .../DocumentationGenerator/DocumentationGeneration.cs | 0 .../DocumentationGenerator/DocumentationGenerator.csproj | 0 .../DocumentationGenerator/DocumentationGenerator.props | 0 .../DocumentationGenerator/DocumentationWriter.cs | 0 .../DocumentationGenerator/Extensions.cs | 0 .../DocumentationGenerator/ProcessDocComments.cs | 0 .../DocumentationParser/DocBuilder.cs | 0 .../DocumentationParser/DocCallable.cs | 0 .../DocumentationParser/DocComment.cs | 0 .../DocumentationParser/DocItem.cs | 0 .../DocumentationParser/DocNamespace.cs | 0 .../DocumentationParser/DocUdt.cs | 0 .../DocumentationParser/DocumentationParser.csproj | 0 .../DocumentationParser/Properties/AssemblyInfo.cs | 0 .../DocumentationParser/Utils.cs | 0 .../Documentation/Summarizer}/README.md | 4 ++-- .../Documentation/Summarizer}/requirements.txt | 2 +- .../Documentation/Summarizer}/summarize_documentation.py | 0 src/QsCompiler/Compiler/Compiler.csproj | 2 +- src/QsCompiler/SyntaxProcessor/SyntaxProcessor.fsproj | 2 +- 23 files changed, 9 insertions(+), 9 deletions(-) rename src/{QsCompiler => Documentation}/DocumentationGenerator/DocumentationGeneration.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationGenerator/DocumentationGenerator.csproj (100%) rename src/{QsCompiler => Documentation}/DocumentationGenerator/DocumentationGenerator.props (100%) rename src/{QsCompiler => Documentation}/DocumentationGenerator/DocumentationWriter.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationGenerator/Extensions.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationGenerator/ProcessDocComments.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocBuilder.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocCallable.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocComment.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocItem.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocNamespace.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocUdt.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/DocumentationParser.csproj (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/Properties/AssemblyInfo.cs (100%) rename src/{QsCompiler => Documentation}/DocumentationParser/Utils.cs (100%) rename {utilities/summarize_documentation => src/Documentation/Summarizer}/README.md (72%) rename {utilities/summarize_documentation => src/Documentation/Summarizer}/requirements.txt (67%) rename {utilities/summarize_documentation => src/Documentation/Summarizer}/summarize_documentation.py (100%) diff --git a/QsCompiler.sln b/QsCompiler.sln index 79e9fe225c..6b888c9915 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -13,7 +13,7 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SyntaxProcessor", "src\QsCo EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TextProcessor", "src\QsCompiler\TextProcessor\TextProcessor.fsproj", "{57F1310F-9210-47A2-AEC5-DE2CF345D754}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentationParser", "src\QsCompiler\DocumentationParser\DocumentationParser.csproj", "{EB06DB1E-2B86-4279-81F9-D39B62B4AE0A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentationParser", "src\Documentation\DocumentationParser\DocumentationParser.csproj", "{EB06DB1E-2B86-4279-81F9-D39B62B4AE0A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LanguageServer", "src\QsCompiler\LanguageServer\LanguageServer.csproj", "{D21C9875-2E84-423B-B2CA-84103661F7E4}" EndProject @@ -47,7 +47,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B4A9484D EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library2", "src\QsCompiler\TestTargets\Libraries\Library2\Library2.csproj", "{E7E019AB-42F8-48AB-B80C-D33351F2C96A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentationGenerator", "src\QsCompiler\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentationGenerator", "src\Documentation\DocumentationGenerator\DocumentationGenerator.csproj", "{11311F0C-78CA-43A3-9C84-D7EA0AE9748C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/build/manifest.ps1 b/build/manifest.ps1 index c92d4ee016..9b2e3bb1a6 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -39,7 +39,7 @@ if ($Env:ENABLE_VSIX -ne "false") { "Microsoft.Quantum.DocumentationGenerator" ); Assemblies = $VsixAssemblies + @( - "./src/QsCompiler/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netstandard2.1/Microsoft.Quantum.DocumentationGenerator.dll", + "./src/Documentation/DocumentationGenerator/bin/$Env:BUILD_CONFIGURATION/netstandard2.1/Microsoft.Quantum.DocumentationGenerator.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsCompiler.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/Microsoft.Quantum.QsDocumentationParser.dll", "./src/QsCompiler/CommandLineTool/bin/$Env:BUILD_CONFIGURATION/netcoreapp3.1/qsc.dll", diff --git a/build/pack.ps1 b/build/pack.ps1 index 409b755d58..8be4e28f08 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -237,7 +237,7 @@ Publish-One '../src/QuantumSdk/Tools/BuildConfiguration/BuildConfiguration.cspro Pack-One '../src/QsCompiler/Compiler/Compiler.csproj' '-IncludeReferencedProjects' Pack-One '../src/QsCompiler/CommandLineTool/CommandLineTool.csproj' '-IncludeReferencedProjects' -Pack-Dotnet '../src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj' +Pack-Dotnet '../src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj' Pack-One '../src/ProjectTemplates/Microsoft.Quantum.ProjectTemplates.nuspec' Pack-One '../src/QuantumSdk/QuantumSdk.nuspec' diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGeneration.cs b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs similarity index 100% rename from src/QsCompiler/DocumentationGenerator/DocumentationGeneration.cs rename to src/Documentation/DocumentationGenerator/DocumentationGeneration.cs diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj b/src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj similarity index 100% rename from src/QsCompiler/DocumentationGenerator/DocumentationGenerator.csproj rename to src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props b/src/Documentation/DocumentationGenerator/DocumentationGenerator.props similarity index 100% rename from src/QsCompiler/DocumentationGenerator/DocumentationGenerator.props rename to src/Documentation/DocumentationGenerator/DocumentationGenerator.props diff --git a/src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs similarity index 100% rename from src/QsCompiler/DocumentationGenerator/DocumentationWriter.cs rename to src/Documentation/DocumentationGenerator/DocumentationWriter.cs diff --git a/src/QsCompiler/DocumentationGenerator/Extensions.cs b/src/Documentation/DocumentationGenerator/Extensions.cs similarity index 100% rename from src/QsCompiler/DocumentationGenerator/Extensions.cs rename to src/Documentation/DocumentationGenerator/Extensions.cs diff --git a/src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs similarity index 100% rename from src/QsCompiler/DocumentationGenerator/ProcessDocComments.cs rename to src/Documentation/DocumentationGenerator/ProcessDocComments.cs diff --git a/src/QsCompiler/DocumentationParser/DocBuilder.cs b/src/Documentation/DocumentationParser/DocBuilder.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/DocBuilder.cs rename to src/Documentation/DocumentationParser/DocBuilder.cs diff --git a/src/QsCompiler/DocumentationParser/DocCallable.cs b/src/Documentation/DocumentationParser/DocCallable.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/DocCallable.cs rename to src/Documentation/DocumentationParser/DocCallable.cs diff --git a/src/QsCompiler/DocumentationParser/DocComment.cs b/src/Documentation/DocumentationParser/DocComment.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/DocComment.cs rename to src/Documentation/DocumentationParser/DocComment.cs diff --git a/src/QsCompiler/DocumentationParser/DocItem.cs b/src/Documentation/DocumentationParser/DocItem.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/DocItem.cs rename to src/Documentation/DocumentationParser/DocItem.cs diff --git a/src/QsCompiler/DocumentationParser/DocNamespace.cs b/src/Documentation/DocumentationParser/DocNamespace.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/DocNamespace.cs rename to src/Documentation/DocumentationParser/DocNamespace.cs diff --git a/src/QsCompiler/DocumentationParser/DocUdt.cs b/src/Documentation/DocumentationParser/DocUdt.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/DocUdt.cs rename to src/Documentation/DocumentationParser/DocUdt.cs diff --git a/src/QsCompiler/DocumentationParser/DocumentationParser.csproj b/src/Documentation/DocumentationParser/DocumentationParser.csproj similarity index 100% rename from src/QsCompiler/DocumentationParser/DocumentationParser.csproj rename to src/Documentation/DocumentationParser/DocumentationParser.csproj diff --git a/src/QsCompiler/DocumentationParser/Properties/AssemblyInfo.cs b/src/Documentation/DocumentationParser/Properties/AssemblyInfo.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/Properties/AssemblyInfo.cs rename to src/Documentation/DocumentationParser/Properties/AssemblyInfo.cs diff --git a/src/QsCompiler/DocumentationParser/Utils.cs b/src/Documentation/DocumentationParser/Utils.cs similarity index 100% rename from src/QsCompiler/DocumentationParser/Utils.cs rename to src/Documentation/DocumentationParser/Utils.cs diff --git a/utilities/summarize_documentation/README.md b/src/Documentation/Summarizer/README.md similarity index 72% rename from utilities/summarize_documentation/README.md rename to src/Documentation/Summarizer/README.md index 9dfe93ee19..957db4479a 100644 --- a/utilities/summarize_documentation/README.md +++ b/src/Documentation/Summarizer/README.md @@ -6,6 +6,6 @@ producing namespace and TOC files from the gathered documentation. For example: ```bash -$ pipenv install -$ pipenv run python obj/qsharp/docs/*.md obj/qsharp/docs +$ pip install -r requirementx.txt +$ python obj/qsharp/docs/*.md obj/qsharp/docs ``` diff --git a/utilities/summarize_documentation/requirements.txt b/src/Documentation/Summarizer/requirements.txt similarity index 67% rename from utilities/summarize_documentation/requirements.txt rename to src/Documentation/Summarizer/requirements.txt index d55d361a5e..eb24756324 100644 --- a/utilities/summarize_documentation/requirements.txt +++ b/src/Documentation/Summarizer/requirements.txt @@ -1,3 +1,3 @@ python-frontmatter click -ruamel-yaml \ No newline at end of file +ruamel-yaml diff --git a/utilities/summarize_documentation/summarize_documentation.py b/src/Documentation/Summarizer/summarize_documentation.py similarity index 100% rename from utilities/summarize_documentation/summarize_documentation.py rename to src/Documentation/Summarizer/summarize_documentation.py diff --git a/src/QsCompiler/Compiler/Compiler.csproj b/src/QsCompiler/Compiler/Compiler.csproj index 2a5f429a9d..a82612086c 100644 --- a/src/QsCompiler/Compiler/Compiler.csproj +++ b/src/QsCompiler/Compiler/Compiler.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/QsCompiler/SyntaxProcessor/SyntaxProcessor.fsproj b/src/QsCompiler/SyntaxProcessor/SyntaxProcessor.fsproj index ee8e14a0ae..d32a850e53 100644 --- a/src/QsCompiler/SyntaxProcessor/SyntaxProcessor.fsproj +++ b/src/QsCompiler/SyntaxProcessor/SyntaxProcessor.fsproj @@ -23,7 +23,7 @@ - + From 738b22cb5eb2f489286129e70f9fa585bee8badd Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 8 Oct 2020 15:26:41 -0700 Subject: [PATCH 45/74] Misc path fixes. --- QsCompiler.sln | 2 +- .../DocumentationGenerator/DocumentationGenerator.csproj | 2 +- .../DocumentationGenerator/DocumentationWriter.cs | 8 ++++---- .../DocumentationParser/DocumentationParser.csproj | 4 ++-- .../Tests.DocGenerator/DocParsingTests.cs | 0 .../Tests.DocGenerator/DocWritingTests.cs | 0 .../Tests.DocGenerator/Tests.DocGenerator.csproj | 2 +- .../Tests.DocGenerator/Utils.cs | 0 8 files changed, 9 insertions(+), 9 deletions(-) rename src/{QsCompiler => Documentation}/Tests.DocGenerator/DocParsingTests.cs (100%) rename src/{QsCompiler => Documentation}/Tests.DocGenerator/DocWritingTests.cs (100%) rename src/{QsCompiler => Documentation}/Tests.DocGenerator/Tests.DocGenerator.csproj (93%) rename src/{QsCompiler => Documentation}/Tests.DocGenerator/Utils.cs (100%) diff --git a/QsCompiler.sln b/QsCompiler.sln index 6b888c9915..ca25e0d9f5 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -25,7 +25,7 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Core", "src\QsCompiler\Core EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Transformations", "src\QsCompiler\Transformations\Transformations.csproj", "{BA5D3733-09F1-4676-9CAC-99AD9A00AECB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.DocGenerator", "src\QsCompiler\Tests.DocGenerator\Tests.DocGenerator.csproj", "{256A6275-FC7F-42E9-9931-BC6EA6D0F31A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.DocGenerator", "src\Documentation\Tests.DocGenerator\Tests.DocGenerator.csproj", "{256A6275-FC7F-42E9-9931-BC6EA6D0F31A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLineTool", "src\QsCompiler\CommandLineTool\CommandLineTool.csproj", "{B15C4786-0D35-4E66-907F-94DA85FD5576}" EndProject diff --git a/src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj b/src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj index 9d89600c2a..8b7425c589 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj +++ b/src/Documentation/DocumentationGenerator/DocumentationGenerator.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs index a1b015ca5d..af29ab1c85 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs @@ -22,7 +22,7 @@ public class DocumentationWriter public DocumentationWriter(string outputPath, string? packageName) { - this.outputPath = outputPath; + this.OutputPath = outputPath; this.packageName = packageName; // If the output path is not null, make sure the directory exists. @@ -67,7 +67,7 @@ public async Task WriteOutput(QsNamespace ns, DocComment docComment) // Open a file to write the new doc to. await File.WriteAllTextAsync( - Path.Join(outputPath, $"{name.ToLowerInvariant()}.md"), + Path.Join(OutputPath, $"{name.ToLowerInvariant()}.md"), document ); } @@ -129,7 +129,7 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) // Open a file to write the new doc to. await File.WriteAllTextAsync( - Path.Join(outputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), + Path.Join(OutputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), document ); } @@ -205,7 +205,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) // Open a file to write the new doc to. await File.WriteAllTextAsync( - Path.Join(outputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), + Path.Join(OutputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), document ); } diff --git a/src/Documentation/DocumentationParser/DocumentationParser.csproj b/src/Documentation/DocumentationParser/DocumentationParser.csproj index b6992d5d78..0dc1a71b93 100644 --- a/src/Documentation/DocumentationParser/DocumentationParser.csproj +++ b/src/Documentation/DocumentationParser/DocumentationParser.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/src/QsCompiler/Tests.DocGenerator/DocParsingTests.cs b/src/Documentation/Tests.DocGenerator/DocParsingTests.cs similarity index 100% rename from src/QsCompiler/Tests.DocGenerator/DocParsingTests.cs rename to src/Documentation/Tests.DocGenerator/DocParsingTests.cs diff --git a/src/QsCompiler/Tests.DocGenerator/DocWritingTests.cs b/src/Documentation/Tests.DocGenerator/DocWritingTests.cs similarity index 100% rename from src/QsCompiler/Tests.DocGenerator/DocWritingTests.cs rename to src/Documentation/Tests.DocGenerator/DocWritingTests.cs diff --git a/src/QsCompiler/Tests.DocGenerator/Tests.DocGenerator.csproj b/src/Documentation/Tests.DocGenerator/Tests.DocGenerator.csproj similarity index 93% rename from src/QsCompiler/Tests.DocGenerator/Tests.DocGenerator.csproj rename to src/Documentation/Tests.DocGenerator/Tests.DocGenerator.csproj index a0328017db..f5884465dd 100644 --- a/src/QsCompiler/Tests.DocGenerator/Tests.DocGenerator.csproj +++ b/src/Documentation/Tests.DocGenerator/Tests.DocGenerator.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/QsCompiler/Tests.DocGenerator/Utils.cs b/src/Documentation/Tests.DocGenerator/Utils.cs similarity index 100% rename from src/QsCompiler/Tests.DocGenerator/Utils.cs rename to src/Documentation/Tests.DocGenerator/Utils.cs From bb8595f16f1828e1eb3258e14a7d295e1dbd322e Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 8 Oct 2020 15:46:44 -0700 Subject: [PATCH 46/74] Enforce QsharpDocGenerationMode values. --- src/QuantumSdk/Sdk/Sdk.targets | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 5c1faaee8a..07b945eae5 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -66,6 +66,15 @@ + + + <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe From 8e179eef8ed972e73fc23a1c84664564b719471a Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 8 Oct 2020 16:24:21 -0700 Subject: [PATCH 47/74] Consolidate with SyntaxTreeToQSharp --- .../DocumentationGenerator/Extensions.cs | 160 ++---------------- .../Transformations/QsharpCodeOutput.cs | 7 + 2 files changed, 17 insertions(+), 150 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/Extensions.cs b/src/Documentation/DocumentationGenerator/Extensions.cs index 0e6ec466cc..2ce3c3acce 100644 --- a/src/Documentation/DocumentationGenerator/Extensions.cs +++ b/src/Documentation/DocumentationGenerator/Extensions.cs @@ -33,7 +33,6 @@ namespace Microsoft.Quantum.Documentation internal interface IAttributeBuilder { public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute); - public QsNullable Location { get; } public T Build(); } @@ -41,13 +40,12 @@ internal interface IAttributeBuilder internal class Callable : IAttributeBuilder { private readonly QsCallable callable; + internal Callable(QsCallable callable) { this.callable = callable; } - public QsNullable Location => callable.Location; - public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute) => new Callable(callable.AddAttribute(attribute)); @@ -57,13 +55,12 @@ public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribu internal class Udt : IAttributeBuilder { private QsCustomType type; + internal Udt(QsCustomType type) { this.type = type; } - public QsNullable Location => type.Location; - public IAttributeBuilder AddAttribute(QsDeclarationAttribute attribute) => new Udt(type.AddAttribute(attribute)); @@ -75,6 +72,7 @@ internal static class Extensions internal static IAttributeBuilder AttributeBuilder( this QsCallable callable ) => new Callable(callable); + internal static IAttributeBuilder AttributeBuilder( this QsCustomType type ) => new Udt(type); @@ -172,154 +170,16 @@ this IAttributeBuilder builder, string attributeName, IDictionary + internal static string ToSyntax(this QsCustomType type) => SyntaxTreeToQsharp.Default.ToCode(type); - internal static T WithSideEffect(this T value, Action effect) - { - effect(); - return value; - } - - internal static string ToSyntax(this QsTypeItem item, Action? onDiagnostic = null) => - item switch - { - QsTypeItem.Anonymous anon => anon.Item.ToSyntax(), - QsTypeItem.Named named => $"{named.Item.VariableName.Value} : {named.Item.Type.ToSyntax()}", - _ => "__UNKNOWN__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for type item {item}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }; - - internal static string ToSyntax(this QsTuple items, Action? onDiagnostic = null) => - items switch - { - QsTuple.QsTuple tuple => $@"({ - String.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) - })", - QsTuple.QsTupleItem item => item.Item.ToSyntax(), - _ => "__UNKNOWN__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for type items {items}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }; - - internal static string ToSyntax( - this QsTuple> items, - Action? onDiagnostic = null - ) => - items switch - { - QsTuple>.QsTuple tuple => $@"({ - string.Join(", ", tuple.Item.Select(innerItem => innerItem.ToSyntax())) - })", - QsTuple>.QsTupleItem item => item.Item.ToSyntax(), - _ => "__UNKNOWN__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for tuple items {items}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }; - - internal static string ToSyntax(this LocalVariableDeclaration symbol, Action? onDiagnostic = null) => - $@"{symbol.VariableName switch - { - QsLocalSymbol.ValidName name => name.Item.Value, - _ => "__INVALID__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for local symbol {symbol}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }} : {symbol.Type.ToSyntax()}"; - - internal static string ToSyntax(this QsCustomType type, Action? onDiagnostic = null) => - $@"newtype {type.FullName.Name.Value} = { - string.Join(",", type.TypeItems.ToSyntax(onDiagnostic)) - };"; - - internal static string ToSyntax(this ResolvedCharacteristics characteristics, Action? onDiagnostic = null) => - characteristics.SupportedFunctors.ValueOr(null) switch - { - null => "", - { Count: 0 } => "", - var functors => $@" is {String.Join(" + ", - functors.Select(functor => functor.Tag switch - { - QsFunctor.Tags.Adjoint => "Adj", - QsFunctor.Tags.Controlled => "Ctl", - _ => "__UNKNOWN__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for characteristic {functor}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }) - )}" - }; + internal static string ToSyntax(this ResolvedCharacteristics characteristics) => + SyntaxTreeToQsharp.CharacteristicsExpression(characteristics); - internal static string ToSyntax(this QsCallable callable, Action? onDiagnostic = null) - { - var kind = callable.Kind.Tag switch - { - QsCallableKind.Tags.Function => "function", - QsCallableKind.Tags.Operation => "operation", - QsCallableKind.Tags.TypeConstructor => "function", - _ => "__UNKNOWN__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for type callable kind {callable.Kind}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }; - var modifiers = callable.Modifiers.Access.Tag switch - { - AccessModifier.Tags.DefaultAccess => "", - AccessModifier.Tags.Internal => "internal ", - _ => "__UNKNOWN__".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for access modifier {callable.Modifiers.Access}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - }; - var typeParameters = callable.Signature.TypeParameters switch - { - { Length: 0 } => "", - var typeParams => $@"<{ - string.Join(", ", typeParams.Select( - param => param switch - { - QsLocalSymbol.ValidName name => $"'{name.Item.Value}", - _ => "{invalid}".WithSideEffect( - () => onDiagnostic?.Invoke(new IRewriteStep.Diagnostic - { - Message = $"Failed to generate syntax for type parameter {param}.", - Severity = CodeAnalysis.DiagnosticSeverity.Error, - }) - ), - } - )) - }>", - }; - var input = callable.ArgumentTuple.ToSyntax(onDiagnostic); - var output = callable.Signature.ReturnType.ToSyntax(); - var characteristics = callable.Signature.Information.Characteristics.ToSyntax(onDiagnostic); - return $"{modifiers}{kind} {callable.FullName.Name.Value}{typeParameters}{input} : {output}{characteristics}"; - } + internal static string ToSyntax(this QsCallable callable, Action? onDiagnostic = null) => + SyntaxTreeToQsharp.DeclarationSignature( + callable, SyntaxTreeToQsharp.Default.ToCode + ); internal static string MaybeWithSection(this string document, string name, string? contents) => contents == null || contents.Trim().Length == 0 diff --git a/src/QsCompiler/Transformations/QsharpCodeOutput.cs b/src/QsCompiler/Transformations/QsharpCodeOutput.cs index ad6d869e34..e991fa91bf 100644 --- a/src/QsCompiler/Transformations/QsharpCodeOutput.cs +++ b/src/QsCompiler/Transformations/QsharpCodeOutput.cs @@ -128,6 +128,13 @@ public string ToCode(QsExpressionKind k) public string ToCode(TypedExpression ex) => this.ToCode(ex.Expression); + public string ToCode(QsCustomType type) + { + var nrPreexistingLines = this.SharedState.NamespaceOutputHandle.Count; + this.Namespaces.OnTypeDeclaration(type); + return string.Join(Environment.NewLine, this.SharedState.NamespaceOutputHandle.Skip(nrPreexistingLines)); + } + public string ToCode(QsStatementKind stmKind) { var nrPreexistingLines = this.SharedState.StatementOutputHandle.Count; From 3b7440d74fba672565fdbcdc3949bc03cba50e8a Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 8 Oct 2020 16:45:54 -0700 Subject: [PATCH 48/74] Document new SDK properties. --- src/QuantumSdk/README.md | 118 ++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/src/QuantumSdk/README.md b/src/QuantumSdk/README.md index 26501c5c4e..c77a9cc048 100644 --- a/src/QuantumSdk/README.md +++ b/src/QuantumSdk/README.md @@ -3,14 +3,14 @@ ## Content ## -The NuGet package Microsoft.Quantum.Sdk serves a .NET Core Sdk for developing quantum applications, meaning it acts as [shared SDK Component](https://docs.microsoft.com/en-us/dotnet/core/tools/cli-msbuild-architecture#the-tooling-layers). +The NuGet package Microsoft.Quantum.Sdk serves a .NET Core Sdk for developing quantum applications, meaning it acts as [shared SDK Component](https://docs.microsoft.com/en-us/dotnet/core/tools/cli-msbuild-architecture#the-tooling-layers). It contains the properties and targets that define the compilation process for Q# projects, tools used as part of the build, as well as some project system support for Q# files. It in particular also provides the support for executing a compilation step defined in a package or project reference as part of the compilation process. See [this section](#extending-the-q#-compiler) for more details. -The Sdk includes all \*.qs files within the project directory as well as the Q# standard libraries by default. No additional reference to `Microsoft.Quantum.Standard` is needed. For more details see the [section on defined properties](#defined-project-properties) below. +The Sdk includes all \*.qs files within the project directory as well as the Q# standard libraries by default. No additional reference to `Microsoft.Quantum.Standard` is needed. For more details see the [section on defined properties](#defined-project-properties) below. ## Using the Sdk ## -To use the Quantum Sdk simply list the NuGet package as Sdk at the top of your project file: +To use the Quantum Sdk simply list the NuGet package as Sdk at the top of your project file: ``` ... @@ -18,7 +18,7 @@ To use the Quantum Sdk simply list the NuGet package as Sdk at the top of your p ``` See also the [MSBuild documentation](https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2019). -If you would like to build the Microsoft.Quantum.Sdk NuGet package from source, first run the `bootstrap.ps1` script in the root of this repository and then run the `build/pack.ps1` script. You will find the built package in the generated `drops` folder under `nugets`. Simply add the package to your local NuGet folder to start using it. +If you would like to build the Microsoft.Quantum.Sdk NuGet package from source, first run the `bootstrap.ps1` script in the root of this repository and then run the `build/pack.ps1` script. You will find the built package in the generated `drops` folder under `nugets`. Simply add the package to your local NuGet folder to start using it. [comment]: # (TODO: add a section on specifying an execution target) @@ -32,7 +32,7 @@ Any project that uses the Quantum Sdk can easily incorporate custom compilation ``` Marking all assets as private by adding a `PrivateAssets="All"` attribute is generally a good practice if the reference is a development only dependency, which is often the case for assemblies that implement rewrite steps. -A custom compilation step is defined by a class that implements the [IRewriteStep interface](https://github.com/microsoft/qsharp-compiler/blob/master/src/QsCompiler/Compiler/PluginInterface.cs). The output assembly of a project reference or any .NET Core library contained in a package reference marked as qsc reference is loaded during compilation and searched for classes implementing the `IRewriteStep` interface. Any such class is instantiated using the default constructor, and the implemented transformation is executed. +A custom compilation step is defined by a class that implements the [IRewriteStep interface](https://github.com/microsoft/qsharp-compiler/blob/master/src/QsCompiler/Compiler/PluginInterface.cs). The output assembly of a project reference or any .NET Core library contained in a package reference marked as qsc reference is loaded during compilation and searched for classes implementing the `IRewriteStep` interface. Any such class is instantiated using the default constructor, and the implemented transformation is executed. [comment]: # (TODO: add a section detailing the IRewriteStep interface, and link it here) @@ -42,41 +42,41 @@ The order in which these steps are executed can be configured by specifying thei ... ``` -If no priority is specified, the priority for that reference is set to zero. -Steps defined within packages or projects with higher priority are executed first. If several classes within a certain reference implement the `IRewriteStep` interface, then these steps are executed according to their priority specified as part of the interface. The priority defined for the project or package reference takes precedence, such that the priorities defined by the interface property are not compared across assemblies. +If no priority is specified, the priority for that reference is set to zero. +Steps defined within packages or projects with higher priority are executed first. If several classes within a certain reference implement the `IRewriteStep` interface, then these steps are executed according to their priority specified as part of the interface. The priority defined for the project or package reference takes precedence, such that the priorities defined by the interface property are not compared across assemblies. [comment]: # (TODO: describe how to limit included rewrite steps to a particular execution target) -An example for defining custom compilation steps in a referenced .NET Core project can be found [here](https://github.com/microsoft/qsharp-compiler/tree/master/examples). -See the [this section](#packaging) for more detail on how to package a Q# compiler extension to distribute it as a NuGet package. +An example for defining custom compilation steps in a referenced .NET Core project can be found [here](https://github.com/microsoft/qsharp-compiler/tree/master/examples). +See the [this section](#packaging) for more detail on how to package a Q# compiler extension to distribute it as a NuGet package. ### Injected C# code ### -It is possible to inject C# code into Q# packages e.g. for integration purposes. By default the Sdk is configured to do just that, see also the section on [defined properties](#defined-project-properties). That code may be generated as part of a custom rewrite step, e.g. if the code generation requires information about the Q# compilation. +It is possible to inject C# code into Q# packages e.g. for integration purposes. By default the Sdk is configured to do just that, see also the section on [defined properties](#defined-project-properties). That code may be generated as part of a custom rewrite step, e.g. if the code generation requires information about the Q# compilation. The Sdk defines a couple of build targets that can be redefined to run certain tasks before important build stages. These targets do nothing by default and merely serve as handles to easily integrate into the build process. -The following such targets are currently available: +The following such targets are currently available: -- `BeforeQsharpCompile`: -The target will execute right before the Q# compiler is invoked. All assembly references and the paths to all qsc references will be resolved at that time. +- `BeforeQsharpCompile`: +The target will execute right before the Q# compiler is invoked. All assembly references and the paths to all qsc references will be resolved at that time. -- `BeforeCsharpCompile`: -The target will execute right before the C# compiler is invoked. All Q# compilation steps will have completed at that time, and in particular all rewrite steps will have been executed. +- `BeforeCsharpCompile`: +The target will execute right before the C# compiler is invoked. All Q# compilation steps will have completed at that time, and in particular all rewrite steps will have been executed. -For example, if a qsc reference contains a rewrite step that generates C# code during transformation, that code can be included into the built dll by adding the following target to the project file: +For example, if a qsc reference contains a rewrite step that generates C# code during transformation, that code can be included into the built dll by adding the following target to the project file: ``` - + ``` ### Distributing Q# compiler extensions as NuGet packages ### -In order to avoid a dependency of the Q# build targets on the Restore target, we require that NuGet packages containing Q# compiler extensions define a property that contains the path to the dll to load. This is done by including a file with MSBuild props in the package, following the instructions [here](https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#include-msbuild-props-and-targets-in-a-package). +In order to avoid a dependency of the Q# build targets on the Restore target, we require that NuGet packages containing Q# compiler extensions define a property that contains the path to the dll to load. This is done by including a file with MSBuild props in the package, following the instructions [here](https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#include-msbuild-props-and-targets-in-a-package). The content of the file should be similar to the following, with `Package_Name` being replace by the name of your package after replacing dots by underscore, and `Package.Name` should be replaced by the assembly name of your package: @@ -88,111 +88,115 @@ The content of the file should be similar to the following, with `Package_Name` $(MSBuildThisFileDirectory)/../lib/netstandard2.1/Package.Name.dll - + ``` -This [example](https://github.com/microsoft/qsharp-compiler/tree/master/examples/CompilerExtensions/ExtensionPackage) provides a template for packaging a Q# compiler extension. +This [example](https://github.com/microsoft/qsharp-compiler/tree/master/examples/CompilerExtensions/ExtensionPackage) provides a template for packaging a Q# compiler extension. -If you develop a NuGet package to extend the Q# compilation process, we recommend to distribute it as a self-contained package to avoid issues due to references that could not be resolved. Each qsc reference is loaded into its own context to avoid issues when several references depend on different versions of the same package. +If you develop a NuGet package to extend the Q# compilation process, we recommend to distribute it as a self-contained package to avoid issues due to references that could not be resolved. Each qsc reference is loaded into its own context to avoid issues when several references depend on different versions of the same package. ### Troubleshooting compiler extensions ### -The compiler attempts to load rewrite steps even if these have been compiled against a different compiler version. While we do our best to mitigate issue due to a version mismatch, it is generally recommended to use compiler extensions that are compiled against the same compiler package version as the Sdk version of the project. +The compiler attempts to load rewrite steps even if these have been compiled against a different compiler version. While we do our best to mitigate issue due to a version mismatch, it is generally recommended to use compiler extensions that are compiled against the same compiler package version as the Sdk version of the project. When a rewrite steps fails to execute, setting the `QscVerbosity` to "Detailed" or "Diagnostic" will log the encountered exception with stack trace: ``` Detailed ``` -A `FileNotFoundException` will be raised if a compiler extension attempts to load a reference that either could not be found, or could not be loaded for other reasons. +A `FileNotFoundException` will be raised if a compiler extension attempts to load a reference that either could not be found, or could not be loaded for other reasons. By default, the compiler will search the project output directory for a suitable assembly in case a dependency cannot be found. -If such an exception occurs during a compilation step loaded from a package reference, the issue may be resolved by adding the package containing the missing dll to the project or by copying the missing dll to the output directory. +If such an exception occurs during a compilation step loaded from a package reference, the issue may be resolved by adding the package containing the missing dll to the project or by copying the missing dll to the output directory. If such an exception occurs during a compilation step loaded from a project reference, issue may be resolved by defining the property ``` true ``` -in the project that implements the compilation step. +in the project that implements the compilation step. ## Defined project properties ## -The Sdk defines the following properties for each project using it: +The Sdk defines the following properties for each project using it: -- `QsharpLangVersion`: +- `QsharpLangVersion`: The version of the Q# language specification. -- `QuantumSdkVersion`: +- `QuantumSdkVersion`: The NuGet version of the Sdk package. -The following properties can be configured to customize the build: +The following properties can be configured to customize the build: -- `AdditionalQscArguments`: -May contain additional arguments to pass to the Q# command line compiler. Valid additional arguments are `--emit-dll`, or `--no-warn` followed by any number of integers specifying the warnings to ignore. +- `AdditionalQscArguments`: +May contain additional arguments to pass to the Q# command line compiler. Valid additional arguments are `--emit-dll`, or `--no-warn` followed by any number of integers specifying the warnings to ignore. -- `CsharpGeneration`: -Specifies whether to generate C# code as part of the compilation process. Setting this property to false may prevent certain interoperability features or integration with other pieces of the Quantum Development Kit. +- `CsharpGeneration`: +Specifies whether to generate C# code as part of the compilation process. Setting this property to false may prevent certain interoperability features or integration with other pieces of the Quantum Development Kit. - `DefaultSimulator`: -Specifies the simulator to use by default for execution. Valid values are QuantumSimulator, ToffoliSimulator, ResourcesEstimator, or the fully qualified name of a custom simulator. +Specifies the simulator to use by default for execution. Valid values are QuantumSimulator, ToffoliSimulator, ResourcesEstimator, or the fully qualified name of a custom simulator. -- `IncludeQsharpCorePackages`: -Specifies whether the packages providing the basic language support for Q# are referenced. This property is set to true by default. If set to false, the Sdk will not reference any Q# libraries. +- `IncludeQsharpCorePackages`: +Specifies whether the packages providing the basic language support for Q# are referenced. This property is set to true by default. If set to false, the Sdk will not reference any Q# libraries. - `IncludeProviderPackages`: Specifies whether the packages for specific hardware providers should be automatically included based on the specified `ExecutionTarget`. This property is set to true by default. If set to false, the Sdk will not automatically reference any provider packages. -- `QscExe`: -The command to invoke the Q# compiler. The value set by default invokes the Q# compiler that is packaged as tool with the Sdk. The default value can be accessed via the `DefaultQscExe` property. +- `QscExe`: +The command to invoke the Q# compiler. The value set by default invokes the Q# compiler that is packaged as tool with the Sdk. The default value can be accessed via the `DefaultQscExe` property. -- `QscVerbosity`: +- `QscVerbosity`: Defines the verbosity of the Q# compiler. Recognized values are: Quiet, Minimal, Normal, Detailed, and Diagnostic. -- `QsharpDocsGeneration`: -Specified whether to generate yml documentation for the compiled Q# code. The default value is "false". +- `QsharpDocsGeneration`: +Specified whether to generate yml documentation for the compiled Q# code. The default value is "false". -- `QsharpDocsOutputPath`: -Directory where any generated documentation will be saved. +- `QsharpDocsOutputPath`: +Directory where any generated documentation will be saved. + +- `QsharpDocsGenerationMode`: Specifies whether to use the legacy YAML-based documentation generation engine, or the newer engine that outputs directly to Markdown. Recognized values are: `markdown`, and `yaml`. + +- `QsharpDocsPackageId`: Specifies the package ID that should appear in generated documentation. Set to `PackageId` by default, but can be overriden to allow for documenting parts of metapackages. [comment]: # (TODO: document QscBuildConfigExe, QscBuildConfigOutputPath) ## Defined item groups ## -The following configurable item groups are used by the Sdk: +The following configurable item groups are used by the Sdk: -- `PackageLoadFallbackFolder`: -Contains the directories where the Q# compiler will look for a suitable dll if a qsc reference or one if its dependencies cannot be found. By default, the project output path is included in this item group. +- `PackageLoadFallbackFolder`: +Contains the directories where the Q# compiler will look for a suitable dll if a qsc reference or one if its dependencies cannot be found. By default, the project output path is included in this item group. -- `PackageReference`: +- `PackageReference`: Contains all referenced NuGet packages. Package references for which the `IsQscReference` attribute is set to "true" may extend the Q# compiler and any implemented rewrite steps will be executed as part of the compilation process. See [this section](#extending-the-q#-compiler) for more details. -- `ProjectReference`: +- `ProjectReference`: Contains all referenced projects. Project references for which the `IsQscReference` attribute is set to "true" may extend the Q# compiler and any implemented rewrite steps will be executed as part of the compilation process. See [this section](#extending-the-q#-compiler) for more details. -- `QsharpCompile`: +- `QsharpCompile`: Contains all Q# source files included in the compilation. # Sdk Packages # A NuGet package of type `Sdk` enjoys certain privileges in terms of when and how its content is loaded. -To understand how the content in this package works it is useful to understand how the properties, item groups, and targets defined in the Sdk are combined with those defined by a specific project. -The order of evaluation for properties and item groups is roughly the following: +To understand how the content in this package works it is useful to understand how the properties, item groups, and targets defined in the Sdk are combined with those defined by a specific project. +The order of evaluation for properties and item groups is roughly the following: - Properties defined in \*.props files of the Sdk - Properties defined or included by the specific project file - Properties defined in *.targets files of the Sdk - Item groups defined in *.props files of the Sdk - Item groups defined or included by the specific project file -- Item groups defined in *.targets files of the Sdk +- Item groups defined in *.targets files of the Sdk -Similar considerations apply for the definition of targets. MSBuild will overwrite targets if multiple targets with the same name are defined. In that case, the target is replaced in its entirety independent on whether the values for `DependsOn`, `BeforeTarget`, and `AfterTarget` match - i.e. those will be overwritten. However, a target can be "anchored" by the surrounding targets' specifications of their dependencies, see e.g. the defined `BeforeCsharpCompile` target. +Similar considerations apply for the definition of targets. MSBuild will overwrite targets if multiple targets with the same name are defined. In that case, the target is replaced in its entirety independent on whether the values for `DependsOn`, `BeforeTarget`, and `AfterTarget` match - i.e. those will be overwritten. However, a target can be "anchored" by the surrounding targets' specifications of their dependencies, see e.g. the defined `BeforeCsharpCompile` target. ## Load context in .NET Core -To avoid issues with conflicting packages, we load each Q# compiler extension into its own context. For more information, see the Core CLR [design docs](https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/assemblyloadcontext.md). +To avoid issues with conflicting packages, we load each Q# compiler extension into its own context. For more information, see the Core CLR [design docs](https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/assemblyloadcontext.md). ## Known Issues ## The following issues and PRs may be of interest when using the Sdk: -> https://github.com/NuGet/Home/issues/8692 -> https://github.com/dotnet/runtime/issues/949 -> https://github.com/NuGet/NuGet.Client/pull/3170 +> https://github.com/NuGet/Home/issues/8692 +> https://github.com/dotnet/runtime/issues/949 +> https://github.com/NuGet/NuGet.Client/pull/3170 From 6d49a2d0e462430939cb9554c878da60922802ba Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 9 Oct 2020 10:35:49 -0700 Subject: [PATCH 49/74] Deprecate YAML-based generator entirely. --- src/Documentation/DocumentationParser/DocBuilder.cs | 1 + src/Documentation/DocumentationParser/DocCallable.cs | 2 ++ src/Documentation/DocumentationParser/DocItem.cs | 2 ++ .../DocumentationParser/DocNamespace.cs | 3 +++ .../DefaultItems/DefaultItems.props.v.template | 2 -- src/QuantumSdk/README.md | 2 -- src/QuantumSdk/Sdk/Sdk.props | 2 +- src/QuantumSdk/Sdk/Sdk.targets | 12 +----------- 8 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/Documentation/DocumentationParser/DocBuilder.cs b/src/Documentation/DocumentationParser/DocBuilder.cs index 635d00cb0b..a6e6a50832 100644 --- a/src/Documentation/DocumentationParser/DocBuilder.cs +++ b/src/Documentation/DocumentationParser/DocBuilder.cs @@ -15,6 +15,7 @@ namespace Microsoft.Quantum.QsCompiler.Documentation /// This class contains the functionality for writing all of the documentation /// YAML files for an entire compilation. /// + [Obsolete("The YAML-based documentation builder has been replaced by the Markdown-based DocumentationGenerator.")] public class DocBuilder { private readonly string rootDocPath; diff --git a/src/Documentation/DocumentationParser/DocCallable.cs b/src/Documentation/DocumentationParser/DocCallable.cs index 4a3e0c868a..e58ea663b7 100644 --- a/src/Documentation/DocumentationParser/DocCallable.cs +++ b/src/Documentation/DocumentationParser/DocCallable.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; @@ -57,6 +58,7 @@ internal DocCallable(string ns, QsCallable callableObj) /// Writes a YAML representation of this callable to a text writer. /// /// The writer to output to + [Obsolete("Writing YAML documentation is no longer supported.")] internal override void WriteToFile(TextWriter text) { YamlNode BuildInputNode() diff --git a/src/Documentation/DocumentationParser/DocItem.cs b/src/Documentation/DocumentationParser/DocItem.cs index 00a379b152..265a8708ea 100644 --- a/src/Documentation/DocumentationParser/DocItem.cs +++ b/src/Documentation/DocumentationParser/DocItem.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; @@ -77,6 +78,7 @@ internal DocItem( /// Writes a full YAML representation of this item to the given text stream. /// /// The text stream to output to + [Obsolete("Writing YAML documentation is no longer supported.")] internal abstract void WriteToFile(TextWriter text); } } diff --git a/src/Documentation/DocumentationParser/DocNamespace.cs b/src/Documentation/DocumentationParser/DocNamespace.cs index a683163016..9d1dae9e1c 100644 --- a/src/Documentation/DocumentationParser/DocNamespace.cs +++ b/src/Documentation/DocumentationParser/DocNamespace.cs @@ -198,6 +198,7 @@ int CompareUids(YamlNode node1, YamlNode node2) => /// specified directory. /// /// The directory to write the files to + [Obsolete("Writing YAML documentation is no longer supported.")] internal void WriteItemsToDirectory(string directoryPath, List errors) { void WriteItem(DocItem i) @@ -221,6 +222,7 @@ void WriteItem(DocItem i) /// /// The mapping node representing the preexisting contents of this namespace's YAML file. /// + [Obsolete("Writing YAML documentation is no longer supported.")] internal void WriteToStream(Stream stream, YamlMappingNode? rootNode = null) { string ToSequenceKey(string itemTypeName) @@ -323,6 +325,7 @@ string ToSequenceKey(string itemTypeName) /// Writes the YAML file for this namespace. /// /// The directory to write the file to + [Obsolete("Writing YAML documentation is no longer supported.")] internal void WriteToFile(string directoryPath) { var rootNode = Utils.ReadYamlFile(directoryPath, this.name) as YamlMappingNode; diff --git a/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template b/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template index 650b312e4e..560d4130d4 100644 --- a/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template +++ b/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template @@ -35,8 +35,6 @@ true false $(PackageId) - - markdown false dotnet "$(MSBuildThisFileDirectory)../tools/utils/Microsoft.Quantum.Sdk.BuildConfiguration.dll" $(DefaultQscBuildConfigExe) diff --git a/src/QuantumSdk/README.md b/src/QuantumSdk/README.md index c77a9cc048..8bcbfdb0ac 100644 --- a/src/QuantumSdk/README.md +++ b/src/QuantumSdk/README.md @@ -153,8 +153,6 @@ Specified whether to generate yml documentation for the compiled Q# code. The de - `QsharpDocsOutputPath`: Directory where any generated documentation will be saved. -- `QsharpDocsGenerationMode`: Specifies whether to use the legacy YAML-based documentation generation engine, or the newer engine that outputs directly to Markdown. Recognized values are: `markdown`, and `yaml`. - - `QsharpDocsPackageId`: Specifies the package ID that should appear in generated documentation. Set to `PackageId` by default, but can be overriden to allow for documenting parts of metapackages. [comment]: # (TODO: document QscBuildConfigExe, QscBuildConfigOutputPath) diff --git a/src/QuantumSdk/Sdk/Sdk.props b/src/QuantumSdk/Sdk/Sdk.props index 461bae521d..56d4ce0309 100644 --- a/src/QuantumSdk/Sdk/Sdk.props +++ b/src/QuantumSdk/Sdk/Sdk.props @@ -36,7 +36,7 @@ - diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 07b945eae5..478c2e6731 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -66,20 +66,10 @@ - - - <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe <_QscCommandOutputFlag>--output "$(GeneratedFilesOutputPath)" - <_QscCommandDocsFlag Condition="$(QsharpDocsGeneration) AND ('$(QsharpDocGenerationMode)' == 'yaml')">--doc "$(QsharpDocsOutputPath)" <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" <_QscCommandReferencesFlag Condition="@(ResolvedQsharpReferences->Count()) > 0">--references "@(ResolvedQsharpReferences,'" "')" <_QscCommandLoadFlag Condition="@(_PrioritizedResolvedQscReferences->Count()) > 0">--load "@(_PrioritizedResolvedQscReferences,'" "')" @@ -94,7 +84,7 @@ <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" - <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandDocsFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) + <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) <_QscCommandArgsFile>$(QscBuildConfigOutputPath)qsc.rsp From f8340c64007b0ce397b02bf9128f9de2b6112e22 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 9 Oct 2020 10:40:48 -0700 Subject: [PATCH 50/74] Remove --doc option from compiler. --- src/QsCompiler/CommandLineTool/Commands/Build.cs | 8 -------- src/QsCompiler/Compiler/CompilationLoader.cs | 15 --------------- 2 files changed, 23 deletions(-) diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index f59a244130..c91c1c5727 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -53,13 +53,6 @@ public static IEnumerable UsageExamples HelpText = "Destination folder where the output of the compilation will be generated.")] public string OutputFolder { get; set; } - [Option( - "doc", - Required = false, - SetName = CODE_MODE, - HelpText = "Destination folder where documentation will be generated.")] - public string DocFolder { get; set; } - [Option( "proj", Required = false, @@ -205,7 +198,6 @@ public static int Run(BuildOptions options, ConsoleLogger logger) GenerateFunctorSupport = true, SkipSyntaxTreeTrimming = options.TrimLevel == 0, AttemptFullPreEvaluation = options.TrimLevel > 2, - DocumentationOutputFolder = options.DocFolder, BuildOutputFolder = options.OutputFolder ?? (usesPlugins ? "." : null), DllOutputPath = options.EmitDll ? " " : null, // set to e.g. an empty space to generate the dll in the same location as the .bson file IsExecutable = options.MakeExecutable, diff --git a/src/QsCompiler/Compiler/CompilationLoader.cs b/src/QsCompiler/Compiler/CompilationLoader.cs index 71a7b8bc4f..4803b93999 100644 --- a/src/QsCompiler/Compiler/CompilationLoader.cs +++ b/src/QsCompiler/Compiler/CompilationLoader.cs @@ -279,7 +279,6 @@ internal bool Success(Configuration options) => this.WasSuccessful(!options.SkipSyntaxTreeTrimming, this.TreeTrimming) && this.WasSuccessful(options.ConvertClassicalControl, this.ConvertClassicalControl) && this.WasSuccessful(options.IsExecutable && !options.SkipMonomorphization, this.Monomorphization) && - this.WasSuccessful(options.DocumentationOutputFolder != null, this.Documentation) && this.WasSuccessful(options.SerializeSyntaxTree, this.Serialization) && this.WasSuccessful(options.BuildOutputFolder != null, this.BinaryFormat) && this.WasSuccessful(options.DllOutputPath != null, this.DllGeneration) && @@ -607,20 +606,6 @@ Func Execute(int index) => () => } } - if (this.config.DocumentationOutputFolder != null) - { - this.RaiseCompilationTaskStart("OutputGeneration", "DocumentationGeneration"); - this.compilationStatus.Documentation = Status.Succeeded; - var docsFolder = Path.GetFullPath(string.IsNullOrWhiteSpace(this.config.DocumentationOutputFolder) ? "." : this.config.DocumentationOutputFolder); - void OnDocException(Exception ex) => this.LogAndUpdate(ref this.compilationStatus.Documentation, ex); - var docsGenerated = this.VerifiedCompilation != null && DocBuilder.Run(docsFolder, this.VerifiedCompilation.SyntaxTree.Values, this.VerifiedCompilation.SourceFiles, onException: OnDocException); - if (!docsGenerated) - { - this.LogAndUpdate(ref this.compilationStatus.Documentation, ErrorCode.DocGenerationFailed, Enumerable.Empty()); - } - this.RaiseCompilationTaskEnd("OutputGeneration", "DocumentationGeneration"); - } - this.RaiseCompilationTaskEnd("OverallCompilation", "OutputGeneration"); this.RaiseCompilationTaskEnd(null, "OverallCompilation"); } From 985a24d5c35e4c6906475749931984e5ef8f54e4 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 9 Oct 2020 14:14:22 -0700 Subject: [PATCH 51/74] Apply style rules, add API documentation comments. --- .../DocumentationWriter.cs | 84 +++++++++++++++---- .../ProcessDocComments.cs | 39 +++++++-- .../DocumentationParser/DocNamespace.cs | 3 +- 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs index af29ab1c85..0c386f93e3 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs @@ -12,14 +12,40 @@ namespace Microsoft.Quantum.Documentation { + /// + /// Writes API documentation files as Markdown to a given output + /// directory, using parsed API documentation comments. + /// public class DocumentationWriter { + /// + /// Path to which output documentation files should be written. + /// public string OutputPath { get; } private readonly string? packageName; - public string? PackageName => packageName; + + /// + /// The name of the NuGet package whose contents are being + /// documented, or null if the documentation being written + /// does not concern a particular package. + /// + public string? PackageName => this.packageName; + private readonly string PackageLink; + /// + /// Initializes a new instance of the + /// class. + /// + /// + /// The path to which documentation files should be written. + /// + /// + /// The name of the NuGet package being documented, or null + /// if the documentation to be written by this object does not + /// relate to a particular package. + /// public DocumentationWriter(string outputPath, string? packageName) { this.OutputPath = outputPath; @@ -36,6 +62,16 @@ public DocumentationWriter(string outputPath, string? packageName) : $"Package: [{PackageName}](https://nuget.org/packages/{PackageName})\n"; } + /// + /// Given a documentation comment describing a Q# namespace, + /// writes a Markdown file documenting that namespace to + /// . + /// + /// The Q# namespace being documented. + /// + /// The API documentation comment describing . + /// + /// A representing the result of the asynchronous operation. public async Task WriteOutput(QsNamespace ns, DocComment docComment) { var name = ns.Name.Value; @@ -67,11 +103,21 @@ public async Task WriteOutput(QsNamespace ns, DocComment docComment) // Open a file to write the new doc to. await File.WriteAllTextAsync( - Path.Join(OutputPath, $"{name.ToLowerInvariant()}.md"), + Path.Join(this.OutputPath, $"{name.ToLowerInvariant()}.md"), document ); } - + + /// + /// Given a documentation comment describing a Q# user-defined type + /// declaration, writes a Markdown file documenting that UDT + /// declaration to . + /// + /// The Q# UDT being documented. + /// + /// The API documentation comment describing . + /// + /// A representing the result of the asynchronous operation. public async Task WriteOutput(QsCustomType type, DocComment docComment) { var namedItemDeclarations = type.TypeItems.ToDictionaryOfDeclarations(); @@ -95,7 +141,7 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) }; var document = $@" Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) -{PackageLink} +{this.PackageLink} # {title} @@ -129,13 +175,21 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) // Open a file to write the new doc to. await File.WriteAllTextAsync( - Path.Join(OutputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), + Path.Join(this.OutputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), document ); } - - + /// + /// Given a documentation comment describing a Q# function or operation + /// declaration, writes a Markdown file documenting that callable + /// declaration to . + /// + /// The Q# callable being documented. + /// + /// The API documentation comment describing . + /// + /// A representing the result of the asynchronous operation. public async Task WriteOutput(QsCallable callable, DocComment docComment) { var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); @@ -145,7 +199,8 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) { QsCallableKind.Tags.Function => "function", QsCallableKind.Tags.Operation => "operation", - QsCallableKind.Tags.TypeConstructor => "type constructor" + QsCallableKind.Tags.TypeConstructor => "type constructor", + _ => "" }; var title = $@"{callable.FullName.Name.Value} {kind}"; var header = new Dictionary @@ -166,7 +221,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) }; var document = $@" Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) -{PackageLink} +{this.PackageLink} # {title} @@ -179,7 +234,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) .MaybeWithSection("Description", docComment.Description) .MaybeWithSection( "Input", - String.Join("\n", docComment.Input.Select( + string.Join("\n", docComment.Input.Select( item => { var hasInput = inputDeclarations.TryGetValue(item.Key, out var inputType); @@ -188,8 +243,9 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) )) ) .MaybeWithSection("Output", docComment.Output) - .MaybeWithSection("Type Parameters", - String.Join("\n", docComment.TypeParameters.Select( + .MaybeWithSection( + "Type Parameters", + string.Join("\n", docComment.TypeParameters.Select( item => $"### {item.Key}\n\n{item.Value}\n\n" )) ) @@ -197,7 +253,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) .MaybeWithSection("References", docComment.References) .MaybeWithSection( "See Also", - String.Join("\n", docComment.SeeAlso.Select( + string.Join("\n", docComment.SeeAlso.Select( seeAlso => $"- [{seeAlso}](xref:{seeAlso})" )) ) @@ -205,7 +261,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) // Open a file to write the new doc to. await File.WriteAllTextAsync( - Path.Join(OutputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), + Path.Join(this.OutputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), document ); } diff --git a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs index 6f34fe20da..8ed571ba15 100644 --- a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs +++ b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs @@ -21,6 +21,11 @@ namespace Microsoft.Quantum.Documentation { + /// + /// A syntax tree transformation that parses documentation comments, + /// saving documentation content back to the syntax tree as attributes, + /// and writing formatted documentation content out to Markdown files. + /// public class ProcessDocComments : SyntaxTreeTransformation { @@ -29,24 +34,36 @@ public class TransformationState private readonly DocumentationWriter? writer; + /// + /// Initializes a new instance of the class. + /// + /// + /// The path to which documentation files should be written. + /// + /// + /// The name of the NuGet package being documented, or null + /// if the documentation to be written by this object does not + /// relate to a particular package. + /// public ProcessDocComments( string? outputPath = null, string? packageName = null ) : base(new TransformationState()) { - writer = outputPath == null - ? null - : new DocumentationWriter(outputPath, packageName); + this.writer = outputPath == null + ? null + : new DocumentationWriter(outputPath, packageName); // We provide our own custom namespace transformation, and expression kind transformation. - this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, writer); + this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, this.writer); } private class NamespaceTransformation : NamespaceTransformation { private DocumentationWriter? writer; + internal NamespaceTransformation(ProcessDocComments parent, DocumentationWriter? writer) : base(parent) { this.writer = writer; } @@ -72,7 +89,10 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) // If the UDT didn't come from a Q# source file, then it // came in from a reference, and shouldn't be documented in this // project. - if (!type.IsInCompilationUnit()) return type; + if (!type.IsInCompilationUnit()) + { + return type; + } var isDeprecated = type.IsDeprecated(out var replacement); var docComment = new DocComment( @@ -81,7 +101,7 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) replacement: replacement ); - writer?.WriteOutput(type, docComment)?.Wait(); + this.writer?.WriteOutput(type, docComment)?.Wait(); return type .AttributeBuilder() @@ -101,7 +121,10 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) // If the callable didn't come from a Q# source file, then it // came in from a reference, and shouldn't be documented in this // project. - if (!callable.IsInCompilationUnit()) return callable; + if (!callable.IsInCompilationUnit()) + { + return callable; + } var isDeprecated = callable.IsDeprecated(out var replacement); var docComment = new DocComment( @@ -110,7 +133,7 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) replacement: replacement ); - writer?.WriteOutput(callable, docComment)?.Wait(); + this.writer?.WriteOutput(callable, docComment)?.Wait(); return callable .AttributeBuilder() diff --git a/src/Documentation/DocumentationParser/DocNamespace.cs b/src/Documentation/DocumentationParser/DocNamespace.cs index 9d1dae9e1c..6a7176a0d3 100644 --- a/src/Documentation/DocumentationParser/DocNamespace.cs +++ b/src/Documentation/DocumentationParser/DocNamespace.cs @@ -289,8 +289,7 @@ string ToSequenceKey(string itemTypeName) foreach (var item in this.items) { var typeKey = ToSequenceKey(item.ItemType); - SortedDictionary typeList; - if (itemTypeNodes.TryGetValue(typeKey, out typeList)) + if (itemTypeNodes.TryGetValue(typeKey, out var typeList)) { if (typeList.ContainsKey(item.Uid)) { From dc4d23367338491dcee1c001fa40112c3b753dee Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 12 Oct 2020 11:56:22 -0700 Subject: [PATCH 52/74] Remove unit test used for removed functionality. --- .../Tests.Compiler/CommandLineTests.fs | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/CommandLineTests.fs b/src/QsCompiler/Tests.Compiler/CommandLineTests.fs index 47961c0290..77c908fcc3 100644 --- a/src/QsCompiler/Tests.Compiler/CommandLineTests.fs +++ b/src/QsCompiler/Tests.Compiler/CommandLineTests.fs @@ -203,41 +203,6 @@ let ``execute rewrite steps only if validation passes`` () = Assert.Equal(CompilationLoader.Status.NotRun, loaded.FunctorSupport) Assert.Equal(CompilationLoader.Status.NotRun, loaded.Monomorphization) - -[] -let ``generate docs`` () = - let docsFolder = ("TestCases", "docs.Out") |> Path.Combine - if (Directory.Exists docsFolder) then - for file in Directory.GetFiles docsFolder do - File.Delete file - - let toc = Path.Combine (docsFolder, "toc.yml") - let nsDoc = Path.Combine (docsFolder, "Microsoft.Quantum.Testing.General.yml") - let opDoc = Path.Combine (docsFolder, "microsoft.quantum.testing.general.unitary.yml") - let existsAndNotEmpty fileName = fileName |> File.Exists && not (File.ReadAllText fileName |> String.IsNullOrWhiteSpace) - let args = - [| - "build" - "--input" - ("TestCases","General.qs") |> Path.Combine - "--doc" - docsFolder - |] - - let result = Program.Main args - Assert.Equal(ReturnCode.SUCCESS, result) - Assert.True (existsAndNotEmpty toc) - Assert.True (existsAndNotEmpty nsDoc) - Assert.True (existsAndNotEmpty opDoc) - - // Verify that we can compile repeatedly without errors despite docs already existing. - let result2 = Program.Main args - Assert.Equal(ReturnCode.SUCCESS, result2) - Assert.True (existsAndNotEmpty toc) - Assert.True (existsAndNotEmpty nsDoc) - Assert.True (existsAndNotEmpty opDoc) - - [] let ``find path relative`` () = let fullPath = Path.Combine (Path.GetFullPath "alpha","beta","c","test-path.qs") From a644b7ed10f8e2218bee87ca66510e4fffd1ac74 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 14 Oct 2020 11:42:28 -0700 Subject: [PATCH 53/74] Apply feedback. --- src/Documentation/DocumentationGenerator/ProcessDocComments.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs index 8ed571ba15..891aadb190 100644 --- a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs +++ b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs @@ -49,7 +49,7 @@ public ProcessDocComments( string? outputPath = null, string? packageName = null ) - : base(new TransformationState()) + : base(new TransformationState(), TransformationOptions.Disabled) { this.writer = outputPath == null ? null From 0cd17cb920e4562cf2fdbff6630341d82e7266d4 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 14 Oct 2020 17:24:16 -0700 Subject: [PATCH 54/74] Turn type parameters to markdown links as well. --- src/Documentation/DocumentationGenerator/Extensions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Documentation/DocumentationGenerator/Extensions.cs b/src/Documentation/DocumentationGenerator/Extensions.cs index 2ce3c3acce..7d726cf9c8 100644 --- a/src/Documentation/DocumentationGenerator/Extensions.cs +++ b/src/Documentation/DocumentationGenerator/Extensions.cs @@ -287,6 +287,8 @@ internal static Dictionary ToDictionaryOfDeclarations(this tuple.Item.Select(ToMarkdownLink) ) + ")", ResolvedTypeKind.UserDefinedType udt => udt.Item.ToMarkdownLink(), + ResolvedTypeKind.TypeParameter typeParam => + $"'{typeParam.Item.TypeName.Value}", _ => type.Resolution.Tag switch { ResolvedTypeKind.Tags.BigInt => "BigInt", From 4a7771ea01716dfe0887731c618caa5d08e10557 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 14 Oct 2020 17:24:37 -0700 Subject: [PATCH 55/74] Propagate package ID to docs correctly. --- .../DefaultItems/DefaultItems.props.v.template | 1 - src/QuantumSdk/Sdk/Sdk.targets | 15 ++++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template b/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template index 560d4130d4..6a5a926646 100644 --- a/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template +++ b/src/QuantumSdk/DefaultItems/DefaultItems.props.v.template @@ -34,7 +34,6 @@ true true false - $(PackageId) false dotnet "$(MSBuildThisFileDirectory)../tools/utils/Microsoft.Quantum.Sdk.BuildConfiguration.dll" $(DefaultQscBuildConfigExe) diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index 478c2e6731..defcb6dafd 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -68,6 +68,11 @@ + + <_QscDocsPackageeId Condition="'$(PackageId)' != ''">$(PackageId) + <_QscDocsPackageeId Condition="'$(QsharpDocsPackageId)' != ''">$(QsharpDocsPackageId) <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe <_QscCommandOutputFlag>--output "$(GeneratedFilesOutputPath)" <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" @@ -77,11 +82,11 @@ <_QscCommandTargetDecompositionsFlag Condition="@(ResolvedTargetSpecificDecompositions->Count()) > 0">--target-specific-decompositions "@(ResolvedTargetSpecificDecompositions,'" "')" <_QscCommandTestNamesFlag Condition="$(ExposeReferencesViaTestNames)">--load-test-names <_QscCommandPredefinedAssemblyProperties>ProcessorArchitecture:$(ResolvedProcessorArchitecture) QsharpOutputType:$(ResolvedQsharpOutputType) - <_QscCommandPredefinedAssemblyProperties Condition="$(DefaultSimulator) != ''">$(_QscCommandPredefinedAssemblyProperties) DefaultSimulator:$(DefaultSimulator) - <_QscCommandPredefinedAssemblyProperties Condition="$(ExecutionTarget) != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) - <_QscCommandPredefinedAssemblyProperties Condition="$(ExposeReferencesViaTestNames)">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true - <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsPackageId) != ''">$(_QscCommandPredefinedAssemblyProperties) DocsPackageId:$(QsharpDocsPackageId) - <_QscCommandPredefinedAssemblyProperties Condition="$(QsharpDocsGeneration)">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) + <_QscCommandPredefinedAssemblyProperties Condition="'$(DefaultSimulator)' != ''">$(_QscCommandPredefinedAssemblyProperties) DefaultSimulator:$(DefaultSimulator) + <_QscCommandPredefinedAssemblyProperties Condition="'$(ExecutionTarget)' != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) + <_QscCommandPredefinedAssemblyProperties Condition="'$(ExposeReferencesViaTestNames)'">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true + <_QscCommandPredefinedAssemblyProperties Condition="'$(_QscDocsPackageeId)' != ''">$(_QscCommandPredefinedAssemblyProperties) DocsPackageId:$(_QscDocsPackageeId) + <_QscCommandPredefinedAssemblyProperties Condition="'$(QsharpDocsGeneration)'">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) From ccdc2f6bfa894e50db28a47b4090e64a49a1d434 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 14 Oct 2020 17:29:53 -0700 Subject: [PATCH 56/74] Ensure newline before package name. --- src/Documentation/DocumentationGenerator/DocumentationWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs index 0c386f93e3..ed6edb2ab5 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs @@ -59,7 +59,7 @@ public DocumentationWriter(string outputPath, string? packageName) PackageLink = PackageName == null ? "" - : $"Package: [{PackageName}](https://nuget.org/packages/{PackageName})\n"; + : $"\nPackage: [{PackageName}](https://nuget.org/packages/{PackageName})\n"; } /// From 61a1fbdd5b65ef2779ba14d05f3ba40accd9274d Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 10:22:35 -0700 Subject: [PATCH 57/74] Quote docs output path in qsc.rsp. --- src/QuantumSdk/Sdk/Sdk.targets | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/QuantumSdk/Sdk/Sdk.targets b/src/QuantumSdk/Sdk/Sdk.targets index defcb6dafd..242f27bf0d 100644 --- a/src/QuantumSdk/Sdk/Sdk.targets +++ b/src/QuantumSdk/Sdk/Sdk.targets @@ -71,8 +71,8 @@ - <_QscDocsPackageeId Condition="'$(PackageId)' != ''">$(PackageId) - <_QscDocsPackageeId Condition="'$(QsharpDocsPackageId)' != ''">$(QsharpDocsPackageId) + <_QscDocsPackageId Condition="'$(PackageId)' != ''">$(PackageId) + <_QscDocsPackageId Condition="'$(QsharpDocsPackageId)' != ''">$(QsharpDocsPackageId) <_QscCommandIsExecutableFlag Condition="'$(ResolvedQsharpOutputType)' == 'QsharpExe'">--build-exe <_QscCommandOutputFlag>--output "$(GeneratedFilesOutputPath)" <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" @@ -85,8 +85,8 @@ <_QscCommandPredefinedAssemblyProperties Condition="'$(DefaultSimulator)' != ''">$(_QscCommandPredefinedAssemblyProperties) DefaultSimulator:$(DefaultSimulator) <_QscCommandPredefinedAssemblyProperties Condition="'$(ExecutionTarget)' != ''">$(_QscCommandPredefinedAssemblyProperties) ExecutionTarget:$(ExecutionTarget) <_QscCommandPredefinedAssemblyProperties Condition="'$(ExposeReferencesViaTestNames)'">$(_QscCommandPredefinedAssemblyProperties) ExposeReferencesViaTestNames:true - <_QscCommandPredefinedAssemblyProperties Condition="'$(_QscDocsPackageeId)' != ''">$(_QscCommandPredefinedAssemblyProperties) DocsPackageId:$(_QscDocsPackageeId) - <_QscCommandPredefinedAssemblyProperties Condition="'$(QsharpDocsGeneration)'">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:$(QsharpDocsOutputPath) + <_QscCommandPredefinedAssemblyProperties Condition="'$(_QscDocsPackageId)' != ''">$(_QscCommandPredefinedAssemblyProperties) DocsPackageId:$(_QscDocsPackageeId) + <_QscCommandPredefinedAssemblyProperties Condition="'$(QsharpDocsGeneration)'">$(_QscCommandPredefinedAssemblyProperties) DocsOutputPath:"$(QsharpDocsOutputPath)" <_QscCommandAssemblyPropertiesFlag>--assembly-properties $(_QscCommandPredefinedAssemblyProperties) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandIsExecutableFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandRuntimeFlag) $(_QscCommandTargetDecompositionsFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandTestNamesFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) From cdfc66095c03ffa6ec76fa4dca9947b13e5d995f Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 10:23:09 -0700 Subject: [PATCH 58/74] Add better diagnostics to DocumentationWriter. --- .../DocumentationGeneration.cs | 14 ++- .../DocumentationWriter.cs | 96 ++++++++++++++----- 2 files changed, 86 insertions(+), 24 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs index 536e156242..cfdcf70944 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs @@ -70,14 +70,24 @@ public bool PreconditionVerification(QsCompilation compilation) public bool Transformation(QsCompilation compilation, out QsCompilation transformed) { - transformed = new ProcessDocComments( + var docProcessor = new ProcessDocComments( this.AssemblyConstants.TryGetValue("DocsOutputPath", out var path) ? path : null, this.AssemblyConstants.TryGetValue("DocsPackageId", out var packageName) ? packageName : null - ).OnCompilation(compilation); + ); + + if (docProcessor.Writer != null) + { + docProcessor.Writer.OnDiagnostic += diagnostic => + { + this.diagnostics.Add(diagnostic); + }; + } + + transformed = docProcessor.OnCompilation(compilation); return true; } diff --git a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs index ed6edb2ab5..4bba29230f 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; using System.IO; -using System.Threading.Tasks; using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.Quantum.QsCompiler; using Microsoft.Quantum.QsCompiler.Documentation; using Microsoft.Quantum.QsCompiler.SyntaxTree; @@ -18,6 +20,12 @@ namespace Microsoft.Quantum.Documentation /// public class DocumentationWriter { + /// + /// An event that is raised on diagnostics about documentation + /// writing (e.g., if an I/O problem prevents writing to disk). + /// + public event Action? OnDiagnostic; + /// /// Path to which output documentation files should be written. /// @@ -34,6 +42,36 @@ public class DocumentationWriter private readonly string PackageLink; + private async Task TryWithExceptionsAsDiagnostics(string description, Func action, DiagnosticSeverity severity = DiagnosticSeverity.Warning) + { + try + { + await action(); + } + catch (Exception ex) + { + this.OnDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Severity = severity, + Message = $"Exception raised when {description}:\n{ex.Message}", + Range = null, + Source = null, + Stage = IRewriteStep.Stage.Transformation, + }); + } + } + + private async Task WriteAllTextAsync(string filename, string contents) + { + await this.TryWithExceptionsAsDiagnostics( + $"writing output to {filename}", + async () => await File.WriteAllTextAsync( + Path.Join(this.OutputPath, $"{filename.ToLowerInvariant()}.md"), + contents + ) + ); + } + /// /// Initializes a new instance of the /// class. @@ -52,14 +90,28 @@ public DocumentationWriter(string outputPath, string? packageName) this.packageName = packageName; // If the output path is not null, make sure the directory exists. - if (outputPath != null && !Directory.Exists(outputPath)) + if (outputPath != null) { - Directory.CreateDirectory(outputPath); + this.OnDiagnostic?.Invoke(new IRewriteStep.Diagnostic + { + Severity = CodeAnalysis.DiagnosticSeverity.Info, + Message = $"Writing documentation output to: {outputPath}...", + Range = null, + Source = null, + Stage = IRewriteStep.Stage.Transformation, + }); + if (!Directory.Exists(outputPath)) + { + this.TryWithExceptionsAsDiagnostics( + "creating directory", + async () => Directory.CreateDirectory(outputPath) + ).Wait(); + } } - PackageLink = PackageName == null - ? "" - : $"\nPackage: [{PackageName}](https://nuget.org/packages/{PackageName})\n"; + this.PackageLink = this.PackageName == null + ? string.Empty + : $"\nPackage: [{this.PackageName}](https://nuget.org/packages/{this.PackageName})\n"; } /// @@ -90,7 +142,7 @@ public async Task WriteOutput(QsNamespace ns, DocComment docComment) // Q# metadata ["qsharp.kind"] = "namespace", ["qsharp.name"] = name, - ["qsharp.summary"] = docComment.Summary + ["qsharp.summary"] = docComment.Summary, }; var document = $@" # {title} @@ -102,9 +154,8 @@ public async Task WriteOutput(QsNamespace ns, DocComment docComment) .WithYamlHeader(header); // Open a file to write the new doc to. - await File.WriteAllTextAsync( - Path.Join(this.OutputPath, $"{name.ToLowerInvariant()}.md"), - document + await this.WriteAllTextAsync( + name, document ); } @@ -121,6 +172,7 @@ await File.WriteAllTextAsync( public async Task WriteOutput(QsCustomType type, DocComment docComment) { var namedItemDeclarations = type.TypeItems.ToDictionaryOfDeclarations(); + // Make a new Markdown document for the type declaration. var title = $"{type.FullName.Name.Value} user defined type"; var header = new Dictionary @@ -137,18 +189,18 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) ["qsharp.kind"] = "udt", ["qsharp.namespace"] = type.FullName.Namespace.Value, ["qsharp.name"] = type.FullName.Name.Value, - ["qsharp.summary"] = docComment.Summary + ["qsharp.summary"] = docComment.Summary, }; var document = $@" +# {title} + Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) {this.PackageLink} -# {title} - {docComment.Summary} ```Q# -{type.ToSyntax()} +{type.WithoutDocumentationAndComments().ToSyntax()} ``` " @@ -174,8 +226,8 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) .WithYamlHeader(header); // Open a file to write the new doc to. - await File.WriteAllTextAsync( - Path.Join(this.OutputPath, $"{type.FullName.Namespace.Value.ToLowerInvariant()}.{type.FullName.Name.Value.ToLowerInvariant()}.md"), + await this.WriteAllTextAsync( + $"{type.FullName.Namespace.Value}.{type.FullName.Name.Value}.md", document ); } @@ -200,7 +252,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) QsCallableKind.Tags.Function => "function", QsCallableKind.Tags.Operation => "operation", QsCallableKind.Tags.TypeConstructor => "type constructor", - _ => "" + _ => "", }; var title = $@"{callable.FullName.Name.Value} {kind}"; var header = new Dictionary @@ -217,14 +269,14 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) ["qsharp.kind"] = kind, ["qsharp.namespace"] = callable.FullName.Namespace.Value, ["qsharp.name"] = callable.FullName.Name.Value, - ["qsharp.summary"] = docComment.Summary + ["qsharp.summary"] = docComment.Summary, }; var document = $@" +# {title} + Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) {this.PackageLink} -# {title} - {docComment.Summary} ```Q# @@ -260,8 +312,8 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) .WithYamlHeader(header); // Open a file to write the new doc to. - await File.WriteAllTextAsync( - Path.Join(this.OutputPath, $"{callable.FullName.Namespace.Value.ToLowerInvariant()}.{callable.FullName.Name.Value.ToLowerInvariant()}.md"), + await this.WriteAllTextAsync( + $"{callable.FullName.Namespace.Value}.{callable.FullName.Name.Value}.md", document ); } From 66d5c16fabc0b143fa9d2007bd22c3fb79ee3dce Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 10:23:26 -0700 Subject: [PATCH 59/74] Strip comments from syntax blocks. --- .../DocumentationGenerator/Extensions.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Documentation/DocumentationGenerator/Extensions.cs b/src/Documentation/DocumentationGenerator/Extensions.cs index 7d726cf9c8..ba768ed96c 100644 --- a/src/Documentation/DocumentationGenerator/Extensions.cs +++ b/src/Documentation/DocumentationGenerator/Extensions.cs @@ -300,7 +300,8 @@ internal static Dictionary ToDictionaryOfDeclarations(this ResolvedTypeKind.Tags.Range => "Range", ResolvedTypeKind.Tags.String => "String", ResolvedTypeKind.Tags.UnitType => "Unit", - _ => "__invalid__", + ResolvedTypeKind.Tags.InvalidType => "__invalid__", + _ => $"__invalid<{type.Resolution.ToString()}>__", }, }; @@ -320,6 +321,19 @@ internal static bool IsInCompilationUnit(this QsCallable callable) => internal static bool IsInCompilationUnit(this QsCustomType type) => type.SourceFile.Value.EndsWith(".qs"); + + internal static QsCustomType WithoutDocumentationAndComments(this QsCustomType type) => + new QsCustomType( + fullName: type.FullName, + attributes: type.Attributes, + modifiers: type.Modifiers, + sourceFile: type.SourceFile, + location: type.Location, + type: type.Type, + typeItems: type.TypeItems, + documentation: ImmutableArray.Empty, + comments: QsComments.Empty + ); } } From 27a84c1f56598ba97e919e69a9756d7d63f9bfe6 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 10:24:06 -0700 Subject: [PATCH 60/74] Style and diagnostics fixes. --- .../DocumentationGenerator/ProcessDocComments.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs index 891aadb190..a287bbd5c6 100644 --- a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs +++ b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs @@ -32,7 +32,7 @@ public class ProcessDocComments public class TransformationState { } - private readonly DocumentationWriter? writer; + internal readonly DocumentationWriter? Writer; /// /// Initializes a new instance of the class. @@ -51,12 +51,12 @@ public ProcessDocComments( ) : base(new TransformationState(), TransformationOptions.Disabled) { - this.writer = outputPath == null + this.Writer = outputPath == null ? null : new DocumentationWriter(outputPath, packageName); // We provide our own custom namespace transformation, and expression kind transformation. - this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, this.writer); + this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, this.Writer); } private class NamespaceTransformation From 4c657008b6f1e0845663a3c8fd8c71b3849bb1e7 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 10:25:00 -0700 Subject: [PATCH 61/74] Fix #679. --- src/QsCompiler/CommandLineTool/Commands/Build.cs | 10 +++++++++- src/QsCompiler/CommandLineTool/Options.cs | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index c91c1c5727..56b24d76c2 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -112,8 +112,14 @@ internal static bool IncorporateResponseFiles(BuildOptions options, out BuildOpt /// private static IEnumerable SplitCommandLineArguments(string commandLine) { + string TrimQuotes(string s) => + s.StartsWith('"') && s.EndsWith('"') + ? s.Substring(1, s.Length - 2) + : s; + var parmChars = commandLine?.ToCharArray() ?? Array.Empty(); var inQuote = false; + for (int index = 0; index < parmChars.Length; index++) { var precededByBackslash = index > 0 && parmChars[index - 1] == '\\'; @@ -131,9 +137,10 @@ private static IEnumerable SplitCommandLineArguments(string commandLine) parmChars[index] = '\n'; } } + return new string(parmChars) .Split('\n', StringSplitOptions.RemoveEmptyEntries) - .Select(arg => arg.Trim('"')); + .Select(arg => TrimQuotes(arg)); } /// @@ -148,6 +155,7 @@ private static BuildOptions FromResponseFiles(IEnumerable responseFiles) throw new ArgumentNullException(nameof(responseFiles)); } var commandLine = string.Join(" ", responseFiles.Select(File.ReadAllText)); + System.Diagnostics.Debugger.Launch(); var args = SplitCommandLineArguments(commandLine); var parsed = Parser.Default.ParseArguments(args); return parsed.MapResult( diff --git a/src/QsCompiler/CommandLineTool/Options.cs b/src/QsCompiler/CommandLineTool/Options.cs index de79138fe8..3d3402ed1c 100644 --- a/src/QsCompiler/CommandLineTool/Options.cs +++ b/src/QsCompiler/CommandLineTool/Options.cs @@ -90,7 +90,8 @@ internal bool ParseAssemblyProperties(out Dictionary parsed) parsed = new Dictionary(); foreach (var keyValue in this.AdditionalAssemblyProperties ?? Array.Empty()) { - var pieces = keyValue?.Split(":"); + // NB: We use `count: 2` here to ensure that assembly constants can contain colons. + var pieces = keyValue?.Split(":", count: 2); var valid = pieces != null && pieces.Length == 2; success = valid && parsed.TryAdd(pieces[0].Trim().Trim('"'), pieces[1].Trim().Trim('"')) && success; } From a27ebcc4ade6b540cf77b59a9a732a305f4ffa61 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 16:16:30 -0700 Subject: [PATCH 62/74] Warn when documenting input or type parameter names that don't exist. --- .../DocumentationGeneration.cs | 9 +-- .../DocumentationWriter.cs | 22 +++++-- .../ProcessDocComments.cs | 64 +++++++++++++++++++ .../DocumentationParser/DocComment.cs | 2 +- .../CommandLineTool/Commands/Build.cs | 1 - 5 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs index cfdcf70944..e31d3b6e14 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs @@ -79,13 +79,10 @@ public bool Transformation(QsCompilation compilation, out QsCompilation transfor : null ); - if (docProcessor.Writer != null) + docProcessor.OnDiagnostic += diagnostic => { - docProcessor.Writer.OnDiagnostic += diagnostic => - { - this.diagnostics.Add(diagnostic); - }; - } + this.diagnostics.Add(diagnostic); + }; transformed = docProcessor.OnCompilation(compilation); return true; diff --git a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs index 4bba29230f..1d545a9bba 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs @@ -42,6 +42,14 @@ public class DocumentationWriter private readonly string PackageLink; + private static string AsSeeAlsoLink(string target, string? currentNamespace = null) + { + var actualTarget = currentNamespace == null || target.Contains(".") + ? target + : $"{currentNamespace}.{target}"; + return $"- [{actualTarget}](xref:{actualTarget})"; + } + private async Task TryWithExceptionsAsDiagnostics(string description, Func action, DiagnosticSeverity severity = DiagnosticSeverity.Warning) { try @@ -66,7 +74,7 @@ private async Task WriteAllTextAsync(string filename, string contents) await this.TryWithExceptionsAsDiagnostics( $"writing output to {filename}", async () => await File.WriteAllTextAsync( - Path.Join(this.OutputPath, $"{filename.ToLowerInvariant()}.md"), + Path.Join(this.OutputPath, filename.ToLowerInvariant()), contents ) ); @@ -151,11 +159,17 @@ public async Task WriteOutput(QsNamespace ns, DocComment docComment) " .MaybeWithSection("Description", docComment.Description) + .MaybeWithSection( + "See Also", + string.Join("\n", docComment.SeeAlso.Select( + seeAlso => AsSeeAlsoLink(seeAlso) + )) + ) .WithYamlHeader(header); // Open a file to write the new doc to. await this.WriteAllTextAsync( - name, document + $"{name}.md", document ); } @@ -220,7 +234,7 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) .MaybeWithSection( "See Also", string.Join("\n", docComment.SeeAlso.Select( - seeAlso => $"- {seeAlso}" + seeAlso => AsSeeAlsoLink(seeAlso, type.FullName.Namespace.Value) )) ) .WithYamlHeader(header); @@ -306,7 +320,7 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) .MaybeWithSection( "See Also", string.Join("\n", docComment.SeeAlso.Select( - seeAlso => $"- [{seeAlso}](xref:{seeAlso})" + seeAlso => AsSeeAlsoLink(seeAlso, callable.FullName.Namespace.Value) )) ) .WithYamlHeader(header); diff --git a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs index a287bbd5c6..e7da259742 100644 --- a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs +++ b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs @@ -32,6 +32,12 @@ public class ProcessDocComments public class TransformationState { } + /// + /// An event that is raised on diagnostics about documentation + /// writing (e.g., if an I/O problem prevents writing to disk). + /// + public event Action? OnDiagnostic; + internal readonly DocumentationWriter? Writer; /// @@ -55,6 +61,12 @@ public ProcessDocComments( ? null : new DocumentationWriter(outputPath, packageName); + if (this.Writer != null) + { + this.Writer.OnDiagnostic += diagnostic => + this.OnDiagnostic?.Invoke(diagnostic); + } + // We provide our own custom namespace transformation, and expression kind transformation. this.Namespaces = new ProcessDocComments.NamespaceTransformation(this, this.Writer); } @@ -68,6 +80,33 @@ internal NamespaceTransformation(ProcessDocComments parent, DocumentationWriter? : base(parent) { this.writer = writer; } + private void ValidateNames( + string symbolName, + string nameKind, + Func isNameValid, + IEnumerable actualNames, + Range? range = null, + string? source = null + ) + { + foreach (var name in actualNames) + { + if (!isNameValid(name)) + { + (this.Transformation as ProcessDocComments)?.OnDiagnostic?.Invoke( + new IRewriteStep.Diagnostic + { + Message = $"When documenting {symbolName}, found documentation for {nameKind} {name}, but no such {nameKind} exists.", + Severity = CodeAnalysis.DiagnosticSeverity.Warning, + Range = range, + Source = source, + Stage = IRewriteStep.Stage.Transformation, + } + ); + } + } + } + public override QsNamespace OnNamespace(QsNamespace ns) { ns = base.OnNamespace(ns); @@ -132,6 +171,31 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) deprecated: isDeprecated, replacement: replacement ); + var callableName = + $"{callable.FullName.Namespace.Value}.{callable.FullName.Name.Value}"; + + // Validate input and type parameter names. + var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); + this.ValidateNames( + callableName, + "input", + name => inputDeclarations.ContainsKey(name), + docComment.Input.Keys, + range: null, // TODO: provide more exact locations once supported by DocParser. + source: callable.SourceFile.Value + ); + this.ValidateNames( + callableName, + "type parameter", + name => callable.Signature.TypeParameters.Any( + typeParam => + typeParam is QsLocalSymbol.ValidName validName && + validName.Item.Value == name.TrimStart('\'') + ), + docComment.TypeParameters.Keys, + range: null, // TODO: provide more exact locations once supported by DocParser. + source: callable.SourceFile.Value + ); this.writer?.WriteOutput(callable, docComment)?.Wait(); diff --git a/src/Documentation/DocumentationParser/DocComment.cs b/src/Documentation/DocumentationParser/DocComment.cs index 0cdada643e..b3bf8af313 100644 --- a/src/Documentation/DocumentationParser/DocComment.cs +++ b/src/Documentation/DocumentationParser/DocComment.cs @@ -221,7 +221,7 @@ static void ParseListSection(IEnumerable blocks, List accum, bool { itemText = itemText.Substring(2, itemText.Length - 3); } - literal.Content = new Markdig.Helpers.StringSlice(itemText.ToLowerInvariant()); + literal.Content = new Markdig.Helpers.StringSlice(itemText); } accum.Add(ToMarkdown(new Block[] { item })); } diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index 56b24d76c2..becf22e8f8 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -155,7 +155,6 @@ private static BuildOptions FromResponseFiles(IEnumerable responseFiles) throw new ArgumentNullException(nameof(responseFiles)); } var commandLine = string.Join(" ", responseFiles.Select(File.ReadAllText)); - System.Diagnostics.Debugger.Launch(); var args = SplitCommandLineArguments(commandLine); var parsed = Parser.Default.ParseArguments(args); return parsed.MapResult( From 6aa06f0be1c953c3a6b0ad4caf151afc8e88017a Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 15 Oct 2020 17:07:12 -0700 Subject: [PATCH 63/74] Warn on invalid named items as well. --- .../DocumentationGenerator/ProcessDocComments.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs index e7da259742..d493c12ac1 100644 --- a/src/Documentation/DocumentationGenerator/ProcessDocComments.cs +++ b/src/Documentation/DocumentationGenerator/ProcessDocComments.cs @@ -140,6 +140,17 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) replacement: replacement ); + // Validate named item names. + var inputDeclarations = type.TypeItems.ToDictionaryOfDeclarations(); + this.ValidateNames( + $"{type.FullName.Namespace.Value}.{type.FullName.Name.Value}", + "named item", + name => inputDeclarations.ContainsKey(name), + docComment.Input.Keys, + range: null, // TODO: provide more exact locations once supported by DocParser. + source: type.SourceFile.Value + ); + this.writer?.WriteOutput(type, docComment)?.Wait(); return type From dd70aa7ed34532f9cdf59a45d605183354d6bdbc Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Fri, 16 Oct 2020 10:57:46 -0700 Subject: [PATCH 64/74] Pack docs summary script as well. --- build/pack.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/pack.ps1 b/build/pack.ps1 index 8be4e28f08..b252337755 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -255,6 +255,11 @@ if ($Env:ENABLE_VSIX -ne "false") { Write-Host "##vso[task.logissue type=warning;]VSIX packing skipped due to ENABLE_VSIX variable." } +# Copy documentation summarization tool into docs drop. +Push-Location (Join-Path $PSScriptRoot "../src/Documentation/Summarizer") + Copy-Item -Path *.py, *.txt -Destination $Env:DOCS_OUTDIR +Pop-Location + Write-Host "##[info]Verifying manifest..." & (Join-Path $PSScriptRoot "manifest.ps1") From 5529200fc8b9299c66d59231ca96ec7b56672aab Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 19 Oct 2020 20:44:54 -0700 Subject: [PATCH 65/74] Fix package links and Markdown syntax highlighting. --- .../DocumentationWriter.cs | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs index 1d545a9bba..41593bb763 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationWriter.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationWriter.cs @@ -40,7 +40,12 @@ public class DocumentationWriter /// public string? PackageName => this.packageName; - private readonly string PackageLink; + private readonly string packageLink; + + /// + /// Markdown mode used to mark Q# syntax blocks. + /// + public virtual string LanguageMode => "qsharp"; private static string AsSeeAlsoLink(string target, string? currentNamespace = null) { @@ -117,7 +122,7 @@ public DocumentationWriter(string outputPath, string? packageName) } } - this.PackageLink = this.PackageName == null + this.packageLink = this.PackageName == null ? string.Empty : $"\nPackage: [{this.PackageName}](https://nuget.org/packages/{this.PackageName})\n"; } @@ -209,22 +214,26 @@ public async Task WriteOutput(QsCustomType type, DocComment docComment) # {title} Namespace: [{type.FullName.Namespace.Value}](xref:{type.FullName.Namespace.Value}) -{this.PackageLink} +{this.packageLink} {docComment.Summary} -```Q# +```{this.LanguageMode} {type.WithoutDocumentationAndComments().ToSyntax()} ``` " .MaybeWithSection( "Named Items", - string.Join("\n", docComment.NamedItems.Select( + string.Join("\n", type.TypeItems.TypeDeclarations().Select( item => { - var hasName = namedItemDeclarations.TryGetValue(item.Key, out var itemType); - return $"### {item.Key}{(hasName ? $" : {itemType.ToMarkdownLink()}" : "")}\n\n{item.Value}\n\n";; + (var itemName, var resolvedType) = item; + var documentation = + docComment.NamedItems.TryGetValue(itemName, out var comment) + ? comment + : string.Empty; + return $"### {itemName} : {resolvedType.ToMarkdownLink()}\n\n{documentation}"; } )) ) @@ -258,8 +267,6 @@ await this.WriteAllTextAsync( /// A representing the result of the asynchronous operation. public async Task WriteOutput(QsCallable callable, DocComment docComment) { - var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); - // Make a new Markdown document for the type declaration. var kind = callable.Kind.Tag switch { @@ -289,30 +296,47 @@ public async Task WriteOutput(QsCallable callable, DocComment docComment) # {title} Namespace: [{callable.FullName.Namespace.Value}](xref:{callable.FullName.Namespace.Value}) -{this.PackageLink} +{this.packageLink} {docComment.Summary} -```Q# -{callable.ToSyntax()} +```{this.LanguageMode} +{ + callable.Kind.Tag switch + { + QsCallableKind.Tags.Function => "function ", + QsCallableKind.Tags.Operation => "operation ", + QsCallableKind.Tags.TypeConstructor => "newtype ", + _ => "" + } +}{callable.ToSyntax()} ``` " .MaybeWithSection("Description", docComment.Description) .MaybeWithSection( "Input", - string.Join("\n", docComment.Input.Select( - item => + string.Join("\n", callable.ArgumentTuple.InputDeclarations().Select( + (item) => { - var hasInput = inputDeclarations.TryGetValue(item.Key, out var inputType); - return $"### {item.Key}{(hasInput ? $" : {inputType.ToMarkdownLink()}" : "")}\n\n{item.Value}\n\n"; + (var inputName, var resolvedType) = item; + var documentation = docComment.Input.TryGetValue(inputName, out var inputComment) + ? inputComment + : string.Empty; + return $"### {inputName} : {resolvedType.ToMarkdownLink()}\n\n{documentation}\n\n"; } )) ) - .MaybeWithSection("Output", docComment.Output) + .WithSection($"Output : {callable.Signature.ReturnType.ToMarkdownLink()}", docComment.Output) .MaybeWithSection( "Type Parameters", - string.Join("\n", docComment.TypeParameters.Select( - item => $"### {item.Key}\n\n{item.Value}\n\n" + string.Join("\n", callable.Signature.TypeParameters.Select( + typeParam => $@"### {typeParam}\n\n{( + typeParam is QsLocalSymbol.ValidName name + ? docComment.TypeParameters.TryGetValue(name.Item.Value, out var comment) + ? comment + : string.Empty + : string.Empty + )}" )) ) .MaybeWithSection("Remarks", docComment.Remarks) From b38620c7c806ff5c06c51af9649475790a3bf156 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 19 Oct 2020 20:45:28 -0700 Subject: [PATCH 66/74] Fix UID casings, Markdown links, etc. --- .../DocumentationGenerator/Extensions.cs | 27 ++++++++++--------- .../DocumentationParser/DocCallable.cs | 2 +- .../DocumentationParser/DocComment.cs | 8 ++---- .../DocumentationParser/DocUdt.cs | 2 +- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/Extensions.cs b/src/Documentation/DocumentationGenerator/Extensions.cs index ba768ed96c..0f4e0e65db 100644 --- a/src/Documentation/DocumentationGenerator/Extensions.cs +++ b/src/Documentation/DocumentationGenerator/Extensions.cs @@ -184,7 +184,10 @@ internal static string ToSyntax(this QsCallable callable, Action contents == null || contents.Trim().Length == 0 ? document - : $"{document}\n\n## {name}\n\n{contents}"; + : document.WithSection(name, contents); + + internal static string WithSection(this string document, string name, string contents) => + $"{document}\n\n## {name}\n\n{contents}"; internal static string WithYamlHeader(this string document, object header) => $"---\n{new SerializerBuilder().Build().Serialize(header)}---\n{document}"; @@ -231,7 +234,7 @@ internal static Dictionary ToDictionaryOfDeclarations(this declaration => declaration.Item2 ); - private static List<(string, ResolvedType)> TypeDeclarations(this QsTuple typeItems) => typeItems switch + internal static List<(string, ResolvedType)> TypeDeclarations(this QsTuple typeItems) => typeItems switch { QsTuple.QsTuple tuple => tuple.Item.SelectMany( @@ -252,7 +255,7 @@ internal static Dictionary ToDictionaryOfDeclarations(this _ => throw new ArgumentException($"Type items {typeItems} aren't a tuple of type items.", nameof(typeItems)), }; - private static List<(string, ResolvedType)> InputDeclarations(this QsTuple> items) => items switch + internal static List<(string, ResolvedType)> InputDeclarations(this QsTuple> items) => items switch { QsTuple>.QsTuple tuple => tuple.Item.SelectMany( @@ -291,15 +294,15 @@ internal static Dictionary ToDictionaryOfDeclarations(this $"'{typeParam.Item.TypeName.Value}", _ => type.Resolution.Tag switch { - ResolvedTypeKind.Tags.BigInt => "BigInt", - ResolvedTypeKind.Tags.Bool => "Bool", - ResolvedTypeKind.Tags.Double => "Double", - ResolvedTypeKind.Tags.Int => "Int", - ResolvedTypeKind.Tags.Pauli => "Pauli", - ResolvedTypeKind.Tags.Qubit => "Qubit", - ResolvedTypeKind.Tags.Range => "Range", - ResolvedTypeKind.Tags.String => "String", - ResolvedTypeKind.Tags.UnitType => "Unit", + ResolvedTypeKind.Tags.BigInt => "[BigInt](xref:microsoft.quantum.lang-ref.bigint)", + ResolvedTypeKind.Tags.Bool => "[Bool](xref:microsoft.quantum.lang-ref.bool)", + ResolvedTypeKind.Tags.Double => "[Double](xref:microsoft.quantum.lang-ref.double)", + ResolvedTypeKind.Tags.Int => "[Int](xref:microsoft.quantum.lang-ref.int)", + ResolvedTypeKind.Tags.Pauli => "[Pauli](xref:microsoft.quantum.lang-ref.pauli)", + ResolvedTypeKind.Tags.Qubit => "[Qubit](xref:microsoft.quantum.lang-ref.qubit)", + ResolvedTypeKind.Tags.Range => "[Range](xref:microsoft.quantum.lang-ref.range)", + ResolvedTypeKind.Tags.String => "[String](xref:microsoft.quantum.lang-ref.string)", + ResolvedTypeKind.Tags.UnitType => "[Unit](xref:microsoft.quantum.lang-ref.unit)", ResolvedTypeKind.Tags.InvalidType => "__invalid__", _ => $"__invalid<{type.Resolution.ToString()}>__", }, diff --git a/src/Documentation/DocumentationParser/DocCallable.cs b/src/Documentation/DocumentationParser/DocCallable.cs index e58ea663b7..e41fd5e559 100644 --- a/src/Documentation/DocumentationParser/DocCallable.cs +++ b/src/Documentation/DocumentationParser/DocCallable.cs @@ -111,7 +111,7 @@ YamlNode BuildOutputNode() rootNode.AddStringMapping(Utils.UidKey, this.uid); rootNode.AddStringMapping(Utils.NameKey, this.name); rootNode.AddStringMapping(Utils.TypeKey, this.itemType); - rootNode.AddStringMapping(Utils.NamespaceKey, this.namespaceName.NamespaceAsUid()); + rootNode.AddStringMapping(Utils.NamespaceKey, this.namespaceName.AsObsoleteUid()); if (!string.IsNullOrWhiteSpace(this.comments.Documentation)) { rootNode.AddStringMapping(Utils.SummaryKey, this.comments.Documentation); diff --git a/src/Documentation/DocumentationParser/DocComment.cs b/src/Documentation/DocumentationParser/DocComment.cs index b3bf8af313..6ebca50ffe 100644 --- a/src/Documentation/DocumentationParser/DocComment.cs +++ b/src/Documentation/DocumentationParser/DocComment.cs @@ -212,15 +212,11 @@ static void ParseListSection(IEnumerable blocks, List accum, bool { if (sub is ListItemBlock item) { - // Some special treatment for funky doc comments in some of the Canon + // Some special treatment for funky doc comments in some of the Canon\ if (item.Count == 1 && item.LastChild is LeafBlock leaf && leaf.Inline != null && leaf.Inline.FirstChild is LiteralInline literal) { var itemText = lowerCase ? GetParagraphText(leaf).ToLowerInvariant() : GetParagraphText(leaf); - if (itemText.StartsWith("@\"") && itemText.EndsWith("\"")) - { - itemText = itemText.Substring(2, itemText.Length - 3); - } literal.Content = new Markdig.Helpers.StringSlice(itemText); } accum.Add(ToMarkdown(new Block[] { item })); @@ -274,7 +270,7 @@ static void ParseMapSection(IEnumerable blocks, Dictionary" }); var deprecationDetails = ""; var text = string.Join("\n", docComments); diff --git a/src/Documentation/DocumentationParser/DocUdt.cs b/src/Documentation/DocumentationParser/DocUdt.cs index a17672146c..35e5eca84d 100644 --- a/src/Documentation/DocumentationParser/DocUdt.cs +++ b/src/Documentation/DocumentationParser/DocUdt.cs @@ -38,7 +38,7 @@ internal override void WriteToFile(TextWriter text) rootNode.AddStringMapping(Utils.UidKey, this.uid); rootNode.AddStringMapping(Utils.NameKey, this.name); rootNode.AddStringMapping(Utils.TypeKey, this.itemType); - rootNode.AddStringMapping(Utils.NamespaceKey, this.namespaceName.NamespaceAsUid()); + rootNode.AddStringMapping(Utils.NamespaceKey, this.namespaceName.AsObsoleteUid()); if (!string.IsNullOrEmpty(this.comments.Documentation)) { rootNode.AddStringMapping(Utils.SummaryKey, this.comments.Documentation); From 41c447a8174ba58d2ec18f622849456047d172d2 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 19 Oct 2020 20:45:40 -0700 Subject: [PATCH 67/74] Explicitly denote new-style UIDs. --- src/Documentation/DocumentationParser/Utils.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Documentation/DocumentationParser/Utils.cs b/src/Documentation/DocumentationParser/Utils.cs index c4a19ed40e..98905b0311 100644 --- a/src/Documentation/DocumentationParser/Utils.cs +++ b/src/Documentation/DocumentationParser/Utils.cs @@ -475,8 +475,11 @@ internal static void DoTrackingExceptions(Action act, List errors) } } - internal static string NamespaceAsUid(this string namespaceName) => - namespaceName.ToLowerInvariant(); + internal static string AsObsoleteUid(this string qualifiedName) => + qualifiedName.ToLowerInvariant(); + + internal static string AsUid(this string qualifiedName) => + qualifiedName; } // See https://stackoverflow.com/a/5037815/267841. From e044df726624a5ae6f46ed2e4859aff193f45d7f Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 19 Oct 2020 20:45:57 -0700 Subject: [PATCH 68/74] Fix documentation summarization tool. --- src/Documentation/Summarizer/summarize_documentation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Documentation/Summarizer/summarize_documentation.py b/src/Documentation/Summarizer/summarize_documentation.py index 985c419646..0c1f4c1717 100644 --- a/src/Documentation/Summarizer/summarize_documentation.py +++ b/src/Documentation/Summarizer/summarize_documentation.py @@ -4,7 +4,7 @@ # Licensed under the MIT License. from collections import defaultdict -from dataclasses import dataclass, asdict +from dataclasses import dataclass, asdict, field from pathlib import Path import glob @@ -32,7 +32,9 @@ class Namespace: summary: str = "" uid: str = "" name: str = "" - items = set() + # NB: We need to set default_factory instead of default, since set is a + # mutable type. + items = field(default_factory=set) def items_of_kind(items, kind): return [ From b567cefd3f5829dbc9d3d29057ca20484487c876 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 20 Oct 2020 08:21:28 -0700 Subject: [PATCH 69/74] Adapt unit tests. --- src/Documentation/Tests.DocGenerator/DocParsingTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Documentation/Tests.DocGenerator/DocParsingTests.cs b/src/Documentation/Tests.DocGenerator/DocParsingTests.cs index 3cedc12057..7a3350a1b8 100644 --- a/src/Documentation/Tests.DocGenerator/DocParsingTests.cs +++ b/src/Documentation/Tests.DocGenerator/DocParsingTests.cs @@ -103,8 +103,8 @@ public void ParseUdt() "```", "", "# See Also", - "- @\"microsoft.quantum.canon.paulievolutionset\"", - "- @\"microsoft.quantum.canon.evolutionset\"" + "- Microsoft.Quantum.Canon.PauliEvolutionSet", + "- Microsoft.Quantum.Canon.EvolutionSet", }; string expected = @"### YamlMime:QSharpType # This file is automatically generated. @@ -376,7 +376,7 @@ public void ParseDeprecated() }; string dep = "NewName"; string warning = "> [!WARNING]\n> Deprecated\n"; - string warningText = "name has been deprecated. Please use @\"newname\" instead."; + string warningText = "name has been deprecated. Please use instead."; // Test with just the Deprecated comment section var dc = new DocComment(comments); From 8b85ec1b209d2ec971a654a54ebcd59cefad2fec Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 20 Oct 2020 08:39:36 -0700 Subject: [PATCH 70/74] One more unit test adaptation. --- src/Documentation/Tests.DocGenerator/DocParsingTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Documentation/Tests.DocGenerator/DocParsingTests.cs b/src/Documentation/Tests.DocGenerator/DocParsingTests.cs index 7a3350a1b8..223509a9f2 100644 --- a/src/Documentation/Tests.DocGenerator/DocParsingTests.cs +++ b/src/Documentation/Tests.DocGenerator/DocParsingTests.cs @@ -140,8 +140,8 @@ element indexes the subsystem on which the generator acts on. ``` syntax: newtype GeneratorIndex = ((Int[], Double[]), Int[]); seeAlso: -- microsoft.quantum.canon.paulievolutionset -- microsoft.quantum.canon.evolutionset +- Microsoft.Quantum.Canon.PauliEvolutionSet +- Microsoft.Quantum.Canon.EvolutionSet ... "; var intArrayType = ResolvedType.New(QsType.NewArrayType(ResolvedType.New(QsType.Int))); From 8a7123449aa43af582c737043f887fa779ce14f5 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 20 Oct 2020 09:15:22 -0700 Subject: [PATCH 71/74] -Force on copying summarization tool. --- build/pack.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/pack.ps1 b/build/pack.ps1 index b252337755..44e5f51dcc 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -257,7 +257,9 @@ if ($Env:ENABLE_VSIX -ne "false") { # Copy documentation summarization tool into docs drop. Push-Location (Join-Path $PSScriptRoot "../src/Documentation/Summarizer") - Copy-Item -Path *.py, *.txt -Destination $Env:DOCS_OUTDIR + # NB: We use -Force here, as the documentation summarization tool may + # already be present. + Copy-Item -Force -Path *.py, *.txt -Destination $Env:DOCS_OUTDIR Pop-Location Write-Host "##[info]Verifying manifest..." From b27b366c393f1765b58c25d9cc5061514ff1ae19 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 20 Oct 2020 09:34:58 -0700 Subject: [PATCH 72/74] Guard copying documentation tool on packing docs at all. --- build/pack.ps1 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build/pack.ps1 b/build/pack.ps1 index 44e5f51dcc..07d43b7a60 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -256,11 +256,13 @@ if ($Env:ENABLE_VSIX -ne "false") { } # Copy documentation summarization tool into docs drop. -Push-Location (Join-Path $PSScriptRoot "../src/Documentation/Summarizer") - # NB: We use -Force here, as the documentation summarization tool may - # already be present. - Copy-Item -Force -Path *.py, *.txt -Destination $Env:DOCS_OUTDIR -Pop-Location +# Note that we only copy this tool when DOCS_OUTDIR is set (that is, when we're +# collecting docs in a build artifact). +if ("$Env:DOCS_OUTDIR".Trim() -ne "") { + Push-Location (Join-Path $PSScriptRoot "../src/Documentation/Summarizer") + Copy-Item -Path *.py, *.txt -Destination $Env:DOCS_OUTDIR + Pop-Location +} Write-Host "##[info]Verifying manifest..." & (Join-Path $PSScriptRoot "manifest.ps1") From 302c4692574ad3b633f60bcad1afbf4f6997bb57 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 20 Oct 2020 23:42:57 -0700 Subject: [PATCH 73/74] Fix nullability issues from merge. --- .../DocumentationGenerator/DocumentationGeneration.cs | 3 +-- src/Documentation/DocumentationGenerator/Extensions.cs | 5 ++++- src/QsCompiler/CommandLineTool/Commands/Build.cs | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs index e31d3b6e14..3f6a434651 100644 --- a/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs +++ b/src/Documentation/DocumentationGenerator/DocumentationGeneration.cs @@ -22,7 +22,6 @@ public class DocumentationGeneration : IRewriteStep /// public DocumentationGeneration() { - this.AssemblyConstants = new Dictionary(); // will be populated by the Q# compiler this.diagnostics = new List(); // collects diagnostics that will be displayed to the user } @@ -33,7 +32,7 @@ public DocumentationGeneration() public int Priority => 0; // only compared within this dll /// - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } = new Dictionary(); /// public IEnumerable GeneratedDiagnostics => this.diagnostics; diff --git a/src/Documentation/DocumentationGenerator/Extensions.cs b/src/Documentation/DocumentationGenerator/Extensions.cs index 0f4e0e65db..3dad3758a5 100644 --- a/src/Documentation/DocumentationGenerator/Extensions.cs +++ b/src/Documentation/DocumentationGenerator/Extensions.cs @@ -174,7 +174,10 @@ internal static string ToSyntax(this QsCustomType type) => SyntaxTreeToQsharp.Default.ToCode(type); internal static string ToSyntax(this ResolvedCharacteristics characteristics) => - SyntaxTreeToQsharp.CharacteristicsExpression(characteristics); + SyntaxTreeToQsharp.CharacteristicsExpression(characteristics) + // CharacteristicsExpression returns null when the characteristics + // are an empty set; in that case, we want an empty string. + ?? string.Empty; internal static string ToSyntax(this QsCallable callable, Action? onDiagnostic = null) => SyntaxTreeToQsharp.DeclarationSignature( diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index 88fa964230..9e9bbf9883 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -41,6 +41,7 @@ public static IEnumerable UsageExamples new BuildOptions { Input = new string[] { "file.qs" }, References = new string[] { "library.dll" }, OutputFolder = Path.Combine("obj", "qsharp") }); } } +#nullable restore annotations [Option( "response-files", From aee997cc622db866ef783b438ed4efdab73f4bc6 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 21 Oct 2020 08:41:38 -0700 Subject: [PATCH 74/74] Fix nullability merge again. --- src/QsCompiler/CommandLineTool/Commands/Build.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index 9e9bbf9883..594da37663 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -41,7 +41,6 @@ public static IEnumerable UsageExamples new BuildOptions { Input = new string[] { "file.qs" }, References = new string[] { "library.dll" }, OutputFolder = Path.Combine("obj", "qsharp") }); } } -#nullable restore annotations [Option( "response-files", @@ -58,6 +57,8 @@ public static IEnumerable UsageExamples HelpText = "Destination folder where the output of the compilation will be generated.")] public string OutputFolder { get; set; } +#nullable restore annotations + [Option( "proj", Required = false,