From 260bbaf2accc2c3706a547e00995e5a669c6f87e Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Thu, 27 Feb 2020 11:11:10 -0800 Subject: [PATCH 01/22] Re-enable duplicate reference declarations test --- .../TestTargets/Libraries/Library1/AccessModifiers.qs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/QsCompiler/TestTargets/Libraries/Library1/AccessModifiers.qs b/src/QsCompiler/TestTargets/Libraries/Library1/AccessModifiers.qs index 8a38dafb1f..b7dc61fabc 100644 --- a/src/QsCompiler/TestTargets/Libraries/Library1/AccessModifiers.qs +++ b/src/QsCompiler/TestTargets/Libraries/Library1/AccessModifiers.qs @@ -1,15 +1,13 @@ /// This file contains redefinitions of types and callables declared in Tests.Compiler\TestCases\AccessModifiers.qs. It /// is used as an assembly reference to test support for re-using names of inaccessible declarations in references. namespace Microsoft.Quantum.Testing.AccessModifiers { - // TODO: Uncomment these definitions when re-using names of inaccessible declarations in references is supported. + private newtype PrivateType = Unit; - // private newtype PrivateType = Unit; + internal newtype InternalType = Unit; - // internal newtype InternalType = Unit; + private function PrivateFunction () : Unit {} - // private function PrivateFunction () : Unit {} - - // internal function InternalFunction () : Unit {} + internal function InternalFunction () : Unit {} } /// This namespace contains additional definitions of types and callables meant to be used by the From bec4ad8396c2f7406319584238fb1cfcf3f1e8f7 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Fri, 28 Feb 2020 16:20:51 -0800 Subject: [PATCH 02/22] Add RenameReferences transformation --- .../Transformations/SearchAndReplace.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/QsCompiler/Transformations/SearchAndReplace.cs b/src/QsCompiler/Transformations/SearchAndReplace.cs index e12ed5dd81..a8034b5224 100644 --- a/src/QsCompiler/Transformations/SearchAndReplace.cs +++ b/src/QsCompiler/Transformations/SearchAndReplace.cs @@ -446,6 +446,90 @@ public override QsExpressionKind OnIdentifier(Identifier sym, QsNullable + /// A transformation that renames all references to each given qualified name. + /// + public class RenameReferences : SyntaxTreeTransformation + { + private readonly IImmutableDictionary names; + + /// + /// Creates a new rename references transformation. + /// + /// The mapping from existing names to new names. + public RenameReferences(IImmutableDictionary names) + { + this.names = names; + Types = new TypeTransformation(this); + ExpressionKinds = new ExpressionKindTransformation(this); + Namespaces = new NamespaceTransformation(this); + } + + /// + /// Gets the renamed version of the qualified name if one exists; otherwise, returns the original name. + /// + /// The qualified name to rename. + /// + /// The renamed version of the qualified name if one exists; otherwise, returns the original name. + /// + private QsQualifiedName GetNewName(QsQualifiedName name) => names.GetValueOrDefault(name) ?? name; + + private class TypeTransformation : Core.TypeTransformation + { + private readonly RenameReferences parent; + + public TypeTransformation(RenameReferences parent) : base(parent) => this.parent = parent; + + public override QsTypeKind OnUserDefinedType(UserDefinedType udt) + { + var newName = parent.GetNewName(new QsQualifiedName(udt.Namespace, udt.Name)); + return base.OnUserDefinedType(new UserDefinedType(newName.Namespace, newName.Name, udt.Range)); + } + + public override QsTypeKind OnTypeParameter(QsTypeParameter tp) => + base.OnTypeParameter(new QsTypeParameter(parent.GetNewName(tp.Origin), tp.TypeName, tp.Range)); + } + + private class ExpressionKindTransformation : Core.ExpressionKindTransformation + { + private readonly RenameReferences parent; + + public ExpressionKindTransformation(RenameReferences parent) : base(parent) => this.parent = parent; + + public override QsExpressionKind OnIdentifier(Identifier id, + QsNullable> typeArgs) + { + if (id is Identifier.GlobalCallable global) + { + id = Identifier.NewGlobalCallable(parent.GetNewName(global.Item)); + } + return base.OnIdentifier(id, typeArgs); + } + } + + private class NamespaceTransformation : Core.NamespaceTransformation + { + private readonly RenameReferences parent; + + public NamespaceTransformation(RenameReferences parent) : base(parent) => this.parent = parent; + + public override QsCallable OnCallableDeclaration(QsCallable callable) => + base.OnCallableDeclaration(callable.WithFullName(parent.GetNewName)); + + public override QsCustomType OnTypeDeclaration(QsCustomType type) => + base.OnTypeDeclaration(new QsCustomType( + fullName: parent.GetNewName(type.FullName), + attributes: type.Attributes, + modifiers: type.Modifiers, + sourceFile: type.SourceFile, + location: type.Location, + type: type.Type, + typeItems: type.TypeItems, + documentation: type.Documentation, + comments: type.Comments)); + } + } + // general purpose helpers From efb9a4cb1165817711c297c6efad668eb6b2550b Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Fri, 28 Feb 2020 17:32:48 -0800 Subject: [PATCH 03/22] Add methods for renaming declaration headers --- .../Transformations/SearchAndReplace.cs | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/QsCompiler/Transformations/SearchAndReplace.cs b/src/QsCompiler/Transformations/SearchAndReplace.cs index a8034b5224..f67f35e49f 100644 --- a/src/QsCompiler/Transformations/SearchAndReplace.cs +++ b/src/QsCompiler/Transformations/SearchAndReplace.cs @@ -465,6 +465,87 @@ public RenameReferences(IImmutableDictionary n Namespaces = new NamespaceTransformation(this); } + /// + /// Renames references in the callable declaration header, including the name of the callable itself. + /// + /// The callable declaration header in which to rename references. + /// The callable declaration header with renamed references. + public CallableDeclarationHeader OnCallableDeclarationHeader(CallableDeclarationHeader callable) => + new CallableDeclarationHeader( + kind: callable.Kind, + qualifiedName: GetNewName(callable.QualifiedName), + attributes: callable.Attributes.Select(Namespaces.OnAttribute).ToImmutableArray(), + modifiers: callable.Modifiers, + sourceFile: callable.SourceFile, + position: callable.Position, + symbolRange: callable.SymbolRange, + argumentTuple: Namespaces.OnArgumentTuple(callable.ArgumentTuple), + signature: Namespaces.OnSignature(callable.Signature), + documentation: Namespaces.OnDocumentation(callable.Documentation)); + + /// + /// Renames references in the specialization declaration header, including the name of the specialization + /// itself. + /// + /// The specialization declaration header in which to rename references. + /// The specialization declaration header with renamed references. + public SpecializationDeclarationHeader OnSpecializationDeclarationHeader( + SpecializationDeclarationHeader specialization) + { + var typeArguments = + specialization.TypeArguments.IsValue + ? QsNullable>.NewValue( + specialization.TypeArguments.Item.Select(Types.OnType).ToImmutableArray()) + : QsNullable>.Null; + return new SpecializationDeclarationHeader( + kind: specialization.Kind, + typeArguments: typeArguments, + information: specialization.Information, + parent: GetNewName(specialization.Parent), + attributes: specialization.Attributes.Select(Namespaces.OnAttribute).ToImmutableArray(), + sourceFile: specialization.SourceFile, + position: specialization.Position, + headerRange: specialization.HeaderRange, + documentation: Namespaces.OnDocumentation(specialization.Documentation)); + } + + /// + /// Renames references in the specialization implementation. + /// + /// The specialization implementation in which to rename references. + /// The specialization implementation with renamed references. + public SpecializationImplementation OnSpecializationImplementation(SpecializationImplementation implementation) + { + if (implementation is SpecializationImplementation.Provided provided) + { + return SpecializationImplementation.NewProvided(Namespaces.OnArgumentTuple(provided.Item1), + Statements.OnScope(provided.Item2)); + } + else + { + return implementation; + } + } + + /// + /// Renames references in the type declaration header, including the name of the type itself. + /// + /// The type declaration header in which to rename references. + /// The type declaration header with renamed references. + public TypeDeclarationHeader OnTypeDeclarationHeader(TypeDeclarationHeader type) + { + return new TypeDeclarationHeader( + qualifiedName: GetNewName(type.QualifiedName), + attributes: type.Attributes.Select(Namespaces.OnAttribute).ToImmutableArray(), + modifiers: type.Modifiers, + sourceFile: type.SourceFile, + position: type.Position, + symbolRange: type.SymbolRange, + type: Types.OnType(type.Type), + typeItems: Namespaces.OnTypeItems(type.TypeItems), + documentation: Namespaces.OnDocumentation(type.Documentation)); + } + /// /// Gets the renamed version of the qualified name if one exists; otherwise, returns the original name. /// From 2264e5032918eefab09d639899c7e3d85e8f1bf6 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 3 Mar 2020 09:28:56 -0800 Subject: [PATCH 04/22] Rename internal declarations when references are loaded --- .../CompilationManager/CompilationUnit.cs | 52 ++++++++++++++++--- .../Tests.Compiler/AccessModifierTests.fs | 14 ++--- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index d300341b85..72db821f8c 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -6,12 +6,15 @@ using System.Collections.Immutable; using System.Collections.ObjectModel; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using Microsoft.Quantum.QsCompiler.DataTypes; using Microsoft.Quantum.QsCompiler.Diagnostics; using Microsoft.Quantum.QsCompiler.SymbolManagement; using Microsoft.Quantum.QsCompiler.SyntaxProcessing; +using Microsoft.Quantum.QsCompiler.SyntaxTokens; using Microsoft.Quantum.QsCompiler.SyntaxTree; +using Microsoft.Quantum.QsCompiler.Transformations.SearchAndReplace; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -28,9 +31,9 @@ public class Headers public readonly ImmutableArray<(SpecializationDeclarationHeader, SpecializationImplementation)> Specializations; public readonly ImmutableArray Types; - private Headers(string source, - IEnumerable callables = null, - IEnumerable<(SpecializationDeclarationHeader, SpecializationImplementation)> specs = null, + internal Headers(string source, + IEnumerable callables = null, + IEnumerable<(SpecializationDeclarationHeader, SpecializationImplementation)> specs = null, IEnumerable types = null) { NonNullable SourceOr(NonNullable origSource) => NonNullable.New(source ?? origSource.Value); @@ -74,6 +77,36 @@ private static IEnumerable TypeHeaders(IEnumerable<(strin attributes.Select(IsDeclaration("TypeDeclarationAttribute")).Where(v => v != null) .Select(TypeDeclarationHeader.FromJson).Select(built => built.Item2); + /// + /// Renames all private and internal declarations in the headers to have names that are based on the path to the + /// referenced assembly. + /// + /// The path to the assembly that is the source of the given headers. + /// The declaration headers in the assembly. + /// + private static Headers RenameInternals(string source, Headers headers) + { + static bool IsInternal(AccessModifier access) => access.IsInternal || access.IsPrivate; + + var prefix = Regex.Replace(source, @"[^A-Za-z0-9_]", "_"); // TODO: This isn't necessarily unique. + var internalNames = headers.Callables + .Where(callable => IsInternal(callable.Modifiers.Access)) + .Select(callable => callable.QualifiedName) + .Concat(headers.Types + .Where(type => IsInternal(type.Modifiers.Access)) + .Select(type => type.QualifiedName)) + .ToImmutableDictionary( + name => name, + name => new QsQualifiedName(name.Namespace, + NonNullable.New($"__{prefix}_{name.Name.Value}__"))); + var rename = new RenameReferences(internalNames); + var callables = headers.Callables.Select(rename.OnCallableDeclarationHeader); + var specializations = headers.Specializations.Select( + specialization => (rename.OnSpecializationDeclarationHeader(specialization.Item1), + rename.OnSpecializationImplementation(specialization.Item2))); + var types = headers.Types.Select(rename.OnTypeDeclarationHeader); + return new Headers(source, callables, specializations, types); + } /// /// Dictionary that maps the id of a referenced assembly (given by its location on disk) to the headers defined in that assembly. @@ -109,14 +142,17 @@ internal References Remove(NonNullable source, Action /// Given a dictionary that maps the ids of dll files to the corresponding headers, - /// initializes a new set of references based on the given headers and verifies that there are no conflicts. - /// Calls the given Action onError with suitable diagnostics if two or more references conflict, - /// i.e. if two or more references contain a declaration with the same fully qualified name. - /// Throws an ArgumentNullException if the given dictionary of references is null. + /// initializes a new set of references based on the given headers and verifies that there are no conflicts. + /// Calls the given Action onError with suitable diagnostics if two or more references conflict, + /// i.e. if two or more references contain a public declaration with the same fully qualified name. + /// Throws an ArgumentNullException if the given dictionary of references is null. /// public References(ImmutableDictionary, Headers> refs, Action onError = null) { - this.Declarations = refs ?? throw new ArgumentNullException(nameof(refs)); + this.Declarations = + (refs ?? throw new ArgumentNullException(nameof(refs))) + .Select(reference => (reference.Key, RenameInternals(reference.Key.Value, reference.Value))) + .ToImmutableDictionary(reference => reference.Key, reference => reference.Item2); if (onError == null) return; var conflictingCallables = refs.Values.SelectMany(r => r.Callables) diff --git a/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs b/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs index f9a35640c2..7f8431b12c 100644 --- a/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs +++ b/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs @@ -65,9 +65,11 @@ type AccessModifierTests (output) = [] member this.``References`` () = - this.Expect "CallableReferencePrivateInaccessible" [Error ErrorCode.InaccessibleCallable] - this.Expect "CallableReferenceInternalInaccessible" [Error ErrorCode.InaccessibleCallable] - this.Expect "TypeReferencePrivateInaccessible" [Error ErrorCode.InaccessibleType] - this.Expect "TypeConstructorReferencePrivateInaccessible" [Error ErrorCode.InaccessibleCallable] - this.Expect "TypeReferenceInternalInaccessible" [Error ErrorCode.InaccessibleType] - this.Expect "TypeConstructorReferenceInternalInaccessible" [Error ErrorCode.InaccessibleCallable] + // Since internal declarations in references are renamed, the errors will be for unidentified callables and + // types instead of inaccessible ones. + this.Expect "CallableReferencePrivateInaccessible" [Error ErrorCode.UnknownIdentifier] + this.Expect "CallableReferenceInternalInaccessible" [Error ErrorCode.UnknownIdentifier] + this.Expect "TypeReferencePrivateInaccessible" [Error ErrorCode.UnknownType] + this.Expect "TypeConstructorReferencePrivateInaccessible" [Error ErrorCode.UnknownIdentifier] + this.Expect "TypeReferenceInternalInaccessible" [Error ErrorCode.UnknownType] + this.Expect "TypeConstructorReferenceInternalInaccessible" [Error ErrorCode.UnknownIdentifier] From 2b07241875cf4974a8698b07f0060b382c5b75eb Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 3 Mar 2020 23:34:35 -0800 Subject: [PATCH 05/22] Start adding unit tests for internal renaming --- .../CompilationManager/CompilationUnit.cs | 21 ++++-- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 67 ++++++++++++++++++- .../LinkingTests/InternalRenaming.qs | 14 ++++ .../Tests.Compiler/TestUtils/Signatures.fs | 1 + .../Tests.Compiler/Tests.Compiler.fsproj | 3 + 5 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index 72db821f8c..82384ef486 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -88,17 +88,13 @@ private static Headers RenameInternals(string source, Headers headers) { static bool IsInternal(AccessModifier access) => access.IsInternal || access.IsPrivate; - var prefix = Regex.Replace(source, @"[^A-Za-z0-9_]", "_"); // TODO: This isn't necessarily unique. var internalNames = headers.Callables .Where(callable => IsInternal(callable.Modifiers.Access)) .Select(callable => callable.QualifiedName) .Concat(headers.Types .Where(type => IsInternal(type.Modifiers.Access)) .Select(type => type.QualifiedName)) - .ToImmutableDictionary( - name => name, - name => new QsQualifiedName(name.Namespace, - NonNullable.New($"__{prefix}_{name.Name.Value}__"))); + .ToImmutableDictionary(name => name, name => GetNewNameForInternal(source, name)); var rename = new RenameReferences(internalNames); var callables = headers.Callables.Select(rename.OnCallableDeclarationHeader); var specializations = headers.Specializations.Select( @@ -108,6 +104,21 @@ private static Headers RenameInternals(string source, Headers headers) return new Headers(source, callables, specializations, types); } + /// + /// Returns a new name for an internal declaration that is uniquely tagged with its source assembly path. + /// + /// The path to the reference assembly in which the internal name is declared. + /// The name of the internal declaration. + /// + /// A new name for an internal declaration that is uniquely tagged with its source assembly path. + /// + internal static QsQualifiedName GetNewNameForInternal(string source, QsQualifiedName name) + { + // TODO: This isn't necessarily unique. + var prefix = Regex.Replace(source, @"[^A-Za-z0-9_]", "_"); + return new QsQualifiedName(name.Namespace, NonNullable.New($"__{prefix}_{name.Name.Value}__")); + } + /// /// Dictionary that maps the id of a referenced assembly (given by its location on disk) to the headers defined in that assembly. /// diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 760730135e..5f4348f07b 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -5,7 +5,10 @@ namespace Microsoft.Quantum.QsCompiler.Testing open System open System.Collections.Generic +open System.Collections.Immutable open System.IO +open System.Linq +open Microsoft.VisualStudio.LanguageServer.Protocol open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.CompilationBuilder open Microsoft.Quantum.QsCompiler.DataTypes @@ -15,6 +18,7 @@ open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.IntrinsicResolution open Microsoft.Quantum.QsCompiler.Transformations.Monomorphization open Microsoft.Quantum.QsCompiler.Transformations.Monomorphization.Validation +open Microsoft.Quantum.QsCompiler.Transformations.SearchAndReplace open Xunit open Xunit.Abstractions @@ -24,9 +28,37 @@ type LinkingTests (output:ITestOutputHelper) = let compilationManager = new CompilationUnitManager(new Action (fun ex -> failwith ex.Message)) - let getTempFile () = new Uri(Path.GetFullPath(Path.GetRandomFileName())) + let getTempFile () = new Uri(Path.GetFullPath(Path.GetRandomFileName() + ".qs")) let getManager uri content = CompilationUnitManager.InitializeFileManager(uri, content, compilationManager.PublishDiagnostics, compilationManager.LogException) + let defaultOffset = { + Offset = DiagnosticTools.AsTuple (Position (0, 0)) + Range = QsCompilerDiagnostic.DefaultRange + } + + /// Counts the number of references to the qualified name in all of the namespaces. The declaration of the name is + /// included in the count. + let countReferencesInNamespaces (name : QsQualifiedName) namespaces = + let references = IdentifierReferences (name, defaultOffset) + namespaces |> Seq.iter (references.Namespaces.OnNamespace >> ignore) + // TODO: What if name is a type? Is the type constructor included? + if obj.ReferenceEquals (references.SharedState.DeclarationLocation, null) + then references.SharedState.Locations.Count + else 1 + references.SharedState.Locations.Count + + /// Counts the number of references to the qualified name in the headers and specialization implementations. The + /// declaration of the name is included in the count. + let countReferencesInHeaders (name : QsQualifiedName) (headers : References.Headers) = + let references = IdentifierReferences (name, defaultOffset) + references.SharedState.DeclarationOffset <- (0, 0) + headers.Specializations.Select(fun specialization -> snd (specialization.ToTuple ())) + |> Seq.iter (references.Namespaces.OnSpecializationImplementation >> ignore) + let count = + headers.Callables.Count(fun callable -> callable.QualifiedName = name) + + headers.Types.Count(fun types -> types.QualifiedName = name) + + references.SharedState.Locations.Count + count + do let addOrUpdateSourceFile filePath = getManager (new Uri(filePath)) (File.ReadAllText filePath) |> compilationManager.AddOrUpdateSourceFileAsync |> ignore Path.Combine ("TestCases", "LinkingTests", "Core.qs") |> Path.GetFullPath |> addOrUpdateSourceFile @@ -111,6 +143,35 @@ type LinkingTests (output:ITestOutputHelper) = |> Assert.True) |> ignore + member private this.RunInternalRenamingTest num = + let chunks = LinkingTests.ReadAndChunkSourceFile "InternalRenaming.qs" + let compilation = this.BuildContent chunks.[num - 1] + + let name = { + Namespace = NonNullable<_>.New Signatures.InternalRenamingNs + Name = NonNullable<_>.New "RenameMe" + } + let beforeCount = countReferencesInNamespaces name [compilation.SyntaxTree.[name.Namespace]] + + let sourceName = "InternalRenaming.dll" + let headers = + (NonNullable<_>.New sourceName, compilation.BuiltCompilation.Namespaces) + |> References.Headers + let references = + [KeyValuePair.Create(NonNullable<_>.New sourceName, headers)] + |> ImmutableDictionary.CreateRange + |> References + + let oldAfterCount = + countReferencesInHeaders name references.Declarations.[NonNullable<_>.New sourceName] + let newName = References.GetNewNameForInternal (sourceName, name) + let newAfterCount = + countReferencesInHeaders newName references.Declarations.[NonNullable<_>.New sourceName] + + Assert.NotEqual (0, beforeCount) + Assert.Equal (0, oldAfterCount) + Assert.Equal (beforeCount, newAfterCount) + [] member this.``Monomorphization`` () = @@ -245,3 +306,7 @@ type LinkingTests (output:ITestOutputHelper) = this.Expect "InvalidEntryPoint35" [Error ErrorCode.CallableTypeInEntryPointSignature; Error ErrorCode.UserDefinedTypeInEntryPointSignature] this.Expect "InvalidEntryPoint36" [Error ErrorCode.CallableTypeInEntryPointSignature; Error ErrorCode.UserDefinedTypeInEntryPointSignature] + + [] + member this.``Rename internal call references`` () = + this.RunInternalRenamingTest 1 \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs new file mode 100644 index 0000000000..439b5ba975 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Test 1 +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal operation RenameMe () : Unit { + } + + operation Foo () : Unit { + RenameMe(); + } +} + +// ================================= diff --git a/src/QsCompiler/Tests.Compiler/TestUtils/Signatures.fs b/src/QsCompiler/Tests.Compiler/TestUtils/Signatures.fs index e7fd7462ac..5a8be35942 100644 --- a/src/QsCompiler/Tests.Compiler/TestUtils/Signatures.fs +++ b/src/QsCompiler/Tests.Compiler/TestUtils/Signatures.fs @@ -113,6 +113,7 @@ let public MonomorphizationNs = "Microsoft.Quantum.Testing.Monomorphization" let public GenericsNs = "Microsoft.Quantum.Testing.Generics" let public IntrinsicResolutionNs = "Microsoft.Quantum.Testing.IntrinsicResolution" let public ClassicalControlNs = "Microsoft.Quantum.Testing.ClassicalControl" +let public InternalRenamingNs = "Microsoft.Quantum.Testing.InternalRenaming" /// Expected callable signatures to be found when running Monomorphization tests let public MonomorphizationSignatures = diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 53a48775d0..293938f255 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -47,6 +47,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 7580d91a3687125502c860e4a419cadca7b81813 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 3 Mar 2020 23:50:28 -0800 Subject: [PATCH 06/22] Add test for renaming internal type --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 8 ++++++-- .../TestCases/LinkingTests/InternalRenaming.qs | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 5f4348f07b..b78b24f119 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -41,7 +41,6 @@ type LinkingTests (output:ITestOutputHelper) = let countReferencesInNamespaces (name : QsQualifiedName) namespaces = let references = IdentifierReferences (name, defaultOffset) namespaces |> Seq.iter (references.Namespaces.OnNamespace >> ignore) - // TODO: What if name is a type? Is the type constructor included? if obj.ReferenceEquals (references.SharedState.DeclarationLocation, null) then references.SharedState.Locations.Count else 1 + references.SharedState.Locations.Count @@ -309,4 +308,9 @@ type LinkingTests (output:ITestOutputHelper) = [] member this.``Rename internal call references`` () = - this.RunInternalRenamingTest 1 \ No newline at end of file + this.RunInternalRenamingTest 1 + + [] + member this.``Rename internal type references`` () = + // TODO: Check that both RenameMe and Foo are renamed. + this.RunInternalRenamingTest 2 diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs index 439b5ba975..8ce3d9d95c 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -12,3 +12,11 @@ namespace Microsoft.Quantum.Testing.InternalRenaming { } // ================================= + +// Test 2 +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal newtype RenameMe = Unit; + + internal function Foo (x : RenameMe) : Unit { + } +} From 2931e001bc72c68433ee49c47f867becfb50faa5 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 4 Mar 2020 10:12:25 -0800 Subject: [PATCH 07/22] Improve framework for internal renaming tests --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 37 +++++++++++-------- .../LinkingTests/InternalRenaming.qs | 10 ++--- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index b78b24f119..2e41d86e96 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -38,7 +38,7 @@ type LinkingTests (output:ITestOutputHelper) = /// Counts the number of references to the qualified name in all of the namespaces. The declaration of the name is /// included in the count. - let countReferencesInNamespaces (name : QsQualifiedName) namespaces = + let countReferencesInNamespaces namespaces (name : QsQualifiedName) = let references = IdentifierReferences (name, defaultOffset) namespaces |> Seq.iter (references.Namespaces.OnNamespace >> ignore) if obj.ReferenceEquals (references.SharedState.DeclarationLocation, null) @@ -47,7 +47,7 @@ type LinkingTests (output:ITestOutputHelper) = /// Counts the number of references to the qualified name in the headers and specialization implementations. The /// declaration of the name is included in the count. - let countReferencesInHeaders (name : QsQualifiedName) (headers : References.Headers) = + let countReferencesInHeaders (headers : References.Headers) (name : QsQualifiedName) = let references = IdentifierReferences (name, defaultOffset) references.SharedState.DeclarationOffset <- (0, 0) headers.Specializations.Select(fun specialization -> snd (specialization.ToTuple ())) @@ -142,30 +142,33 @@ type LinkingTests (output:ITestOutputHelper) = |> Assert.True) |> ignore - member private this.RunInternalRenamingTest num = + /// Runs the nth internal renaming test, asserting that declarations with the given name and references to them have + /// been renamed across the compilation unit. + member private this.RunInternalRenamingTest num renamed notRenamed = let chunks = LinkingTests.ReadAndChunkSourceFile "InternalRenaming.qs" let compilation = this.BuildContent chunks.[num - 1] - let name = { - Namespace = NonNullable<_>.New Signatures.InternalRenamingNs - Name = NonNullable<_>.New "RenameMe" - } - let beforeCount = countReferencesInNamespaces name [compilation.SyntaxTree.[name.Namespace]] + let beforeCount = + Seq.concat [renamed; notRenamed] + |> Seq.map (countReferencesInNamespaces compilation.BuiltCompilation.Namespaces) + |> Seq.sum let sourceName = "InternalRenaming.dll" - let headers = - (NonNullable<_>.New sourceName, compilation.BuiltCompilation.Namespaces) - |> References.Headers + let headers = (NonNullable<_>.New sourceName, compilation.BuiltCompilation.Namespaces) |> References.Headers let references = [KeyValuePair.Create(NonNullable<_>.New sourceName, headers)] |> ImmutableDictionary.CreateRange |> References let oldAfterCount = - countReferencesInHeaders name references.Declarations.[NonNullable<_>.New sourceName] - let newName = References.GetNewNameForInternal (sourceName, name) + renamed + |> Seq.map (countReferencesInHeaders references.Declarations.[NonNullable<_>.New sourceName]) + |> Seq.sum + let newNames = renamed |> Seq.map (sourceName |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) let newAfterCount = - countReferencesInHeaders newName references.Declarations.[NonNullable<_>.New sourceName] + Seq.concat [newNames; notRenamed] + |> Seq.map (countReferencesInHeaders references.Declarations.[NonNullable<_>.New sourceName]) + |> Seq.sum Assert.NotEqual (0, beforeCount) Assert.Equal (0, oldAfterCount) @@ -309,8 +312,12 @@ type LinkingTests (output:ITestOutputHelper) = [] member this.``Rename internal call references`` () = this.RunInternalRenamingTest 1 + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] [] member this.``Rename internal type references`` () = - // TODO: Check that both RenameMe and Foo are renamed. this.RunInternalRenamingTest 2 + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] + [] diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs index 8ce3d9d95c..91f2bcaccc 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -3,11 +3,11 @@ // Test 1 namespace Microsoft.Quantum.Testing.InternalRenaming { - internal operation RenameMe () : Unit { + internal operation Foo () : Unit { } - operation Foo () : Unit { - RenameMe(); + operation Bar () : Unit { + Foo(); } } @@ -15,8 +15,8 @@ namespace Microsoft.Quantum.Testing.InternalRenaming { // Test 2 namespace Microsoft.Quantum.Testing.InternalRenaming { - internal newtype RenameMe = Unit; + internal newtype Foo = Unit; - internal function Foo (x : RenameMe) : Unit { + internal function Bar (x : Foo) : Unit { } } From 1113c1e9087e53b32a288761e2f0094510c094dc Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 4 Mar 2020 13:34:36 -0800 Subject: [PATCH 08/22] Add more tests Some tests failing due to bugs. --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 63 +++++++++++++-- .../LinkingTests/InternalRenaming.qs | 80 ++++++++++++++++++- 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 2e41d86e96..fc8cb2503d 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -50,11 +50,25 @@ type LinkingTests (output:ITestOutputHelper) = let countReferencesInHeaders (headers : References.Headers) (name : QsQualifiedName) = let references = IdentifierReferences (name, defaultOffset) references.SharedState.DeclarationOffset <- (0, 0) - headers.Specializations.Select(fun specialization -> snd (specialization.ToTuple ())) - |> Seq.iter (references.Namespaces.OnSpecializationImplementation >> ignore) + + for callable in headers.Callables do + Seq.iter (references.Namespaces.OnAttribute >> ignore) callable.Attributes + references.Namespaces.OnArgumentTuple callable.ArgumentTuple |> ignore + references.Namespaces.OnSignature callable.Signature |> ignore + references.Namespaces.OnDocumentation callable.Documentation |> ignore + for (specialization, implementation) in headers.Specializations do + Seq.iter (references.Namespaces.OnAttribute >> ignore) specialization.Attributes + references.Namespaces.OnDocumentation specialization.Documentation |> ignore + references.Namespaces.OnSpecializationImplementation implementation |> ignore + for qsType in headers.Types do + Seq.iter (references.Namespaces.OnAttribute >> ignore) qsType.Attributes + references.Types.OnType qsType.Type |> ignore + references.Namespaces.OnTypeItems qsType.TypeItems |> ignore + references.Namespaces.OnDocumentation qsType.Documentation |> ignore + let count = headers.Callables.Count(fun callable -> callable.QualifiedName = name) + - headers.Types.Count(fun types -> types.QualifiedName = name) + + headers.Types.Count(fun qsType -> qsType.QualifiedName = name) + references.SharedState.Locations.Count count @@ -310,14 +324,49 @@ type LinkingTests (output:ITestOutputHelper) = [] - member this.``Rename internal call references`` () = + member this.``Rename internal operation call references`` () = this.RunInternalRenamingTest 1 [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] [] - member this.``Rename internal type references`` () = + member this.``Rename internal function call references`` () = this.RunInternalRenamingTest 2 - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] + + [] + member this.``Rename internal type references`` () = + this.RunInternalRenamingTest 3 + [ + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" } + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Baz" } + ] [] + + [] + member this.``Rename internal references across namespaces`` () = + this.RunInternalRenamingTest 4 + [ + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" } + { Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Qux" } + ] + [{ Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Baz" }] + + [] + member this.``Rename internal qualified references`` () = + this.RunInternalRenamingTest 5 + [ + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } + { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" } + { Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Qux" } + ] + [{ Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Baz" }] + + [] + member this.``Rename internal attribute references`` () = + this.RunInternalRenamingTest 6 + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] + [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs index 91f2bcaccc..9750ed8507 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// Test 1 +// Test 1: Rename internal operation call references + namespace Microsoft.Quantum.Testing.InternalRenaming { internal operation Foo () : Unit { } @@ -12,11 +13,84 @@ namespace Microsoft.Quantum.Testing.InternalRenaming { } // ================================= +// Test 2: Rename internal function call references + +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal function Foo () : Int { + return 42; + } + + function Bar () : Unit { + let x = Foo(); + let y = 1 + (Foo() - 5); + let z = (Foo(), 9); + } +} + +// ================================= +// Test 3: Rename internal type references + +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal newtype Foo = Unit; + + internal newtype Bar = (Int, Foo); + + internal function Baz (x : Foo) : Foo { + return Foo(); + } +} + +// ================================= +// Test 4: Rename internal references across namespaces + +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal newtype Foo = Unit; + + internal function Bar () : Unit { + } +} + +namespace Microsoft.Quantum.Testing.InternalRenaming.Extra { + open Microsoft.Quantum.Testing.InternalRenaming; + + function Baz () : Unit { + return Bar(); + } + + internal function Qux (x : Foo) : Foo { + return x; + } +} + +// ================================= +// Test 5: Rename internal qualified references + +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal newtype Foo = Unit; + + internal function Bar () : Unit { + } +} + +namespace Microsoft.Quantum.Testing.InternalRenaming.Extra { + function Baz () : Unit { + return Microsoft.Quantum.Testing.InternalRenaming.Bar(); + } + + internal function Qux (x : Microsoft.Quantum.Testing.InternalRenaming.Foo) + : Microsoft.Quantum.Testing.InternalRenaming.Foo { + return x; + } +} + +// ================================= +// Test 6: Rename internal attribute references -// Test 2 namespace Microsoft.Quantum.Testing.InternalRenaming { + @Attribute() internal newtype Foo = Unit; - internal function Bar (x : Foo) : Unit { + @Foo() + function Bar () : Unit { } } From 89b3f6d685192abf160b407cbbc137bc5176dfbe Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 4 Mar 2020 13:51:30 -0800 Subject: [PATCH 09/22] Use spaces instead of tabs in InternalRenaming.qs --- .../LinkingTests/InternalRenaming.qs | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs index 9750ed8507..5a344e4fbe 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -4,93 +4,93 @@ // Test 1: Rename internal operation call references namespace Microsoft.Quantum.Testing.InternalRenaming { - internal operation Foo () : Unit { - } + internal operation Foo () : Unit { + } - operation Bar () : Unit { - Foo(); - } + operation Bar () : Unit { + Foo(); + } } // ================================= // Test 2: Rename internal function call references namespace Microsoft.Quantum.Testing.InternalRenaming { - internal function Foo () : Int { - return 42; - } - - function Bar () : Unit { - let x = Foo(); - let y = 1 + (Foo() - 5); - let z = (Foo(), 9); - } + internal function Foo () : Int { + return 42; + } + + function Bar () : Unit { + let x = Foo(); + let y = 1 + (Foo() - 5); + let z = (Foo(), 9); + } } // ================================= // Test 3: Rename internal type references namespace Microsoft.Quantum.Testing.InternalRenaming { - internal newtype Foo = Unit; + internal newtype Foo = Unit; - internal newtype Bar = (Int, Foo); + internal newtype Bar = (Int, Foo); - internal function Baz (x : Foo) : Foo { - return Foo(); - } + internal function Baz (x : Foo) : Foo { + return Foo(); + } } // ================================= // Test 4: Rename internal references across namespaces namespace Microsoft.Quantum.Testing.InternalRenaming { - internal newtype Foo = Unit; + internal newtype Foo = Unit; - internal function Bar () : Unit { - } + internal function Bar () : Unit { + } } namespace Microsoft.Quantum.Testing.InternalRenaming.Extra { - open Microsoft.Quantum.Testing.InternalRenaming; + open Microsoft.Quantum.Testing.InternalRenaming; - function Baz () : Unit { - return Bar(); - } + function Baz () : Unit { + return Bar(); + } - internal function Qux (x : Foo) : Foo { - return x; - } + internal function Qux (x : Foo) : Foo { + return x; + } } // ================================= // Test 5: Rename internal qualified references namespace Microsoft.Quantum.Testing.InternalRenaming { - internal newtype Foo = Unit; + internal newtype Foo = Unit; - internal function Bar () : Unit { - } + internal function Bar () : Unit { + } } namespace Microsoft.Quantum.Testing.InternalRenaming.Extra { - function Baz () : Unit { - return Microsoft.Quantum.Testing.InternalRenaming.Bar(); - } - - internal function Qux (x : Microsoft.Quantum.Testing.InternalRenaming.Foo) - : Microsoft.Quantum.Testing.InternalRenaming.Foo { - return x; - } + function Baz () : Unit { + return Microsoft.Quantum.Testing.InternalRenaming.Bar(); + } + + internal function Qux (x : Microsoft.Quantum.Testing.InternalRenaming.Foo) + : Microsoft.Quantum.Testing.InternalRenaming.Foo { + return x; + } } // ================================= // Test 6: Rename internal attribute references namespace Microsoft.Quantum.Testing.InternalRenaming { - @Attribute() - internal newtype Foo = Unit; + @Attribute() + internal newtype Foo = Unit; - @Foo() - function Bar () : Unit { - } + @Foo() + function Bar () : Unit { + } } From 7397ae5b99bfa625553f201dd1bfee3f45b5d43d Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 4 Mar 2020 15:52:28 -0800 Subject: [PATCH 10/22] Fix renaming internal attributes --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 3 ++- .../Transformations/SearchAndReplace.cs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index fc8cb2503d..b38613fd5a 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -67,7 +67,8 @@ type LinkingTests (output:ITestOutputHelper) = references.Namespaces.OnDocumentation qsType.Documentation |> ignore let count = - headers.Callables.Count(fun callable -> callable.QualifiedName = name) + + // TODO: We ignore type constructors because countReferencesInNamespaces is not able to count them. + headers.Callables.Count(fun callable -> callable.QualifiedName = name && callable.Kind <> TypeConstructor) + headers.Types.Count(fun qsType -> qsType.QualifiedName = name) + references.SharedState.Locations.Count count diff --git a/src/QsCompiler/Transformations/SearchAndReplace.cs b/src/QsCompiler/Transformations/SearchAndReplace.cs index f67f35e49f..cb17fdc264 100644 --- a/src/QsCompiler/Transformations/SearchAndReplace.cs +++ b/src/QsCompiler/Transformations/SearchAndReplace.cs @@ -608,6 +608,21 @@ public override QsCustomType OnTypeDeclaration(QsCustomType type) => typeItems: type.TypeItems, documentation: type.Documentation, comments: type.Comments)); + + public override QsDeclarationAttribute OnAttribute(QsDeclarationAttribute attribute) + { + var newTypeId = QsNullable.Null; + if (attribute.TypeId.IsValue) + { + var newName = parent.GetNewName(new QsQualifiedName(attribute.TypeId.Item.Namespace, + attribute.TypeId.Item.Name)); + newTypeId = QsNullable.NewValue( + new UserDefinedType(newName.Namespace, newName.Name, attribute.TypeId.Item.Range)); + } + var newArgument = parent.Expressions.OnTypedExpression(attribute.Argument); + return base.OnAttribute( + new QsDeclarationAttribute(newTypeId, newArgument, attribute.Offset, attribute.Comments)); + } } } From defcf506821f945155135a01b635b5285592ee9b Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Thu, 5 Mar 2020 22:26:38 -0800 Subject: [PATCH 11/22] Add shorthand for qualified names in tests --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index b38613fd5a..78663e451b 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -73,6 +73,11 @@ type LinkingTests (output:ITestOutputHelper) = references.SharedState.Locations.Count count + let qualifiedName ns name = { + Namespace = NonNullable<_>.New ns + Name = NonNullable<_>.New name + } + do let addOrUpdateSourceFile filePath = getManager (new Uri(filePath)) (File.ReadAllText filePath) |> compilationManager.AddOrUpdateSourceFileAsync |> ignore Path.Combine ("TestCases", "LinkingTests", "Core.qs") |> Path.GetFullPath |> addOrUpdateSourceFile @@ -327,22 +332,22 @@ type LinkingTests (output:ITestOutputHelper) = [] member this.``Rename internal operation call references`` () = this.RunInternalRenamingTest 1 - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] + [qualifiedName Signatures.InternalRenamingNs "Foo"] + [qualifiedName Signatures.InternalRenamingNs "Bar"] [] member this.``Rename internal function call references`` () = this.RunInternalRenamingTest 2 - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] + [qualifiedName Signatures.InternalRenamingNs "Foo"] + [qualifiedName Signatures.InternalRenamingNs "Bar"] [] member this.``Rename internal type references`` () = this.RunInternalRenamingTest 3 [ - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" } - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Baz" } + qualifiedName Signatures.InternalRenamingNs "Foo" + qualifiedName Signatures.InternalRenamingNs "Bar" + qualifiedName Signatures.InternalRenamingNs "Baz" ] [] @@ -350,24 +355,24 @@ type LinkingTests (output:ITestOutputHelper) = member this.``Rename internal references across namespaces`` () = this.RunInternalRenamingTest 4 [ - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" } - { Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Qux" } + qualifiedName Signatures.InternalRenamingNs "Foo" + qualifiedName Signatures.InternalRenamingNs "Bar" + qualifiedName (Signatures.InternalRenamingNs + ".Extra") "Qux" ] - [{ Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Baz" }] + [qualifiedName (Signatures.InternalRenamingNs + ".Extra") "Baz"] [] member this.``Rename internal qualified references`` () = this.RunInternalRenamingTest 5 [ - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" } - { Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" } - { Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Qux" } + qualifiedName Signatures.InternalRenamingNs "Foo" + qualifiedName Signatures.InternalRenamingNs "Bar" + qualifiedName (Signatures.InternalRenamingNs + ".Extra") "Qux" ] - [{ Namespace = NonNullable<_>.New (Signatures.InternalRenamingNs + ".Extra"); Name = NonNullable<_>.New "Baz" }] + [qualifiedName (Signatures.InternalRenamingNs + ".Extra") "Baz"] [] member this.``Rename internal attribute references`` () = this.RunInternalRenamingTest 6 - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Foo" }] - [{ Namespace = NonNullable<_>.New Signatures.InternalRenamingNs; Name = NonNullable<_>.New "Bar" }] + [qualifiedName Signatures.InternalRenamingNs "Foo"] + [qualifiedName Signatures.InternalRenamingNs "Bar"] From 82da87db5b5f9307bc1082dd895021fcb77aa00f Mon Sep 17 00:00:00 2001 From: bettinaheim <34236215+bettinaheim@users.noreply.github.com> Date: Fri, 6 Mar 2020 17:15:01 -0800 Subject: [PATCH 12/22] All tests pass (#358) --- src/QsCompiler/CommandLineTool/LoadContext.cs | 2 +- .../CompilationManager/CompilationUnit.cs | 4 +- .../EditorSupport/SymbolInformation.cs | 10 +-- src/QsCompiler/Core/TypeTransformation.fs | 3 +- src/QsCompiler/DataStructures/SyntaxTree.fs | 2 + src/QsCompiler/Tests.Compiler/LinkingTests.fs | 56 ++++++------ .../Transformations/SearchAndReplace.cs | 89 +++++++------------ 7 files changed, 73 insertions(+), 93 deletions(-) diff --git a/src/QsCompiler/CommandLineTool/LoadContext.cs b/src/QsCompiler/CommandLineTool/LoadContext.cs index 1f9284ca54..02237d3452 100644 --- a/src/QsCompiler/CommandLineTool/LoadContext.cs +++ b/src/QsCompiler/CommandLineTool/LoadContext.cs @@ -111,7 +111,7 @@ private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name) return path == null ? null : LoadFromAssemblyPath(path); } - private static ConcurrentBag Loaded = + private static readonly ConcurrentBag Loaded = new ConcurrentBag(); /// diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index 82384ef486..254cba519b 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -99,7 +99,7 @@ private static Headers RenameInternals(string source, Headers headers) var callables = headers.Callables.Select(rename.OnCallableDeclarationHeader); var specializations = headers.Specializations.Select( specialization => (rename.OnSpecializationDeclarationHeader(specialization.Item1), - rename.OnSpecializationImplementation(specialization.Item2))); + rename.Namespaces.OnSpecializationImplementation(specialization.Item2))); var types = headers.Types.Select(rename.OnTypeDeclarationHeader); return new Headers(source, callables, specializations, types); } @@ -461,7 +461,7 @@ internal void UpdateCallables(IEnumerable updates) header.Location, header.Signature, header.ArgumentTuple, - ImmutableArray.Create(defaultSpec), + ImmutableArray.Create(defaultSpec), header.Documentation, QsComments.Empty ); diff --git a/src/QsCompiler/CompilationManager/EditorSupport/SymbolInformation.cs b/src/QsCompiler/CompilationManager/EditorSupport/SymbolInformation.cs index f404855810..b5360f587e 100644 --- a/src/QsCompiler/CompilationManager/EditorSupport/SymbolInformation.cs +++ b/src/QsCompiler/CompilationManager/EditorSupport/SymbolInformation.cs @@ -143,10 +143,10 @@ internal static bool TryGetReferences(this CompilationUnit compilation, QsQualif referenceLocations = namespaces.SelectMany(ns => { var locs = IdentifierReferences.Find(fullName, ns, defaultOffset, out var dLoc, limitToSourceFiles); - declLoc = declLoc ?? dLoc; + declLoc ??= dLoc; return locs; }) - .Distinct().Select(AsLocation).ToArray(); // ToArray is needed here to force the execution before checking declLoc + .Select(AsLocation).ToArray(); // ToArray is needed here to force the execution before checking declLoc declarationLocation = declLoc == null ? null : AsLocation(declLoc.Item1, declLoc.Item2.Offset, declLoc.Item2.Range); return true; } @@ -218,8 +218,8 @@ internal static bool TryGetReferences( .SelectMany(spec => spec.Implementation is SpecializationImplementation.Provided impl && spec.Location.IsValue ? IdentifierReferences.Find(definition.Item.Item1, impl.Item2, file.FileName, spec.Location.Item.Offset) - : ImmutableArray.Empty) - .Distinct().Select(AsLocation); + : ImmutableHashSet.Empty) + .Select(AsLocation); } else // the given position corresponds to a variable declared as part of a specialization declaration or implementation { @@ -227,7 +227,7 @@ spec.Implementation is SpecializationImplementation.Provided impl && spec.Locati var statements = implementation.StatementsAfterDeclaration(defStart.Subtract(specPos)); var scope = new QsScope(statements.ToImmutableArray(), locals); var rootOffset = DiagnosticTools.AsTuple(specPos); - referenceLocations = IdentifierReferences.Find(definition.Item.Item1, scope, file.FileName, rootOffset).Distinct().Select(AsLocation); + referenceLocations = IdentifierReferences.Find(definition.Item.Item1, scope, file.FileName, rootOffset).Select(AsLocation); } declarationLocation = AsLocation(file.FileName, definition.Item.Item2, defRange); return true; diff --git a/src/QsCompiler/Core/TypeTransformation.fs b/src/QsCompiler/Core/TypeTransformation.fs index 8737747695..5b619f7087 100644 --- a/src/QsCompiler/Core/TypeTransformation.fs +++ b/src/QsCompiler/Core/TypeTransformation.fs @@ -132,4 +132,5 @@ type TypeTransformationBase(options : TransformationOptions) = | ExpressionType.Result -> this.OnResult () | ExpressionType.Pauli -> this.OnPauli () | ExpressionType.Range -> this.OnRange () - ResolvedType.New |> Node.BuildOr t transformed + let ResolvedType t = ResolvedType.New (true, t) + ResolvedType |> Node.BuildOr t transformed diff --git a/src/QsCompiler/DataStructures/SyntaxTree.fs b/src/QsCompiler/DataStructures/SyntaxTree.fs index 87d83babb3..3d6e8b8fa1 100644 --- a/src/QsCompiler/DataStructures/SyntaxTree.fs +++ b/src/QsCompiler/DataStructures/SyntaxTree.fs @@ -661,6 +661,7 @@ type QsSpecialization = { with member this.AddAttribute att = {this with Attributes = this.Attributes.Add att} member this.WithImplementation impl = {this with Implementation = impl} + member this.WithParent (getName : Func<_,_>) = {this with Parent = getName.Invoke(this.Parent)} /// describes a Q# function, operation, or type constructor @@ -739,6 +740,7 @@ type QsCustomType = { } with member this.AddAttribute att = {this with Attributes = this.Attributes.Add att} + member this.WithFullName (getName : Func<_,_>) = {this with FullName = getName.Invoke(this.FullName)} /// Describes a valid Q# namespace element. diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 78663e451b..2518ae63e9 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -36,15 +36,6 @@ type LinkingTests (output:ITestOutputHelper) = Range = QsCompilerDiagnostic.DefaultRange } - /// Counts the number of references to the qualified name in all of the namespaces. The declaration of the name is - /// included in the count. - let countReferencesInNamespaces namespaces (name : QsQualifiedName) = - let references = IdentifierReferences (name, defaultOffset) - namespaces |> Seq.iter (references.Namespaces.OnNamespace >> ignore) - if obj.ReferenceEquals (references.SharedState.DeclarationLocation, null) - then references.SharedState.Locations.Count - else 1 + references.SharedState.Locations.Count - /// Counts the number of references to the qualified name in the headers and specialization implementations. The /// declaration of the name is included in the count. let countReferencesInHeaders (headers : References.Headers) (name : QsQualifiedName) = @@ -58,8 +49,8 @@ type LinkingTests (output:ITestOutputHelper) = references.Namespaces.OnDocumentation callable.Documentation |> ignore for (specialization, implementation) in headers.Specializations do Seq.iter (references.Namespaces.OnAttribute >> ignore) specialization.Attributes - references.Namespaces.OnDocumentation specialization.Documentation |> ignore references.Namespaces.OnSpecializationImplementation implementation |> ignore + references.Namespaces.OnDocumentation specialization.Documentation |> ignore for qsType in headers.Types do Seq.iter (references.Namespaces.OnAttribute >> ignore) qsType.Attributes references.Types.OnType qsType.Type |> ignore @@ -165,34 +156,41 @@ type LinkingTests (output:ITestOutputHelper) = /// Runs the nth internal renaming test, asserting that declarations with the given name and references to them have /// been renamed across the compilation unit. member private this.RunInternalRenamingTest num renamed notRenamed = + let dllSource = "InternalRenaming.dll" + let newNames = renamed |> Seq.map (dllSource |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) + let chunks = LinkingTests.ReadAndChunkSourceFile "InternalRenaming.qs" let compilation = this.BuildContent chunks.[num - 1] + let originalHeaders = new References.Headers(NonNullable.New dllSource, compilation.BuiltCompilation.Namespaces) - let beforeCount = - Seq.concat [renamed; notRenamed] - |> Seq.map (countReferencesInNamespaces compilation.BuiltCompilation.Namespaces) - |> Seq.sum - - let sourceName = "InternalRenaming.dll" - let headers = (NonNullable<_>.New sourceName, compilation.BuiltCompilation.Namespaces) |> References.Headers - let references = - [KeyValuePair.Create(NonNullable<_>.New sourceName, headers)] + let loadedReferences = + [KeyValuePair.Create(NonNullable<_>.New dllSource, originalHeaders)] |> ImmutableDictionary.CreateRange |> References - let oldAfterCount = - renamed - |> Seq.map (countReferencesInHeaders references.Declarations.[NonNullable<_>.New sourceName]) - |> Seq.sum - let newNames = renamed |> Seq.map (sourceName |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) - let newAfterCount = - Seq.concat [newNames; notRenamed] - |> Seq.map (countReferencesInHeaders references.Declarations.[NonNullable<_>.New sourceName]) + let HeadersFromReference (references : References) = + references.Declarations.Single().Value + + let CountReferencesFor itemsToCount headers = + itemsToCount + |> Seq.map (countReferencesInHeaders headers) |> Seq.sum + let beforeCount = + originalHeaders + |> CountReferencesFor (Seq.concat [renamed; notRenamed]) + + let afterCount = + loadedReferences |> HeadersFromReference + |> CountReferencesFor (Seq.concat [newNames; notRenamed]) + + let afterCountOriginalName = + loadedReferences |> HeadersFromReference + |> CountReferencesFor renamed + Assert.NotEqual (0, beforeCount) - Assert.Equal (0, oldAfterCount) - Assert.Equal (beforeCount, newAfterCount) + Assert.Equal (0, afterCountOriginalName) + Assert.Equal (beforeCount, afterCount) [] member this.``Monomorphization`` () = diff --git a/src/QsCompiler/Transformations/SearchAndReplace.cs b/src/QsCompiler/Transformations/SearchAndReplace.cs index cb17fdc264..1433390ea7 100644 --- a/src/QsCompiler/Transformations/SearchAndReplace.cs +++ b/src/QsCompiler/Transformations/SearchAndReplace.cs @@ -84,7 +84,7 @@ public override int GetHashCode() public class TransformationState { public Tuple, QsLocation> DeclarationLocation { get; internal set; } - public ImmutableList Locations { get; private set; } + public ImmutableHashSet Locations { get; private set; } /// /// Whenever DeclarationOffset is set, the current statement offset is set to this default value. @@ -101,7 +101,7 @@ internal TransformationState(Func trackId, { this.TrackIdentifier = trackId ?? throw new ArgumentNullException(nameof(trackId)); this.RelevantSourseFiles = limitToSourceFiles; - this.Locations = ImmutableList.Empty; + this.Locations = ImmutableHashSet.Empty; this.DefaultOffset = defaultOffset; } @@ -168,7 +168,7 @@ public IdentifierReferences(QsQualifiedName idName, QsLocation defaultOffset, II // static methods for convenience - public static IEnumerable Find(NonNullable idName, QsScope scope, + public static ImmutableHashSet Find(NonNullable idName, QsScope scope, NonNullable sourceFile, Tuple rootLoc) { var finder = new IdentifierReferences(idName, null, ImmutableHashSet.Create(sourceFile)); @@ -178,7 +178,7 @@ public static IEnumerable Find(NonNullable idName, QsScope sco return finder.SharedState.Locations; } - public static IEnumerable Find(QsQualifiedName idName, QsNamespace ns, QsLocation defaultOffset, + public static ImmutableHashSet Find(QsQualifiedName idName, QsNamespace ns, QsLocation defaultOffset, out Tuple, QsLocation> declarationLocation, IImmutableSet> limitToSourceFiles = null) { var finder = new IdentifierReferences(idName, defaultOffset, limitToSourceFiles); @@ -509,24 +509,6 @@ public SpecializationDeclarationHeader OnSpecializationDeclarationHeader( documentation: Namespaces.OnDocumentation(specialization.Documentation)); } - /// - /// Renames references in the specialization implementation. - /// - /// The specialization implementation in which to rename references. - /// The specialization implementation with renamed references. - public SpecializationImplementation OnSpecializationImplementation(SpecializationImplementation implementation) - { - if (implementation is SpecializationImplementation.Provided provided) - { - return SpecializationImplementation.NewProvided(Namespaces.OnArgumentTuple(provided.Item1), - Statements.OnScope(provided.Item2)); - } - else - { - return implementation; - } - } - /// /// Renames references in the type declaration header, including the name of the type itself. /// @@ -555,20 +537,30 @@ public TypeDeclarationHeader OnTypeDeclarationHeader(TypeDeclarationHeader type) /// private QsQualifiedName GetNewName(QsQualifiedName name) => names.GetValueOrDefault(name) ?? name; + /// + /// Gets the renamed version of the user defined type if one exists; otherwise, returns the original one. + /// + /// + /// The renamed version of the user defined type if one exists; otherwise, returns the original one. + /// + private UserDefinedType RenameUdt(UserDefinedType udt) + { + var newName = GetNewName(new QsQualifiedName(udt.Namespace, udt.Name)); + return new UserDefinedType(newName.Namespace, newName.Name, udt.Range); + } + + private class TypeTransformation : Core.TypeTransformation { private readonly RenameReferences parent; public TypeTransformation(RenameReferences parent) : base(parent) => this.parent = parent; - public override QsTypeKind OnUserDefinedType(UserDefinedType udt) - { - var newName = parent.GetNewName(new QsQualifiedName(udt.Namespace, udt.Name)); - return base.OnUserDefinedType(new UserDefinedType(newName.Namespace, newName.Name, udt.Range)); - } + public override QsTypeKind OnUserDefinedType(UserDefinedType udt) => + QsTypeKind.NewUserDefinedType(parent.RenameUdt(udt)); public override QsTypeKind OnTypeParameter(QsTypeParameter tp) => - base.OnTypeParameter(new QsTypeParameter(parent.GetNewName(tp.Origin), tp.TypeName, tp.Range)); + QsTypeKind.NewTypeParameter(new QsTypeParameter(parent.GetNewName(tp.Origin), tp.TypeName, tp.Range)); } private class ExpressionKindTransformation : Core.ExpressionKindTransformation @@ -577,8 +569,7 @@ private class ExpressionKindTransformation : Core.ExpressionKindTransformation public ExpressionKindTransformation(RenameReferences parent) : base(parent) => this.parent = parent; - public override QsExpressionKind OnIdentifier(Identifier id, - QsNullable> typeArgs) + public override QsExpressionKind OnIdentifier(Identifier id, QsNullable> typeArgs) { if (id is Identifier.GlobalCallable global) { @@ -594,35 +585,23 @@ private class NamespaceTransformation : Core.NamespaceTransformation public NamespaceTransformation(RenameReferences parent) : base(parent) => this.parent = parent; + public override QsDeclarationAttribute OnAttribute(QsDeclarationAttribute att) + { + var argument = parent.Expressions.OnTypedExpression(att.Argument); + var tId = att.TypeId.IsValue + ? QsNullable.NewValue(parent.RenameUdt(att.TypeId.Item)) + : att.TypeId; + return new QsDeclarationAttribute(tId, argument, att.Offset, att.Comments); + } + public override QsCallable OnCallableDeclaration(QsCallable callable) => base.OnCallableDeclaration(callable.WithFullName(parent.GetNewName)); public override QsCustomType OnTypeDeclaration(QsCustomType type) => - base.OnTypeDeclaration(new QsCustomType( - fullName: parent.GetNewName(type.FullName), - attributes: type.Attributes, - modifiers: type.Modifiers, - sourceFile: type.SourceFile, - location: type.Location, - type: type.Type, - typeItems: type.TypeItems, - documentation: type.Documentation, - comments: type.Comments)); - - public override QsDeclarationAttribute OnAttribute(QsDeclarationAttribute attribute) - { - var newTypeId = QsNullable.Null; - if (attribute.TypeId.IsValue) - { - var newName = parent.GetNewName(new QsQualifiedName(attribute.TypeId.Item.Namespace, - attribute.TypeId.Item.Name)); - newTypeId = QsNullable.NewValue( - new UserDefinedType(newName.Namespace, newName.Name, attribute.TypeId.Item.Range)); - } - var newArgument = parent.Expressions.OnTypedExpression(attribute.Argument); - return base.OnAttribute( - new QsDeclarationAttribute(newTypeId, newArgument, attribute.Offset, attribute.Comments)); - } + base.OnTypeDeclaration(type.WithFullName(parent.GetNewName)); + + public override QsSpecialization OnSpecializationDeclaration(QsSpecialization spec) => + base.OnSpecializationDeclaration(spec.WithParent(parent.GetNewName)); } } From 7226cb9ac3c528669c70417fc2ebb39bfa7f5b14 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 09:56:18 -0700 Subject: [PATCH 13/22] Include type constructors in count --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 2518ae63e9..4b1963db9a 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -58,8 +58,7 @@ type LinkingTests (output:ITestOutputHelper) = references.Namespaces.OnDocumentation qsType.Documentation |> ignore let count = - // TODO: We ignore type constructors because countReferencesInNamespaces is not able to count them. - headers.Callables.Count(fun callable -> callable.QualifiedName = name && callable.Kind <> TypeConstructor) + + headers.Callables.Count(fun callable -> callable.QualifiedName = name) + headers.Types.Count(fun qsType -> qsType.QualifiedName = name) + references.SharedState.Locations.Count count From dc2876f9e8b5a63f285182e3a3426933234ae44d Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 10:42:58 -0700 Subject: [PATCH 14/22] Small code cleanup --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 38 ++++++++----------- .../Transformations/SearchAndReplace.cs | 19 +++++----- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 4b1963db9a..b7eb16e40a 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -155,37 +155,29 @@ type LinkingTests (output:ITestOutputHelper) = /// Runs the nth internal renaming test, asserting that declarations with the given name and references to them have /// been renamed across the compilation unit. member private this.RunInternalRenamingTest num renamed notRenamed = - let dllSource = "InternalRenaming.dll" - let newNames = renamed |> Seq.map (dllSource |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) + let countAll names headers = + names + |> Seq.map (countReferencesInHeaders headers) + |> Seq.sum let chunks = LinkingTests.ReadAndChunkSourceFile "InternalRenaming.qs" let compilation = this.BuildContent chunks.[num - 1] - let originalHeaders = new References.Headers(NonNullable.New dllSource, compilation.BuiltCompilation.Namespaces) + let dllSource = "InternalRenaming.dll" + let originalHeaders = + References.Headers (NonNullable.New dllSource, compilation.BuiltCompilation.Namespaces) + + let beforeCount = originalHeaders |> countAll (Seq.concat [renamed; notRenamed]) - let loadedReferences = + let references = [KeyValuePair.Create(NonNullable<_>.New dllSource, originalHeaders)] |> ImmutableDictionary.CreateRange |> References + let newNames = + renamed + |> Seq.map (dllSource |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) + let afterCount = references.Declarations.Single().Value |> countAll (Seq.concat [newNames; notRenamed]) - let HeadersFromReference (references : References) = - references.Declarations.Single().Value - - let CountReferencesFor itemsToCount headers = - itemsToCount - |> Seq.map (countReferencesInHeaders headers) - |> Seq.sum - - let beforeCount = - originalHeaders - |> CountReferencesFor (Seq.concat [renamed; notRenamed]) - - let afterCount = - loadedReferences |> HeadersFromReference - |> CountReferencesFor (Seq.concat [newNames; notRenamed]) - - let afterCountOriginalName = - loadedReferences |> HeadersFromReference - |> CountReferencesFor renamed + let afterCountOriginalName = references.Declarations.Single().Value |> countAll renamed Assert.NotEqual (0, beforeCount) Assert.Equal (0, afterCountOriginalName) diff --git a/src/QsCompiler/Transformations/SearchAndReplace.cs b/src/QsCompiler/Transformations/SearchAndReplace.cs index 1433390ea7..7ab0324015 100644 --- a/src/QsCompiler/Transformations/SearchAndReplace.cs +++ b/src/QsCompiler/Transformations/SearchAndReplace.cs @@ -557,10 +557,10 @@ private class TypeTransformation : Core.TypeTransformation public TypeTransformation(RenameReferences parent) : base(parent) => this.parent = parent; public override QsTypeKind OnUserDefinedType(UserDefinedType udt) => - QsTypeKind.NewUserDefinedType(parent.RenameUdt(udt)); + base.OnUserDefinedType(parent.RenameUdt(udt)); public override QsTypeKind OnTypeParameter(QsTypeParameter tp) => - QsTypeKind.NewTypeParameter(new QsTypeParameter(parent.GetNewName(tp.Origin), tp.TypeName, tp.Range)); + base.OnTypeParameter(new QsTypeParameter(parent.GetNewName(tp.Origin), tp.TypeName, tp.Range)); } private class ExpressionKindTransformation : Core.ExpressionKindTransformation @@ -585,13 +585,14 @@ private class NamespaceTransformation : Core.NamespaceTransformation public NamespaceTransformation(RenameReferences parent) : base(parent) => this.parent = parent; - public override QsDeclarationAttribute OnAttribute(QsDeclarationAttribute att) + public override QsDeclarationAttribute OnAttribute(QsDeclarationAttribute attribute) { - var argument = parent.Expressions.OnTypedExpression(att.Argument); - var tId = att.TypeId.IsValue - ? QsNullable.NewValue(parent.RenameUdt(att.TypeId.Item)) - : att.TypeId; - return new QsDeclarationAttribute(tId, argument, att.Offset, att.Comments); + var argument = parent.Expressions.OnTypedExpression(attribute.Argument); + var typeId = attribute.TypeId.IsValue + ? QsNullable.NewValue(parent.RenameUdt(attribute.TypeId.Item)) + : attribute.TypeId; + return base.OnAttribute( + new QsDeclarationAttribute(typeId, argument, attribute.Offset, attribute.Comments)); } public override QsCallable OnCallableDeclaration(QsCallable callable) => @@ -600,7 +601,7 @@ public override QsCallable OnCallableDeclaration(QsCallable callable) => public override QsCustomType OnTypeDeclaration(QsCustomType type) => base.OnTypeDeclaration(type.WithFullName(parent.GetNewName)); - public override QsSpecialization OnSpecializationDeclaration(QsSpecialization spec) => + public override QsSpecialization OnSpecializationDeclaration(QsSpecialization spec) => base.OnSpecializationDeclaration(spec.WithParent(parent.GetNewName)); } } From 167d9352477dffff09c86c6ea43f581645ea67fd Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 10:50:08 -0700 Subject: [PATCH 15/22] Add comment about ".qs" extension required in tests --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index b7eb16e40a..3e79fce08e 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -28,7 +28,11 @@ type LinkingTests (output:ITestOutputHelper) = let compilationManager = new CompilationUnitManager(new Action (fun ex -> failwith ex.Message)) - let getTempFile () = new Uri(Path.GetFullPath(Path.GetRandomFileName() + ".qs")) + let getTempFile () = + // The file name needs to end in ".qs" so that it isn't ignored by the References.Headers class during the + // internal renaming tests. + new Uri(Path.GetFullPath(Path.GetRandomFileName() + ".qs")) + let getManager uri content = CompilationUnitManager.InitializeFileManager(uri, content, compilationManager.PublishDiagnostics, compilationManager.LogException) let defaultOffset = { From f337e4e042f4caea6671af822ca0eb38feb16bcb Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 12:48:45 -0700 Subject: [PATCH 16/22] Rename internals such that the name is always unique --- .../CompilationManager/CompilationUnit.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index 254cba519b..b53883759c 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -114,9 +114,22 @@ private static Headers RenameInternals(string source, Headers headers) /// internal static QsQualifiedName GetNewNameForInternal(string source, QsQualifiedName name) { - // TODO: This isn't necessarily unique. - var prefix = Regex.Replace(source, @"[^A-Za-z0-9_]", "_"); - return new QsQualifiedName(name.Namespace, NonNullable.New($"__{prefix}_{name.Name.Value}__")); + // Returns true if the character c is valid as part of an identifier. "_" is excluded so it can be used as + // an escape character. + static bool IsValidCharacter(char c) => + 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9'; + + // Converts the string s to a string where all invalid characters are escaped by "_X", where "X" is the + // hexadecimal representation of the character. + static string ToEscapedIdentifier(string s) => + string.Join( + "", + s.Select(c => IsValidCharacter(c) ? c.ToString() : "_" + Convert.ToByte(c).ToString("X"))); + + var prefix = ToEscapedIdentifier(source); + // The name is already a valid identifier, but we also want to escape "_". + var escapedName = ToEscapedIdentifier(name.Name.Value); + return new QsQualifiedName(name.Namespace, NonNullable.New($"__{prefix}_{escapedName}__")); } /// From 9ff87866596615cfbe37e18ff048d43495b24ca9 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 13:08:44 -0700 Subject: [PATCH 17/22] Add TODO about alternative to name mangling --- src/QsCompiler/CompilationManager/CompilationUnit.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index b53883759c..bc8df9124e 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -173,6 +173,10 @@ internal References Remove(NonNullable source, Action public References(ImmutableDictionary, Headers> refs, Action onError = null) { + // TODO: We mangle the names of internal declarations in references to avoid name conflicts in the symbol + // table. However, it might be better to instead change the symbol table so it can support duplicate names + // as long as they are not in overlapping scopes, which is the case with internal declarations in separate + // assemblies. this.Declarations = (refs ?? throw new ArgumentNullException(nameof(refs))) .Select(reference => (reference.Key, RenameInternals(reference.Key.Value, reference.Value))) From 0997c6b2fdb81873b431aecc457765bed286759c Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 13:32:53 -0700 Subject: [PATCH 18/22] Use simpler name mangling --- .../CompilationManager/CompilationUnit.cs | 39 ++++++------------- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 3 +- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index bc8df9124e..33fc2674f1 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -78,13 +78,14 @@ private static IEnumerable TypeHeaders(IEnumerable<(strin .Select(TypeDeclarationHeader.FromJson).Select(built => built.Item2); /// - /// Renames all private and internal declarations in the headers to have names that are based on the path to the + /// Renames all private and internal declarations in the headers to have names that are based on the ID of the /// referenced assembly. /// + /// A number uniquely identifying the referenced assembly that contains the headers. /// The path to the assembly that is the source of the given headers. /// The declaration headers in the assembly. /// - private static Headers RenameInternals(string source, Headers headers) + private static Headers RenameInternals(int id, string source, Headers headers) { static bool IsInternal(AccessModifier access) => access.IsInternal || access.IsPrivate; @@ -94,7 +95,7 @@ private static Headers RenameInternals(string source, Headers headers) .Concat(headers.Types .Where(type => IsInternal(type.Modifiers.Access)) .Select(type => type.QualifiedName)) - .ToImmutableDictionary(name => name, name => GetNewNameForInternal(source, name)); + .ToImmutableDictionary(name => name, name => GetNewNameForInternal(id, name)); var rename = new RenameReferences(internalNames); var callables = headers.Callables.Select(rename.OnCallableDeclarationHeader); var specializations = headers.Specializations.Select( @@ -105,32 +106,13 @@ private static Headers RenameInternals(string source, Headers headers) } /// - /// Returns a new name for an internal declaration that is uniquely tagged with its source assembly path. + /// Returns a new name for an internal declaration that is tagged with its reference ID. /// - /// The path to the reference assembly in which the internal name is declared. + /// The ID of the reference in which this name was declared. /// The name of the internal declaration. - /// - /// A new name for an internal declaration that is uniquely tagged with its source assembly path. - /// - internal static QsQualifiedName GetNewNameForInternal(string source, QsQualifiedName name) - { - // Returns true if the character c is valid as part of an identifier. "_" is excluded so it can be used as - // an escape character. - static bool IsValidCharacter(char c) => - 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9'; - - // Converts the string s to a string where all invalid characters are escaped by "_X", where "X" is the - // hexadecimal representation of the character. - static string ToEscapedIdentifier(string s) => - string.Join( - "", - s.Select(c => IsValidCharacter(c) ? c.ToString() : "_" + Convert.ToByte(c).ToString("X"))); - - var prefix = ToEscapedIdentifier(source); - // The name is already a valid identifier, but we also want to escape "_". - var escapedName = ToEscapedIdentifier(name.Name.Value); - return new QsQualifiedName(name.Namespace, NonNullable.New($"__{prefix}_{escapedName}__")); - } + /// A new name for an internal declaration that is tagged with its reference ID. + internal static QsQualifiedName GetNewNameForInternal(int id, QsQualifiedName name) => + new QsQualifiedName(name.Namespace, NonNullable.New($"__Reference{id}_{name.Name.Value}__")); /// /// Dictionary that maps the id of a referenced assembly (given by its location on disk) to the headers defined in that assembly. @@ -179,7 +161,8 @@ public References(ImmutableDictionary, Headers> refs, Action // assemblies. this.Declarations = (refs ?? throw new ArgumentNullException(nameof(refs))) - .Select(reference => (reference.Key, RenameInternals(reference.Key.Value, reference.Value))) + .Select((reference, index) => (reference.Key, + RenameInternals(index, reference.Key.Value, reference.Value))) .ToImmutableDictionary(reference => reference.Key, reference => reference.Item2); if (onError == null) return; diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 3e79fce08e..163711f6a5 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -177,8 +177,7 @@ type LinkingTests (output:ITestOutputHelper) = |> ImmutableDictionary.CreateRange |> References let newNames = - renamed - |> Seq.map (dllSource |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) + renamed |> Seq.map (0 |> FuncConvert.FuncFromTupled References.GetNewNameForInternal) let afterCount = references.Declarations.Single().Value |> countAll (Seq.concat [newNames; notRenamed]) let afterCountOriginalName = references.Declarations.Single().Value |> countAll renamed From 345a4169ec463f70e70a8b71e1683eb2ae3a2b4a Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 9 Mar 2020 16:57:03 -0700 Subject: [PATCH 19/22] Use lambda instead of let --- src/QsCompiler/Core/TypeTransformation.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/QsCompiler/Core/TypeTransformation.fs b/src/QsCompiler/Core/TypeTransformation.fs index 5b619f7087..cc58d49419 100644 --- a/src/QsCompiler/Core/TypeTransformation.fs +++ b/src/QsCompiler/Core/TypeTransformation.fs @@ -132,5 +132,4 @@ type TypeTransformationBase(options : TransformationOptions) = | ExpressionType.Result -> this.OnResult () | ExpressionType.Pauli -> this.OnPauli () | ExpressionType.Range -> this.OnRange () - let ResolvedType t = ResolvedType.New (true, t) - ResolvedType |> Node.BuildOr t transformed + (fun t -> ResolvedType.New (true, t)) |> Node.BuildOr t transformed From 45a65ff3da64646a0645213af1a6d17328f42f14 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 11 Mar 2020 09:19:49 -0700 Subject: [PATCH 20/22] Add test for renaming internal specializations --- src/QsCompiler/Tests.Compiler/LinkingTests.fs | 7 +++++++ .../TestCases/LinkingTests/InternalRenaming.qs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 163711f6a5..257ee6e47c 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -63,6 +63,7 @@ type LinkingTests (output:ITestOutputHelper) = let count = headers.Callables.Count(fun callable -> callable.QualifiedName = name) + + headers.Specializations.Count(fun specialization -> (fst (specialization.ToTuple ())).Parent = name) + headers.Types.Count(fun qsType -> qsType.QualifiedName = name) + references.SharedState.Locations.Count count @@ -368,3 +369,9 @@ type LinkingTests (output:ITestOutputHelper) = this.RunInternalRenamingTest 6 [qualifiedName Signatures.InternalRenamingNs "Foo"] [qualifiedName Signatures.InternalRenamingNs "Bar"] + + [] + member this.``Rename specializations for internal operations`` () = + this.RunInternalRenamingTest 7 + [qualifiedName Signatures.InternalRenamingNs "Foo"] + [qualifiedName Signatures.InternalRenamingNs "Bar"] diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs index 5a344e4fbe..5f95efb10a 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -94,3 +94,21 @@ namespace Microsoft.Quantum.Testing.InternalRenaming { function Bar () : Unit { } } + +// ================================= +// Test 7: Rename specializations for internal operations + +namespace Microsoft.Quantum.Testing.InternalRenaming { + internal operation Foo () : Unit is Adj { + body { + } + + adjoint { + } + } + + operation Bar () : Unit { + Foo(); + Adjoint Foo(); + } +} From 2f2e7b3f270a3eb240f9ce7fdfc8c89d6f59e5f9 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 11 Mar 2020 09:23:02 -0700 Subject: [PATCH 21/22] Replace tabs with spaces... --- .../TestCases/LinkingTests/InternalRenaming.qs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs index 5f95efb10a..3f67ca815a 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/InternalRenaming.qs @@ -101,14 +101,14 @@ namespace Microsoft.Quantum.Testing.InternalRenaming { namespace Microsoft.Quantum.Testing.InternalRenaming { internal operation Foo () : Unit is Adj { body { - } + } adjoint { - } - } + } + } operation Bar () : Unit { Foo(); Adjoint Foo(); - } + } } From 25514593abf2b314954532755ede89ca2c8d63dd Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 11 Mar 2020 11:27:17 -0700 Subject: [PATCH 22/22] Use a private state class in RenameReferences --- .../Transformations/SearchAndReplace.cs | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/QsCompiler/Transformations/SearchAndReplace.cs b/src/QsCompiler/Transformations/SearchAndReplace.cs index 7ab0324015..82f3ead34f 100644 --- a/src/QsCompiler/Transformations/SearchAndReplace.cs +++ b/src/QsCompiler/Transformations/SearchAndReplace.cs @@ -451,7 +451,7 @@ public override QsExpressionKind OnIdentifier(Identifier sym, QsNullable public class RenameReferences : SyntaxTreeTransformation { - private readonly IImmutableDictionary names; + private readonly TransformationState state; /// /// Creates a new rename references transformation. @@ -459,7 +459,7 @@ public class RenameReferences : SyntaxTreeTransformation /// The mapping from existing names to new names. public RenameReferences(IImmutableDictionary names) { - this.names = names; + state = new TransformationState(names); Types = new TypeTransformation(this); ExpressionKinds = new ExpressionKindTransformation(this); Namespaces = new NamespaceTransformation(this); @@ -473,7 +473,7 @@ public RenameReferences(IImmutableDictionary n public CallableDeclarationHeader OnCallableDeclarationHeader(CallableDeclarationHeader callable) => new CallableDeclarationHeader( kind: callable.Kind, - qualifiedName: GetNewName(callable.QualifiedName), + qualifiedName: state.GetNewName(callable.QualifiedName), attributes: callable.Attributes.Select(Namespaces.OnAttribute).ToImmutableArray(), modifiers: callable.Modifiers, sourceFile: callable.SourceFile, @@ -501,7 +501,7 @@ public SpecializationDeclarationHeader OnSpecializationDeclarationHeader( kind: specialization.Kind, typeArguments: typeArguments, information: specialization.Information, - parent: GetNewName(specialization.Parent), + parent: state.GetNewName(specialization.Parent), attributes: specialization.Attributes.Select(Namespaces.OnAttribute).ToImmutableArray(), sourceFile: specialization.SourceFile, position: specialization.Position, @@ -517,7 +517,7 @@ public SpecializationDeclarationHeader OnSpecializationDeclarationHeader( public TypeDeclarationHeader OnTypeDeclarationHeader(TypeDeclarationHeader type) { return new TypeDeclarationHeader( - qualifiedName: GetNewName(type.QualifiedName), + qualifiedName: state.GetNewName(type.QualifiedName), attributes: type.Attributes.Select(Namespaces.OnAttribute).ToImmutableArray(), modifiers: type.Modifiers, sourceFile: type.SourceFile, @@ -528,52 +528,59 @@ public TypeDeclarationHeader OnTypeDeclarationHeader(TypeDeclarationHeader type) documentation: Namespaces.OnDocumentation(type.Documentation)); } - /// - /// Gets the renamed version of the qualified name if one exists; otherwise, returns the original name. - /// - /// The qualified name to rename. - /// - /// The renamed version of the qualified name if one exists; otherwise, returns the original name. - /// - private QsQualifiedName GetNewName(QsQualifiedName name) => names.GetValueOrDefault(name) ?? name; - - /// - /// Gets the renamed version of the user defined type if one exists; otherwise, returns the original one. - /// - /// - /// The renamed version of the user defined type if one exists; otherwise, returns the original one. - /// - private UserDefinedType RenameUdt(UserDefinedType udt) + private class TransformationState { - var newName = GetNewName(new QsQualifiedName(udt.Namespace, udt.Name)); - return new UserDefinedType(newName.Namespace, newName.Name, udt.Range); - } + private readonly IImmutableDictionary names; + internal TransformationState(IImmutableDictionary names) => + this.names = names; + + /// + /// Gets the renamed version of the qualified name if one exists; otherwise, returns the original name. + /// + /// The qualified name to rename. + /// + /// The renamed version of the qualified name if one exists; otherwise, returns the original name. + /// + internal QsQualifiedName GetNewName(QsQualifiedName name) => names.GetValueOrDefault(name) ?? name; + + /// + /// Gets the renamed version of the user-defined type if one exists; otherwise, returns the original one. + /// + /// + /// The renamed version of the user-defined type if one exists; otherwise, returns the original one. + /// + internal UserDefinedType RenameUdt(UserDefinedType udt) + { + var newName = GetNewName(new QsQualifiedName(udt.Namespace, udt.Name)); + return new UserDefinedType(newName.Namespace, newName.Name, udt.Range); + } + } private class TypeTransformation : Core.TypeTransformation { - private readonly RenameReferences parent; + private readonly TransformationState state; - public TypeTransformation(RenameReferences parent) : base(parent) => this.parent = parent; + public TypeTransformation(RenameReferences parent) : base(parent) => state = parent.state; public override QsTypeKind OnUserDefinedType(UserDefinedType udt) => - base.OnUserDefinedType(parent.RenameUdt(udt)); + base.OnUserDefinedType(state.RenameUdt(udt)); public override QsTypeKind OnTypeParameter(QsTypeParameter tp) => - base.OnTypeParameter(new QsTypeParameter(parent.GetNewName(tp.Origin), tp.TypeName, tp.Range)); + base.OnTypeParameter(new QsTypeParameter(state.GetNewName(tp.Origin), tp.TypeName, tp.Range)); } private class ExpressionKindTransformation : Core.ExpressionKindTransformation { - private readonly RenameReferences parent; + private readonly TransformationState state; - public ExpressionKindTransformation(RenameReferences parent) : base(parent) => this.parent = parent; + public ExpressionKindTransformation(RenameReferences parent) : base(parent) => state = parent.state; public override QsExpressionKind OnIdentifier(Identifier id, QsNullable> typeArgs) { if (id is Identifier.GlobalCallable global) { - id = Identifier.NewGlobalCallable(parent.GetNewName(global.Item)); + id = Identifier.NewGlobalCallable(state.GetNewName(global.Item)); } return base.OnIdentifier(id, typeArgs); } @@ -581,28 +588,28 @@ public override QsExpressionKind OnIdentifier(Identifier id, QsNullable this.parent = parent; + public NamespaceTransformation(RenameReferences parent) : base(parent) => state = parent.state; public override QsDeclarationAttribute OnAttribute(QsDeclarationAttribute attribute) { - var argument = parent.Expressions.OnTypedExpression(attribute.Argument); + var argument = Transformation.Expressions.OnTypedExpression(attribute.Argument); var typeId = attribute.TypeId.IsValue - ? QsNullable.NewValue(parent.RenameUdt(attribute.TypeId.Item)) + ? QsNullable.NewValue(state.RenameUdt(attribute.TypeId.Item)) : attribute.TypeId; return base.OnAttribute( new QsDeclarationAttribute(typeId, argument, attribute.Offset, attribute.Comments)); } public override QsCallable OnCallableDeclaration(QsCallable callable) => - base.OnCallableDeclaration(callable.WithFullName(parent.GetNewName)); + base.OnCallableDeclaration(callable.WithFullName(state.GetNewName)); public override QsCustomType OnTypeDeclaration(QsCustomType type) => - base.OnTypeDeclaration(type.WithFullName(parent.GetNewName)); + base.OnTypeDeclaration(type.WithFullName(state.GetNewName)); public override QsSpecialization OnSpecializationDeclaration(QsSpecialization spec) => - base.OnSpecializationDeclaration(spec.WithParent(parent.GetNewName)); + base.OnSpecializationDeclaration(spec.WithParent(state.GetNewName)); } }