diff --git a/build/Targets/Packages.props b/build/Targets/Packages.props index 3350acfec27b..877de7a25362 100644 --- a/build/Targets/Packages.props +++ b/build/Targets/Packages.props @@ -221,6 +221,7 @@ 12.0.4 8.0.0.0-alpha 2.2.0-beta4-build3444 + 2.2.0-beta4-build3444 1.0.2-prerelease-00104 2.2.0-beta4-build3444 2.2.0-beta4-build1194 diff --git a/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj b/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj index 92f79c80837b..e4d06c7c65ba 100644 --- a/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj +++ b/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj @@ -146,14 +146,13 @@ - + - diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs index 75a50e471aa8..a8f09509a607 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { public static class LocalFunctionTestsUtil { - public static IMethodSymbol FindLocalFunction(this CommonTestBase.CompilationVerifier verifier, string localFunctionName) + public static IMethodSymbol FindLocalFunction(this CompilationVerifier verifier, string localFunctionName) { localFunctionName = (char)GeneratedNameKind.LocalFunction + "__" + localFunctionName; var methods = verifier.TestData.GetMethodsByName(); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs index 146fddc1aa86..284bf20c025c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs @@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -703,14 +704,6 @@ public static IEnumerable Power(int number, int exponent) CompileAndVerify(text, expectedOutput: expectedOutput); } - // When ReflectionEmit supports writing exception handler info, this method - // can be removed and CompileAndVerify references above will resolve to - // the overload that emits with both CCI and ReflectionEmit. (Bug #7012) - private CompilationVerifier CompileAndVerify(string source, string expectedOutput = null) - { - return base.CompileAndVerify(source: source, expectedOutput: expectedOutput); - } - [WorkItem(540719, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540719")] [Fact] public void LabelBetweenLocalAndInitialize() diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadata.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Emit/EmitMetadata.cs rename to src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs diff --git a/src/Compilers/CSharp/Test/Emit/Emit/OutputStreams.cs b/src/Compilers/CSharp/Test/Emit/Emit/OutputStreams.cs deleted file mode 100644 index 674fd11abe81..000000000000 --- a/src/Compilers/CSharp/Test/Emit/Emit/OutputStreams.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit -{ - internal class NameResolver - { - public string GetDebugInformationFileName(SyntaxTree syntaxTree) - { - throw new NotImplementedException(); - } - - public Stream GetXmlInclude(SyntaxTree syntaxTree, string xmlIncludeFile) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs index da40616e9f66..1b563f9ad1b5 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs @@ -2214,7 +2214,7 @@ class C var emitResult1 = c.Emit(peStream: peStream1, pdbStream: pdbStream); var emitResult2 = c.Emit(peStream: peStream2); - PdbValidation.VerifyMetadataEqualModuloMvid(peStream1, peStream2); + MetadataValidation.VerifyMetadataEqualModuloMvid(peStream1, peStream2); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs index e729fb670468..47674b58aca6 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs @@ -483,7 +483,7 @@ static System.Action F() Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "value__").WithArguments("A.value__")); // PEVerify should not report "Field value__ ... is not marked RTSpecialName". - var verifier = new CompilationVerifier(this, compilation); + var verifier = new CompilationVerifier(compilation); verifier.EmitAndVerify( "Error: Field name value__ is reserved for Enums only.", "Error: Field name value__ is reserved for Enums only.", diff --git a/src/Compilers/CSharp/Test/WinRT/WinRTUtil.cs b/src/Compilers/CSharp/Test/WinRT/WinRTUtil.cs index 9fa0ac76ee32..27b1e5e0cddf 100644 --- a/src/Compilers/CSharp/Test/WinRT/WinRTUtil.cs +++ b/src/Compilers/CSharp/Test/WinRT/WinRTUtil.cs @@ -1,11 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; -using static Microsoft.CodeAnalysis.Test.Utilities.CommonTestBase; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { diff --git a/src/Compilers/Core/Portable/CodeAnalysis.csproj b/src/Compilers/Core/Portable/CodeAnalysis.csproj index 2079bd97be21..ab58e2793433 100644 --- a/src/Compilers/Core/Portable/CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/CodeAnalysis.csproj @@ -899,6 +899,7 @@ + diff --git a/src/Compilers/Test/Utilities/CSharp/BasicCompilationUtils.cs b/src/Compilers/Test/Utilities/CSharp/BasicCompilationUtils.cs index faa5e71bbc9b..8bce514d5e18 100644 --- a/src/Compilers/Test/Utilities/CSharp/BasicCompilationUtils.cs +++ b/src/Compilers/Test/Utilities/CSharp/BasicCompilationUtils.cs @@ -53,11 +53,6 @@ protected override Compilation GetCompilationForEmit(IEnumerable source, throw new NotImplementedException(); } - internal override IEnumerable ReferencesToModuleSymbols(IEnumerable references, MetadataImportOptions importOptions = MetadataImportOptions.Public) - { - throw new NotImplementedException(); - } - internal override string VisualizeRealIL(IModuleSymbol peModule, CodeAnalysis.CodeGen.CompilationTestData.MethodData methodData, IReadOnlyDictionary markers) { throw new NotImplementedException(); diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 917788c4d65b..114f877c44bb 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -38,11 +38,6 @@ protected CSharpCompilation GetCSharpCompilationForEmit( return (CSharpCompilation)base.GetCompilationForEmit(source, additionalRefs, options, parseOptions); } - internal new IEnumerable ReferencesToModuleSymbols(IEnumerable references, MetadataImportOptions importOptions = MetadataImportOptions.Public) - { - return base.ReferencesToModuleSymbols(references, importOptions).Cast(); - } - private Action Translate2(Action action) { if (action != null) @@ -219,24 +214,6 @@ public static CSharpCompilation CreateWinRtCompilation(string text, MetadataRefe TestOptions.ReleaseExe); } - internal override IEnumerable ReferencesToModuleSymbols(IEnumerable references, MetadataImportOptions importOptions = MetadataImportOptions.Public) - { - var options = TestOptions.ReleaseDll.WithMetadataImportOptions(importOptions); - var tc1 = CSharpCompilation.Create("Dummy", new SyntaxTree[0], references, options); - return references.Select(r => - { - if (r.Properties.Kind == MetadataImageKind.Assembly) - { - var assemblySymbol = tc1.GetReferencedAssemblySymbol(r); - return (object)assemblySymbol == null ? null : assemblySymbol.Modules[0]; - } - else - { - return tc1.GetReferencedModuleSymbol(r); - } - }); - } - protected override CompilationOptions CompilationOptionsReleaseDll { get { return TestOptions.ReleaseDll; } diff --git a/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb b/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb index 1f2063c4ad3b..795ccfcfe58b 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb @@ -414,20 +414,6 @@ End Class Public MustInherit Class BasicTestBaseBase Inherits CommonTestBase - Friend Overrides Function ReferencesToModuleSymbols(references As IEnumerable(Of MetadataReference), Optional importOptions As MetadataImportOptions = MetadataImportOptions.Public) As IEnumerable(Of IModuleSymbol) - Dim options = DirectCast(CompilationOptionsReleaseDll, VisualBasicCompilationOptions).WithMetadataImportOptions(importOptions) - Dim tc1 = VisualBasicCompilation.Create("Dummy", references:=references, options:=options) - Return references.Select( - Function(r) - If r.Properties.Kind = MetadataImageKind.Assembly Then - Dim assemblySymbol = tc1.GetReferencedAssemblySymbol(r) - Return If(assemblySymbol Is Nothing, Nothing, assemblySymbol.Modules(0)) - Else - Return tc1.GetReferencedModuleSymbol(r) - End If - End Function) - End Function - Protected Overrides ReadOnly Property CompilationOptionsReleaseDll As CompilationOptions Get Return TestOptions.ReleaseDll diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb index e668b3c36529..ea2f5e213e2f 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb @@ -2,6 +2,7 @@ Imports System.IO Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.PDB Public Class PDBNamespaceScopes @@ -383,7 +384,7 @@ End Class Dim emitResult1 = c.Emit(peStream:=peStream1, pdbStream:=pdbStream) Dim emitResult2 = c.Emit(peStream:=peStream2) - PdbValidation.VerifyMetadataEqualModuloMvid(peStream1, peStream2) + MetadataValidation.VerifyMetadataEqualModuloMvid(peStream1, peStream2) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBSyncLockTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBSyncLockTests.vb index 8247d7bba772..f4931e5c1150 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBSyncLockTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBSyncLockTests.vb @@ -1,4 +1,5 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +Imports Microsoft.CodeAnalysis.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.PDB diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/FieldTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/FieldTests.vb index d445b591d980..436de03b2743 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/FieldTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/FieldTests.vb @@ -491,7 +491,7 @@ End Module compilation.AssertNoErrors() ' PEVerify should not report "Field value__ ... is not marked RTSpecialName". - Dim verifier = New CompilationVerifier(Me, compilation) + Dim verifier = New CompilationVerifier(compilation) verifier.EmitAndVerify( "Error: Field name value__ is reserved for Enums only.") End Sub diff --git a/src/EditorFeatures/Test/EditorServicesTest.csproj b/src/EditorFeatures/Test/EditorServicesTest.csproj index 5fd0df603292..a8a83332d5a2 100644 --- a/src/EditorFeatures/Test/EditorServicesTest.csproj +++ b/src/EditorFeatures/Test/EditorServicesTest.csproj @@ -127,10 +127,6 @@ {eba4dfa1-6ded-418f-a485-a3b608978906} InteractiveHost - - {afde6bea-5038-4a4a-a88e-dbd2e4088eed} - PdbUtilities - {f822f72a-cc87-4e31-b57d-853f65cbebf3} RemoteWorkspaces diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs index b20973b68810..606727142b5c 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs @@ -27,7 +27,6 @@ using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Roslyn.Test.Utilities; using Xunit; -using PDB::Roslyn.Test.MetadataUtilities; using PDB::Roslyn.Test.PdbUtilities; namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests diff --git a/src/Test/PdbUtilities/Metadata/MethodILExtensions.cs b/src/Test/PdbUtilities/Metadata/MethodILExtensions.cs deleted file mode 100644 index fb08336ab4f8..000000000000 --- a/src/Test/PdbUtilities/Metadata/MethodILExtensions.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection.Metadata; -using System.Text; -using Microsoft.Metadata.Tools; - -namespace Roslyn.Test.MetadataUtilities -{ - public static class MethodILExtensions - { - public static unsafe string GetMethodIL(this ImmutableArray ilArray) - { - var result = new StringBuilder(); - fixed (byte* ilPtr = ilArray.ToArray()) - { - int offset = 0; - while (true) - { - // skip padding: - while (offset < ilArray.Length && ilArray[offset] == 0) - { - offset++; - } - - if (offset == ilArray.Length) - { - break; - } - - var reader = new BlobReader(ilPtr + offset, ilArray.Length - offset); - var methodIL = MethodBodyBlock.Create(reader); - - if (methodIL == null) - { - result.AppendFormat("", ilArray[offset], offset); - offset++; - } - else - { - ILVisualizer.Default.DumpMethod( - result, - methodIL.MaxStack, - methodIL.GetILContent(), - ImmutableArray.Create(), - ImmutableArray.Create()); - - offset += methodIL.Size; - } - } - } - - return result.ToString(); - } - } -} diff --git a/src/Test/Utilities/Portable/Pdb/MockSymWriter.cs b/src/Test/PdbUtilities/Pdb/MockSymWriter.cs similarity index 100% rename from src/Test/Utilities/Portable/Pdb/MockSymWriter.cs rename to src/Test/PdbUtilities/Pdb/MockSymWriter.cs diff --git a/src/Test/Utilities/Portable/Pdb/PdbTestUtilities.cs b/src/Test/PdbUtilities/Pdb/PdbTestUtilities.cs similarity index 89% rename from src/Test/Utilities/Portable/Pdb/PdbTestUtilities.cs rename to src/Test/PdbUtilities/Pdb/PdbTestUtilities.cs index 67535a30ae2f..2d3d86529835 100644 --- a/src/Test/Utilities/Portable/Pdb/PdbTestUtilities.cs +++ b/src/Test/PdbUtilities/Pdb/PdbTestUtilities.cs @@ -6,15 +6,23 @@ using System.Reflection.Metadata; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.DiaSymReader; using Roslyn.Test.PdbUtilities; namespace Roslyn.Test.Utilities { - internal static class PdbTestUtilities + public static class PdbTestUtilities { + public static ISymUnmanagedReader3 CreateSymReader(this CompilationVerifier verifier) + { + var pdbStream = new ImmutableMemoryStream(verifier.EmittedAssemblyPdb); + return SymReaderFactory.CreateReader(pdbStream, metadataReaderOpt: null, metadataMemoryOwnerOpt: null); + } + public unsafe static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(this ISymUnmanagedReader3 symReader, MethodDefinitionHandle handle) { const int S_OK = 0; diff --git a/src/Test/Utilities/Portable/Pdb/PdbValidation.cs b/src/Test/PdbUtilities/Pdb/PdbValidation.cs similarity index 71% rename from src/Test/Utilities/Portable/Pdb/PdbValidation.cs rename to src/Test/PdbUtilities/Pdb/PdbValidation.cs index 5e424fd6a214..802c163c2f09 100644 --- a/src/Test/Utilities/Portable/Pdb/PdbValidation.cs +++ b/src/Test/PdbUtilities/Pdb/PdbValidation.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; @@ -14,12 +13,11 @@ using System.Text; using System.Xml; using System.Xml.Linq; -using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Emit; using Microsoft.DiaSymReader; using Microsoft.DiaSymReader.Tools; using Microsoft.Metadata.Tools; -using Roslyn.Test.MetadataUtilities; using Roslyn.Test.PdbUtilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -29,7 +27,111 @@ namespace Microsoft.CodeAnalysis.Test.Utilities { public static class PdbValidation { - internal static void VerifyPdb( + public static CompilationVerifier VerifyPdb( + this CompilationVerifier verifier, + XElement expectedPdb, + IMethodSymbol debugEntryPoint = null, + DebugInformationFormat format = 0, + PdbToXmlOptions options = 0, + [CallerLineNumber]int expectedValueSourceLine = 0, + [CallerFilePath]string expectedValueSourcePath = null) + { + verifier.Compilation.VerifyPdb(expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); + return verifier; + } + + public static CompilationVerifier VerifyPdb( + this CompilationVerifier verifier, + string expectedPdb, + IMethodSymbol debugEntryPoint = null, + DebugInformationFormat format = 0, + PdbToXmlOptions options = 0, + [CallerLineNumber]int expectedValueSourceLine = 0, + [CallerFilePath]string expectedValueSourcePath = null) + { + verifier.Compilation.VerifyPdb(expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); + return verifier; + } + + public static CompilationVerifier VerifyPdb( + this CompilationVerifier verifier, + string qualifiedMethodName, + string expectedPdb, + IMethodSymbol debugEntryPoint = null, + DebugInformationFormat format = 0, + PdbToXmlOptions options = 0, + [CallerLineNumber]int expectedValueSourceLine = 0, + [CallerFilePath]string expectedValueSourcePath = null) + { + verifier.Compilation.VerifyPdb(qualifiedMethodName, expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); + return verifier; + } + + public static CompilationVerifier VerifyPdb( + this CompilationVerifier verifier, + string qualifiedMethodName, + XElement expectedPdb, + IMethodSymbol debugEntryPoint = null, + DebugInformationFormat format = 0, + PdbToXmlOptions options = 0, + [CallerLineNumber]int expectedValueSourceLine = 0, + [CallerFilePath]string expectedValueSourcePath = null) + { + verifier.Compilation.VerifyPdb(qualifiedMethodName, expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); + return verifier; + } + + public static void VerifyPdb(this CompilationDifference diff, IEnumerable methodHandles, string expectedPdb) + { + VerifyPdb(diff, methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb); + } + + public static void VerifyPdb(this CompilationDifference diff, IEnumerable methodHandles, XElement expectedPdb) + { + VerifyPdb(diff, methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb); + } + + public static void VerifyPdb( + this CompilationDifference diff, + IEnumerable methodTokens, + string expectedPdb, + DebugInformationFormat format = DebugInformationFormat.Pdb, + [CallerLineNumber]int expectedValueSourceLine = 0, + [CallerFilePath]string expectedValueSourcePath = null) + { + VerifyPdb(diff, methodTokens, expectedPdb, format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: false); + } + + public static void VerifyPdb( + this CompilationDifference diff, + IEnumerable methodTokens, + XElement expectedPdb, + DebugInformationFormat format = DebugInformationFormat.Pdb, + [CallerLineNumber]int expectedValueSourceLine = 0, + [CallerFilePath]string expectedValueSourcePath = null) + { + VerifyPdb(diff, methodTokens, expectedPdb.ToString(), format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: true); + } + + private static void VerifyPdb( + this CompilationDifference diff, + IEnumerable methodTokens, + string expectedPdb, + DebugInformationFormat format, + int expectedValueSourceLine, + string expectedValueSourcePath, + bool expectedIsXmlLiteral) + { + Assert.NotEqual(default(DebugInformationFormat), format); + Assert.NotEqual(DebugInformationFormat.Embedded, format); + + string actualPdb = PdbToXmlConverter.DeltaPdbToXml(new ImmutableMemoryStream(diff.PdbDelta), methodTokens); + var (actualXml, expectedXml) = AdjustToPdbFormat(actualPdb, expectedPdb, actualIsPortable: diff.NextGeneration.InitialBaseline.HasPortablePdb); + + AssertXml.Equal(expectedXml, actualXml, $"Format: {format}{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral); + } + + public static void VerifyPdb( this Compilation compilation, string expectedPdb, IMethodSymbol debugEntryPoint = null, @@ -41,7 +143,7 @@ internal static void VerifyPdb( VerifyPdb(compilation, "", expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); } - internal static void VerifyPdb( + public static void VerifyPdb( this Compilation compilation, string qualifiedMethodName, string expectedPdb, @@ -63,7 +165,7 @@ internal static void VerifyPdb( expectedIsXmlLiteral: false); } - internal static void VerifyPdb( + public static void VerifyPdb( this Compilation compilation, XElement expectedPdb, IMethodSymbol debugEntryPoint = null, @@ -75,7 +177,7 @@ internal static void VerifyPdb( VerifyPdb(compilation, "", expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); } - internal static void VerifyPdb( + public static void VerifyPdb( this Compilation compilation, string qualifiedMethodName, XElement expectedPdb, @@ -406,164 +508,5 @@ private unsafe static void ValidatePortablePdbId(Stream pdbStream, byte[] stampI Assert.Equal(id.ToArray(), expectedId); } } - - public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2) - { - peStream1.Position = 0; - peStream2.Position = 0; - - var peReader1 = new PEReader(peStream1); - var peReader2 = new PEReader(peStream2); - - var md1 = peReader1.GetMetadata().GetContent(); - var md2 = peReader2.GetMetadata().GetContent(); - - var mdReader1 = peReader1.GetMetadataReader(); - var mdReader2 = peReader2.GetMetadataReader(); - - var mvidIndex1 = mdReader1.GetModuleDefinition().Mvid; - var mvidIndex2 = mdReader2.GetModuleDefinition().Mvid; - - var mvidOffset1 = mdReader1.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex1) - 1); - var mvidOffset2 = mdReader2.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex2) - 1); - - if (!md1.RemoveRange(mvidOffset1, 16).SequenceEqual(md1.RemoveRange(mvidOffset2, 16))) - { - var mdw1 = new StringWriter(); - var mdw2 = new StringWriter(); - new MetadataVisualizer(mdReader1, mdw1).Visualize(); - new MetadataVisualizer(mdReader2, mdw2).Visualize(); - mdw1.Flush(); - mdw2.Flush(); - - AssertEx.AssertResultsEqual(mdw1.ToString(), mdw2.ToString()); - } - } - - public static Dictionary GetMarkers(string pdbXml, string source = null) - { - string[] lines = source?.Split(new[] { "\r\n" }, StringSplitOptions.None); - var doc = new XmlDocument(); - doc.LoadXml(pdbXml); - var result = new Dictionary(); - - if (source == null) - { - foreach (XmlNode entry in doc.GetElementsByTagName("sequencePoints")) - { - foreach (XmlElement item in entry.ChildNodes) - { - Add(result, - Convert.ToInt32(item.GetAttribute("offset"), 16), - (item.GetAttribute("hidden") == "true") ? "~" : "-"); - } - } - - foreach (XmlNode entry in doc.GetElementsByTagName("asyncInfo")) - { - foreach (XmlElement item in entry.ChildNodes) - { - if (item.Name == "await") - { - Add(result, Convert.ToInt32(item.GetAttribute("yield"), 16), "<"); - Add(result, Convert.ToInt32(item.GetAttribute("resume"), 16), ">"); - } - else if (item.Name == "catchHandler") - { - Add(result, Convert.ToInt32(item.GetAttribute("offset"), 16), "$"); - } - } - } - } - else - { - foreach (XmlNode entry in doc.GetElementsByTagName("asyncInfo")) - { - foreach (XmlElement item in entry.ChildNodes) - { - if (item.Name == "await") - { - AddTextual(result, Convert.ToInt32(item.GetAttribute("yield"), 16), "async: yield"); - AddTextual(result, Convert.ToInt32(item.GetAttribute("resume"), 16), "async: resume"); - } - else if (item.Name == "catchHandler") - { - AddTextual(result, Convert.ToInt32(item.GetAttribute("offset"), 16), "async: catch handler"); - } - } - } - - foreach (XmlNode entry in doc.GetElementsByTagName("sequencePoints")) - { - foreach (XmlElement item in entry.ChildNodes) - { - AddTextual(result, Convert.ToInt32(item.GetAttribute("offset"), 16), "sequence point: " + SnippetFromSpan(lines, item)); - } - } - } - - return result; - - void Add(Dictionary dict, int key, string value) - { - if (dict.TryGetValue(key, out string found)) - { - dict[key] = found + value; - } - else - { - dict[key] = value; - } - } - - void AddTextual(Dictionary dict, int key, string value) - { - if (dict.TryGetValue(key, out string found)) - { - dict[key] = found + ", " + value; - } - else - { - dict[key] = "// " + value; - } - } - } - - private static string SnippetFromSpan(string[] lines, XmlElement span) - { - if (span.GetAttribute("hidden") != "true") - { - var startLine = Convert.ToInt32(span.GetAttribute("startLine")); - var startColumn = Convert.ToInt32(span.GetAttribute("startColumn")); - var endLine = Convert.ToInt32(span.GetAttribute("endLine")); - var endColumn = Convert.ToInt32(span.GetAttribute("endColumn")); - if (startLine == endLine) - { - return lines[startLine - 1].Substring(startColumn - 1, endColumn - startColumn); - } - else - { - var start = lines[startLine - 1].Substring(startColumn - 1); - var end = lines[endLine - 1].Substring(0, endColumn - 1); - return TruncateStart(start, 12) + " ... " + TruncateEnd(end, 12); - } - } - else - { - return ""; - } - - string TruncateStart(string text, int maxLength) - { - if (text.Length < maxLength) { return text; } - return text.Substring(0, maxLength); - } - - string TruncateEnd(string text, int maxLength) - { - if (text.Length < maxLength) { return text; } - return text.Substring(text.Length - maxLength - 1, maxLength); - } - } } } diff --git a/src/Test/PdbUtilities/PdbUtilities.csproj b/src/Test/PdbUtilities/PdbUtilities.csproj index 1bd72d0917d5..654b6e447133 100644 --- a/src/Test/PdbUtilities/PdbUtilities.csproj +++ b/src/Test/PdbUtilities/PdbUtilities.csproj @@ -11,6 +11,7 @@ Roslyn.Test.PdbUtilities Roslyn.Test.PdbUtilities netstandard1.3 + portable-net452 {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14.0 true @@ -18,18 +19,10 @@ - - InternalUtilities\ExceptionUtilities.cs - - - InternalUtilities\Hash.cs - - - InternalUtilities\StreamExtensions.cs - - - + + + @@ -37,20 +30,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + {1EE8CAD3-55F9-4D91-96B2-084641DA9A6C} + CodeAnalysis + + + {ccbd3438-3e84-40a9-83ad-533f23bcfca5} + TestUtilities + - - \ No newline at end of file diff --git a/src/Test/Utilities/CoreClr/TestUtilities.CoreClr.csproj b/src/Test/Utilities/CoreClr/TestUtilities.CoreClr.csproj index c6a95ca6234b..b3b864f199ad 100644 --- a/src/Test/Utilities/CoreClr/TestUtilities.CoreClr.csproj +++ b/src/Test/Utilities/CoreClr/TestUtilities.CoreClr.csproj @@ -22,10 +22,6 @@ {7fe6b002-89d8-4298-9b1b-0b5c247dd1fd} CompilerTestResources - - {afde6bea-5038-4a4a-a88e-dbd2e4088eed} - PdbUtilities - {1EE8CAD3-55F9-4D91-96B2-084641DA9A6C} CodeAnalysis diff --git a/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj b/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj index 711f600c82e6..2e515d501127 100644 --- a/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj +++ b/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj @@ -31,10 +31,6 @@ {2523D0E6-DF32-4A3E-8AE0-A19BFFAE2EF6} BasicCodeAnalysis - - {afde6bea-5038-4a4a-a88e-dbd2e4088eed} - PdbUtilities - {ccbd3438-3e84-40a9-83ad-533f23bcfca5} TestUtilities diff --git a/src/Test/Utilities/Portable/CommonTestBase.CompilationVerifier.cs b/src/Test/Utilities/Portable/CommonTestBase.CompilationVerifier.cs deleted file mode 100644 index 5b2df8ca3df4..000000000000 --- a/src/Test/Utilities/Portable/CommonTestBase.CompilationVerifier.cs +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Runtime.CompilerServices; -using System.Xml.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeGen; -using Microsoft.CodeAnalysis.Emit; -using Microsoft.DiaSymReader; -using Microsoft.DiaSymReader.Tools; -using Roslyn.Test.PdbUtilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Test.Utilities -{ - public partial class CommonTestBase - { - public class CompilationVerifier - { - private readonly CommonTestBase _test; - private readonly Compilation _compilation; - private CompilationTestData _testData; - private readonly IEnumerable _dependencies; - private ImmutableArray _diagnostics; - private IModuleSymbol _lazyModuleSymbol; - private IList _allModuleData; - - internal ImmutableArray EmittedAssemblyData; - internal ImmutableArray EmittedAssemblyPdb; - - public CompilationVerifier( - CommonTestBase test, - Compilation compilation, - IEnumerable dependencies = null) - { - _test = test; - _compilation = compilation; - _dependencies = dependencies; - } - - internal CompilationTestData TestData - { - get { return _testData; } - } - - public Compilation Compilation - { - get { return _compilation; } - } - - public TempRoot Temp - { - get { return _test.Temp; } - } - - internal ImmutableArray Diagnostics - { - get { return _diagnostics; } - } - - internal ImmutableArray GetAllModuleMetadata() - { - if (EmittedAssemblyData == null) - { - throw new InvalidOperationException("You must call Emit before calling GetAllModuleMetadata."); - } - - ImmutableArray modules = ImmutableArray.Create(ModuleMetadata.CreateFromImage(EmittedAssemblyData)); - - if (_allModuleData != null) - { - var netModules = _allModuleData.Where(m => m.Kind == OutputKind.NetModule); - if (netModules.Any()) - { - modules = modules.Concat( - ImmutableArray.CreateRange(netModules.Select(m => ModuleMetadata.CreateFromImage(m.Image)))); - } - } - - return modules; - } - - public void Emit(string expectedOutput, int? expectedReturnCode, string[] args, IEnumerable manifestResources, EmitOptions emitOptions, bool peVerify, SignatureDescription[] expectedSignatures) - { - using (var testEnvironment = RuntimeEnvironmentFactory.Create(_dependencies)) - { - string mainModuleName = Emit(testEnvironment, manifestResources, emitOptions); - _allModuleData = testEnvironment.GetAllModuleData(); - - if (peVerify) - { - testEnvironment.PeVerify(); - } - - if (expectedSignatures != null) - { - MetadataSignatureUnitTestHelper.VerifyMemberSignatures(testEnvironment, expectedSignatures); - } - - if (expectedOutput != null || expectedReturnCode != null) - { - var returnCode = testEnvironment.Execute(mainModuleName, args, expectedOutput); - - if (expectedReturnCode is int exCode) - { - Assert.Equal(exCode, returnCode); - } - } - } - } - - // TODO(tomat): Fold into CompileAndVerify. - // Replace bool verify parameter with string[] expectedPeVerifyOutput. If null, no verification. If empty verify have to succeed. Otherwise compare errors. - public void EmitAndVerify(params string[] expectedPeVerifyOutput) - { - using (var testEnvironment = RuntimeEnvironmentFactory.Create(_dependencies)) - { - string mainModuleName = Emit(testEnvironment, null, null); - string[] actualOutput = testEnvironment.PeVerifyModules(new[] { mainModuleName }, throwOnError: false); - Assert.Equal(expectedPeVerifyOutput, actualOutput); - } - } - - private string Emit(IRuntimeEnvironment testEnvironment, IEnumerable manifestResources, EmitOptions emitOptions) - { - testEnvironment.Emit(_compilation, manifestResources, emitOptions); - - _diagnostics = testEnvironment.GetDiagnostics(); - EmittedAssemblyData = testEnvironment.GetMainImage(); - EmittedAssemblyPdb = testEnvironment.GetMainPdb(); - _testData = ((IInternalRuntimeEnvironment)testEnvironment).GetCompilationTestData(); - - return _compilation.Assembly.Identity.GetDisplayName(); - } - - public CompilationVerifier VerifyIL( - string qualifiedMethodName, - XCData expectedIL, - bool realIL = false, - string sequencePoints = null, - [CallerFilePath]string callerPath = null, - [CallerLineNumber]int callerLine = 0) - { - return VerifyILImpl(qualifiedMethodName, expectedIL.Value, realIL, sequencePoints, callerPath, callerLine, escapeQuotes: false); - } - - public CompilationVerifier VerifyIL( - string qualifiedMethodName, - string expectedIL, - bool realIL = false, - string sequencePoints = null, - [CallerFilePath]string callerPath = null, - [CallerLineNumber]int callerLine = 0, - string source = null) - { - return VerifyILImpl(qualifiedMethodName, expectedIL, realIL, sequencePoints, callerPath, callerLine, escapeQuotes: true, source: source); - } - - public void VerifyLocalSignature( - string qualifiedMethodName, - string expectedSignature, - [CallerLineNumber]int callerLine = 0, - [CallerFilePath]string callerPath = null) - { - var ilBuilder = _testData.GetMethodData(qualifiedMethodName).ILBuilder; - string actualSignature = ILBuilderVisualizer.LocalSignatureToString(ilBuilder); - AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedSignature, actualSignature, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); - } - - private CompilationVerifier VerifyILImpl( - string qualifiedMethodName, - string expectedIL, - bool realIL, - string sequencePoints, - string callerPath, - int callerLine, - bool escapeQuotes, - string source = null) - { - string actualIL = VisualizeIL(qualifiedMethodName, realIL, sequencePoints, source); - AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes, callerPath, callerLine); - return this; - } - - public CompilationVerifier VerifyPdb( - XElement expectedPdb, - IMethodSymbol debugEntryPoint = null, - DebugInformationFormat format = 0, - PdbToXmlOptions options = 0, - [CallerLineNumber]int expectedValueSourceLine = 0, - [CallerFilePath]string expectedValueSourcePath = null) - { - _compilation.VerifyPdb(expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); - return this; - } - - public CompilationVerifier VerifyPdb( - string expectedPdb, - IMethodSymbol debugEntryPoint = null, - DebugInformationFormat format = 0, - PdbToXmlOptions options = 0, - [CallerLineNumber]int expectedValueSourceLine = 0, - [CallerFilePath]string expectedValueSourcePath = null) - { - _compilation.VerifyPdb(expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); - return this; - } - - public CompilationVerifier VerifyPdb( - string qualifiedMethodName, - string expectedPdb, - IMethodSymbol debugEntryPoint = null, - DebugInformationFormat format = 0, - PdbToXmlOptions options = 0, - [CallerLineNumber]int expectedValueSourceLine = 0, - [CallerFilePath]string expectedValueSourcePath = null) - { - _compilation.VerifyPdb(qualifiedMethodName, expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); - return this; - } - - public CompilationVerifier VerifyPdb( - string qualifiedMethodName, - XElement expectedPdb, - IMethodSymbol debugEntryPoint = null, - DebugInformationFormat format = 0, - PdbToXmlOptions options = 0, - [CallerLineNumber]int expectedValueSourceLine = 0, - [CallerFilePath]string expectedValueSourcePath = null) - { - _compilation.VerifyPdb(qualifiedMethodName, expectedPdb, debugEntryPoint, format, options, expectedValueSourceLine, expectedValueSourcePath); - return this; - } - - public ISymUnmanagedReader3 CreateSymReader() - { - var pdbStream = new MemoryStream(EmittedAssemblyPdb.ToArray()); - return SymReaderFactory.CreateReader(pdbStream, metadataReaderOpt: null, metadataMemoryOwnerOpt: null); - } - - public string VisualizeIL(string qualifiedMethodName, bool realIL = false, string sequencePoints = null, string source = null) - { - // TODO: Currently the qualifiedMethodName is a symbol display name while PDB need metadata name. - // So we need to pass the PDB metadata name of the method to sequencePoints (instead of just bool). - - return VisualizeIL(_testData.GetMethodData(qualifiedMethodName), realIL, sequencePoints, source); - } - - internal string VisualizeIL(CompilationTestData.MethodData methodData, bool realIL, string sequencePoints = null, string source = null) - { - Dictionary markers = null; - - if (sequencePoints != null) - { - var actualPdbXml = PdbToXmlConverter.ToXml( - pdbStream: new MemoryStream(EmittedAssemblyPdb.ToArray()), - peStream: new MemoryStream(EmittedAssemblyData.ToArray()), - options: PdbToXmlOptions.ResolveTokens | - PdbToXmlOptions.ThrowOnError | - PdbToXmlOptions.ExcludeDocuments | - PdbToXmlOptions.ExcludeCustomDebugInformation | - PdbToXmlOptions.ExcludeScopes, - methodName: sequencePoints); - - markers = PdbValidation.GetMarkers(actualPdbXml, source); - } - - if (!realIL) - { - return ILBuilderVisualizer.ILBuilderToString(methodData.ILBuilder, markers: markers); - } - - if (_lazyModuleSymbol == null) - { - _lazyModuleSymbol = GetModuleSymbolForEmittedImage(EmittedAssemblyData, MetadataImportOptions.All); - } - - return _lazyModuleSymbol != null ? _test.VisualizeRealIL(_lazyModuleSymbol, methodData, markers) : null; - } - - public CompilationVerifier VerifyMemberInIL(string methodName, bool expected) - { - Assert.Equal(expected, _testData.GetMethodsByName().ContainsKey(methodName)); - return this; - } - - public CompilationVerifier VerifyDiagnostics(params DiagnosticDescription[] expected) - { - _diagnostics.Verify(expected); - return this; - } - - public IModuleSymbol GetModuleSymbolForEmittedImage() - { - return GetModuleSymbolForEmittedImage(EmittedAssemblyData, _compilation.Options.MetadataImportOptions); - } - - private IModuleSymbol GetModuleSymbolForEmittedImage(ImmutableArray peImage, MetadataImportOptions importOptions) - { - if (peImage.IsDefault) - { - return null; - } - - var targetReference = LoadTestEmittedExecutableForSymbolValidation(peImage, _compilation.Options.OutputKind, display: _compilation.AssemblyName); - var references = _compilation.References.Concat(new[] { targetReference }); - var assemblies = _test.ReferencesToModuleSymbols(references, importOptions); - return assemblies.Last(); - } - - internal static MetadataReference LoadTestEmittedExecutableForSymbolValidation( - ImmutableArray image, - OutputKind outputKind, - string display = null) - { - var moduleMetadata = ModuleMetadata.CreateFromImage(image); - moduleMetadata.Module.PretendThereArentNoPiaLocalTypes(); - - if (outputKind == OutputKind.NetModule) - { - return moduleMetadata.GetReference(display: display); - } - else - { - return AssemblyMetadata.Create(moduleMetadata).GetReference(display: display); - } - } - - public void VerifyOperationTree(string expectedOperationTree, bool skipImplicitlyDeclaredSymbols = false) - { - _compilation.VerifyOperationTree(expectedOperationTree, skipImplicitlyDeclaredSymbols); - } - - public void VerifyOperationTree(string symbolToVerify, string expectedOperationTree, bool skipImplicitlyDeclaredSymbols = false) - { - _compilation.VerifyOperationTree(symbolToVerify, expectedOperationTree, skipImplicitlyDeclaredSymbols); - } - } - } -} diff --git a/src/Test/Utilities/Portable/CommonTestBase.cs b/src/Test/Utilities/Portable/CommonTestBase.cs index d1adacc3af75..d32b9e4b2b12 100644 --- a/src/Test/Utilities/Portable/CommonTestBase.cs +++ b/src/Test/Utilities/Portable/CommonTestBase.cs @@ -23,8 +23,6 @@ namespace Microsoft.CodeAnalysis.Test.Utilities /// public abstract partial class CommonTestBase : TestBase { - internal abstract IEnumerable ReferencesToModuleSymbols(IEnumerable references, MetadataImportOptions importOptions = MetadataImportOptions.Public); - #region Emit protected abstract Compilation GetCompilationForEmit( @@ -214,9 +212,7 @@ internal CompilationVerifier Emit( EmitOptions emitOptions, bool verify) { - CompilationVerifier verifier = null; - - verifier = new CompilationVerifier(this, compilation, dependencies); + var verifier = new CompilationVerifier(compilation, VisualizeRealIL, dependencies); verifier.Emit(expectedOutput, expectedReturnCode, args, manifestResources, emitOptions, verify, expectedSignatures); diff --git a/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs b/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs index 40bfaa8f3728..6fc9329c461a 100644 --- a/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs +++ b/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs @@ -3,35 +3,29 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; -using System.Xml.Linq; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Emit; -using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.DiaSymReader.Tools; using Microsoft.Metadata.Tools; -using Roslyn.Test.MetadataUtilities; -using Roslyn.Test.PdbUtilities; using Roslyn.Test.Utilities; -using Xunit; namespace Microsoft.CodeAnalysis.Test.Utilities { - internal sealed class CompilationDifference + public sealed class CompilationDifference { public readonly ImmutableArray MetadataDelta; public readonly ImmutableArray ILDelta; public readonly ImmutableArray PdbDelta; - public readonly CompilationTestData TestData; + internal readonly CompilationTestData TestData; public readonly EmitDifferenceResult EmitResult; public readonly ImmutableArray UpdatedMethods; - public CompilationDifference( + internal CompilationDifference( ImmutableArray metadata, ImmutableArray il, ImmutableArray pdb, @@ -55,7 +49,7 @@ public EmitBaseline NextGeneration } } - public PinnedMetadata GetMetadata() + internal PinnedMetadata GetMetadata() { return new PinnedMetadata(MetadataDelta); } @@ -80,7 +74,7 @@ public void VerifyLocalSignature( AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedSignature, actualSignature, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); } - public void VerifyIL( + internal void VerifyIL( string qualifiedMethodName, string expectedIL, Func mapLocal = null, @@ -94,60 +88,13 @@ public void VerifyIL( if (!methodToken.IsNil) { string actualPdb = PdbToXmlConverter.DeltaPdbToXml(new ImmutableMemoryStream(PdbDelta), new[] { MetadataTokens.GetToken(methodToken) }); - sequencePointMarkers = PdbValidation.GetMarkers(actualPdb); + sequencePointMarkers = ILValidation.GetSequencePointMarkers(actualPdb); } string actualIL = ILBuilderVisualizer.ILBuilderToString(ilBuilder, mapLocal ?? ToLocalInfo, sequencePointMarkers); AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); } - public void VerifyPdb(IEnumerable methodHandles, string expectedPdb) - { - VerifyPdb(methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb); - } - - public void VerifyPdb(IEnumerable methodHandles, XElement expectedPdb) - { - VerifyPdb(methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb); - } - - public void VerifyPdb( - IEnumerable methodTokens, - string expectedPdb, - DebugInformationFormat format = DebugInformationFormat.Pdb, - [CallerLineNumber]int expectedValueSourceLine = 0, - [CallerFilePath]string expectedValueSourcePath = null) - { - VerifyPdb(methodTokens, expectedPdb, format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: false); - } - - public void VerifyPdb( - IEnumerable methodTokens, - XElement expectedPdb, - DebugInformationFormat format = DebugInformationFormat.Pdb, - [CallerLineNumber]int expectedValueSourceLine = 0, - [CallerFilePath]string expectedValueSourcePath = null) - { - VerifyPdb(methodTokens, expectedPdb.ToString(), format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: true); - } - - private void VerifyPdb( - IEnumerable methodTokens, - string expectedPdb, - DebugInformationFormat format, - int expectedValueSourceLine, - string expectedValueSourcePath, - bool expectedIsXmlLiteral) - { - Assert.NotEqual(default(DebugInformationFormat), format); - Assert.NotEqual(DebugInformationFormat.Embedded, format); - - string actualPdb = PdbToXmlConverter.DeltaPdbToXml(new ImmutableMemoryStream(PdbDelta), methodTokens); - var (actualXml, expectedXml) = PdbValidation.AdjustToPdbFormat(actualPdb, expectedPdb, actualIsPortable: NextGeneration.InitialBaseline.HasPortablePdb); - - AssertXml.Equal(expectedXml, actualXml, $"Format: {format}{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral); - } - internal string GetMethodIL(string qualifiedMethodName) { return ILBuilderVisualizer.ILBuilderToString(this.TestData.GetMethodData(qualifiedMethodName).ILBuilder, ToLocalInfo); diff --git a/src/Test/Utilities/Portable/CompilationVerifier.cs b/src/Test/Utilities/Portable/CompilationVerifier.cs new file mode 100644 index 000000000000..d47fbab8aa98 --- /dev/null +++ b/src/Test/Utilities/Portable/CompilationVerifier.cs @@ -0,0 +1,289 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Xml.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.DiaSymReader.Tools; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Test.Utilities +{ + public sealed class CompilationVerifier + { + private readonly Compilation _compilation; + private CompilationTestData _testData; + private readonly IEnumerable _dependencies; + private ImmutableArray _diagnostics; + private IModuleSymbol _lazyModuleSymbol; + private IList _allModuleData; + + public ImmutableArray EmittedAssemblyData; + public ImmutableArray EmittedAssemblyPdb; + + private readonly Func, string> _visualizeRealIL; + + internal CompilationVerifier( + Compilation compilation, + Func, string> visualizeRealIL = null, + IEnumerable dependencies = null) + { + _compilation = compilation; + _dependencies = dependencies; + _visualizeRealIL = visualizeRealIL; + } + + internal CompilationTestData TestData => _testData; + public Compilation Compilation => _compilation; + internal ImmutableArray Diagnostics => _diagnostics; + + internal ImmutableArray GetAllModuleMetadata() + { + if (EmittedAssemblyData == null) + { + throw new InvalidOperationException("You must call Emit before calling GetAllModuleMetadata."); + } + + ImmutableArray modules = ImmutableArray.Create(ModuleMetadata.CreateFromImage(EmittedAssemblyData)); + + if (_allModuleData != null) + { + var netModules = _allModuleData.Where(m => m.Kind == OutputKind.NetModule); + if (netModules.Any()) + { + modules = modules.Concat( + ImmutableArray.CreateRange(netModules.Select(m => ModuleMetadata.CreateFromImage(m.Image)))); + } + } + + return modules; + } + + public void Emit(string expectedOutput, int? expectedReturnCode, string[] args, IEnumerable manifestResources, EmitOptions emitOptions, bool peVerify, SignatureDescription[] expectedSignatures) + { + using (var testEnvironment = RuntimeEnvironmentFactory.Create(_dependencies)) + { + string mainModuleName = Emit(testEnvironment, manifestResources, emitOptions); + _allModuleData = testEnvironment.GetAllModuleData(); + + if (peVerify) + { + testEnvironment.PeVerify(); + } + + if (expectedSignatures != null) + { + MetadataSignatureUnitTestHelper.VerifyMemberSignatures(testEnvironment, expectedSignatures); + } + + if (expectedOutput != null || expectedReturnCode != null) + { + var returnCode = testEnvironment.Execute(mainModuleName, args, expectedOutput); + + if (expectedReturnCode is int exCode) + { + Assert.Equal(exCode, returnCode); + } + } + } + } + + // TODO(tomat): Fold into CompileAndVerify. + // Replace bool verify parameter with string[] expectedPeVerifyOutput. If null, no verification. If empty verify have to succeed. Otherwise compare errors. + public void EmitAndVerify(params string[] expectedPeVerifyOutput) + { + using (var testEnvironment = RuntimeEnvironmentFactory.Create(_dependencies)) + { + string mainModuleName = Emit(testEnvironment, null, null); + string[] actualOutput = testEnvironment.PeVerifyModules(new[] { mainModuleName }, throwOnError: false); + Assert.Equal(expectedPeVerifyOutput, actualOutput); + } + } + + private string Emit(IRuntimeEnvironment testEnvironment, IEnumerable manifestResources, EmitOptions emitOptions) + { + testEnvironment.Emit(_compilation, manifestResources, emitOptions); + + _diagnostics = testEnvironment.GetDiagnostics(); + EmittedAssemblyData = testEnvironment.GetMainImage(); + EmittedAssemblyPdb = testEnvironment.GetMainPdb(); + _testData = ((IInternalRuntimeEnvironment)testEnvironment).GetCompilationTestData(); + + return _compilation.Assembly.Identity.GetDisplayName(); + } + + public CompilationVerifier VerifyIL( + string qualifiedMethodName, + XCData expectedIL, + bool realIL = false, + string sequencePoints = null, + [CallerFilePath]string callerPath = null, + [CallerLineNumber]int callerLine = 0) + { + return VerifyILImpl(qualifiedMethodName, expectedIL.Value, realIL, sequencePoints, callerPath, callerLine, escapeQuotes: false); + } + + public CompilationVerifier VerifyIL( + string qualifiedMethodName, + string expectedIL, + bool realIL = false, + string sequencePoints = null, + [CallerFilePath]string callerPath = null, + [CallerLineNumber]int callerLine = 0, + string source = null) + { + return VerifyILImpl(qualifiedMethodName, expectedIL, realIL, sequencePoints, callerPath, callerLine, escapeQuotes: true, source: source); + } + + public void VerifyLocalSignature( + string qualifiedMethodName, + string expectedSignature, + [CallerLineNumber]int callerLine = 0, + [CallerFilePath]string callerPath = null) + { + var ilBuilder = _testData.GetMethodData(qualifiedMethodName).ILBuilder; + string actualSignature = ILBuilderVisualizer.LocalSignatureToString(ilBuilder); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedSignature, actualSignature, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine); + } + + private CompilationVerifier VerifyILImpl( + string qualifiedMethodName, + string expectedIL, + bool realIL, + string sequencePoints, + string callerPath, + int callerLine, + bool escapeQuotes, + string source = null) + { + string actualIL = VisualizeIL(qualifiedMethodName, realIL, sequencePoints, source); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL, escapeQuotes, callerPath, callerLine); + return this; + } + + public string VisualizeIL(string qualifiedMethodName, bool realIL = false, string sequencePoints = null, string source = null) + { + // TODO: Currently the qualifiedMethodName is a symbol display name while PDB need metadata name. + // So we need to pass the PDB metadata name of the method to sequencePoints (instead of just bool). + + return VisualizeIL(_testData.GetMethodData(qualifiedMethodName), realIL, sequencePoints, source); + } + + internal string VisualizeIL(CompilationTestData.MethodData methodData, bool realIL, string sequencePoints = null, string source = null) + { + Dictionary markers = null; + + if (sequencePoints != null) + { + var actualPdbXml = PdbToXmlConverter.ToXml( + pdbStream: new MemoryStream(EmittedAssemblyPdb.ToArray()), + peStream: new MemoryStream(EmittedAssemblyData.ToArray()), + options: PdbToXmlOptions.ResolveTokens | + PdbToXmlOptions.ThrowOnError | + PdbToXmlOptions.ExcludeDocuments | + PdbToXmlOptions.ExcludeCustomDebugInformation | + PdbToXmlOptions.ExcludeScopes, + methodName: sequencePoints); + + markers = ILValidation.GetSequencePointMarkers(actualPdbXml, source); + } + + if (!realIL) + { + return ILBuilderVisualizer.ILBuilderToString(methodData.ILBuilder, markers: markers); + } + + if (_lazyModuleSymbol == null) + { + _lazyModuleSymbol = GetModuleSymbolForEmittedImage(EmittedAssemblyData, MetadataImportOptions.All); + } + + return _lazyModuleSymbol != null ? _visualizeRealIL(_lazyModuleSymbol, methodData, markers) : null; + } + + public CompilationVerifier VerifyMemberInIL(string methodName, bool expected) + { + Assert.Equal(expected, _testData.GetMethodsByName().ContainsKey(methodName)); + return this; + } + + public CompilationVerifier VerifyDiagnostics(params DiagnosticDescription[] expected) + { + _diagnostics.Verify(expected); + return this; + } + + public IModuleSymbol GetModuleSymbolForEmittedImage() + { + return GetModuleSymbolForEmittedImage(EmittedAssemblyData, _compilation.Options.MetadataImportOptions); + } + + private IModuleSymbol GetModuleSymbolForEmittedImage(ImmutableArray peImage, MetadataImportOptions importOptions) + { + if (peImage.IsDefault) + { + return null; + } + var targetReference = LoadTestEmittedExecutableForSymbolValidation(peImage, _compilation.Options.OutputKind, display: _compilation.AssemblyName); + var references = _compilation.References.Concat(new[] { targetReference }); + var assemblies = GetReferencesToModuleSymbols(references, importOptions); + return assemblies.Last(); + } + + private IEnumerable GetReferencesToModuleSymbols(IEnumerable references, MetadataImportOptions importOptions) + { + var dummy = _compilation + .RemoveAllSyntaxTrees() + .WithReferences(references) + .WithAssemblyName("Dummy") + .WithOptions(_compilation.Options.WithMetadataImportOptions(importOptions)); + + return references.Select(reference => + { + if (reference.Properties.Kind == MetadataImageKind.Assembly) + { + return ((IAssemblySymbol)dummy.GetAssemblyOrModuleSymbol(reference))?.Modules.First(); + } + else + { + return (IModuleSymbol)dummy.GetAssemblyOrModuleSymbol(reference); + } + }); + } + + internal static MetadataReference LoadTestEmittedExecutableForSymbolValidation( + ImmutableArray image, + OutputKind outputKind, + string display = null) + { + var moduleMetadata = ModuleMetadata.CreateFromImage(image); + moduleMetadata.Module.PretendThereArentNoPiaLocalTypes(); + + if (outputKind == OutputKind.NetModule) + { + return moduleMetadata.GetReference(display: display); + } + else + { + return AssemblyMetadata.Create(moduleMetadata).GetReference(display: display); + } + } + + public void VerifyOperationTree(string expectedOperationTree, bool skipImplicitlyDeclaredSymbols = false) + { + _compilation.VerifyOperationTree(expectedOperationTree, skipImplicitlyDeclaredSymbols); + } + + public void VerifyOperationTree(string symbolToVerify, string expectedOperationTree, bool skipImplicitlyDeclaredSymbols = false) + { + _compilation.VerifyOperationTree(symbolToVerify, expectedOperationTree, skipImplicitlyDeclaredSymbols); + } + } +} diff --git a/src/Test/PdbUtilities/Metadata/AggregatedMetadataReader.cs b/src/Test/Utilities/Portable/Metadata/AggregatedMetadataReader.cs similarity index 100% rename from src/Test/PdbUtilities/Metadata/AggregatedMetadataReader.cs rename to src/Test/Utilities/Portable/Metadata/AggregatedMetadataReader.cs diff --git a/src/Test/Utilities/Portable/Metadata/ILValidation.cs b/src/Test/Utilities/Portable/Metadata/ILValidation.cs new file mode 100644 index 000000000000..949dddb3aad7 --- /dev/null +++ b/src/Test/Utilities/Portable/Metadata/ILValidation.cs @@ -0,0 +1,186 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Xml; +using Microsoft.Metadata.Tools; + +namespace Roslyn.Test.Utilities +{ + public static class ILValidation + { + public static unsafe string GetMethodIL(this ImmutableArray ilArray) + { + var result = new StringBuilder(); + fixed (byte* ilPtr = ilArray.ToArray()) + { + int offset = 0; + while (true) + { + // skip padding: + while (offset < ilArray.Length && ilArray[offset] == 0) + { + offset++; + } + + if (offset == ilArray.Length) + { + break; + } + + var reader = new BlobReader(ilPtr + offset, ilArray.Length - offset); + var methodIL = MethodBodyBlock.Create(reader); + + if (methodIL == null) + { + result.AppendFormat("", ilArray[offset], offset); + offset++; + } + else + { + ILVisualizer.Default.DumpMethod( + result, + methodIL.MaxStack, + methodIL.GetILContent(), + ImmutableArray.Create(), + ImmutableArray.Create()); + + offset += methodIL.Size; + } + } + } + + return result.ToString(); + } + + public static Dictionary GetSequencePointMarkers(string pdbXml, string source = null) + { + string[] lines = source?.Split(new[] { "\r\n" }, StringSplitOptions.None); + var doc = new XmlDocument(); + doc.LoadXml(pdbXml); + var result = new Dictionary(); + + if (source == null) + { + foreach (XmlNode entry in doc.GetElementsByTagName("sequencePoints")) + { + foreach (XmlElement item in entry.ChildNodes) + { + Add(result, + Convert.ToInt32(item.GetAttribute("offset"), 16), + (item.GetAttribute("hidden") == "true") ? "~" : "-"); + } + } + + foreach (XmlNode entry in doc.GetElementsByTagName("asyncInfo")) + { + foreach (XmlElement item in entry.ChildNodes) + { + if (item.Name == "await") + { + Add(result, Convert.ToInt32(item.GetAttribute("yield"), 16), "<"); + Add(result, Convert.ToInt32(item.GetAttribute("resume"), 16), ">"); + } + else if (item.Name == "catchHandler") + { + Add(result, Convert.ToInt32(item.GetAttribute("offset"), 16), "$"); + } + } + } + } + else + { + foreach (XmlNode entry in doc.GetElementsByTagName("asyncInfo")) + { + foreach (XmlElement item in entry.ChildNodes) + { + if (item.Name == "await") + { + AddTextual(result, Convert.ToInt32(item.GetAttribute("yield"), 16), "async: yield"); + AddTextual(result, Convert.ToInt32(item.GetAttribute("resume"), 16), "async: resume"); + } + else if (item.Name == "catchHandler") + { + AddTextual(result, Convert.ToInt32(item.GetAttribute("offset"), 16), "async: catch handler"); + } + } + } + + foreach (XmlNode entry in doc.GetElementsByTagName("sequencePoints")) + { + foreach (XmlElement item in entry.ChildNodes) + { + AddTextual(result, Convert.ToInt32(item.GetAttribute("offset"), 16), "sequence point: " + SnippetFromSpan(lines, item)); + } + } + } + + return result; + + void Add(Dictionary dict, int key, string value) + { + if (dict.TryGetValue(key, out string found)) + { + dict[key] = found + value; + } + else + { + dict[key] = value; + } + } + + void AddTextual(Dictionary dict, int key, string value) + { + if (dict.TryGetValue(key, out string found)) + { + dict[key] = found + ", " + value; + } + else + { + dict[key] = "// " + value; + } + } + } + + private static string SnippetFromSpan(string[] lines, XmlElement span) + { + if (span.GetAttribute("hidden") != "true") + { + var startLine = Convert.ToInt32(span.GetAttribute("startLine")); + var startColumn = Convert.ToInt32(span.GetAttribute("startColumn")); + var endLine = Convert.ToInt32(span.GetAttribute("endLine")); + var endColumn = Convert.ToInt32(span.GetAttribute("endColumn")); + if (startLine == endLine) + { + return lines[startLine - 1].Substring(startColumn - 1, endColumn - startColumn); + } + else + { + var start = lines[startLine - 1].Substring(startColumn - 1); + var end = lines[endLine - 1].Substring(0, endColumn - 1); + return TruncateStart(start, 12) + " ... " + TruncateEnd(end, 12); + } + } + else + { + return ""; + } + + string TruncateStart(string text, int maxLength) + { + if (text.Length < maxLength) { return text; } + return text.Substring(0, maxLength); + } + + string TruncateEnd(string text, int maxLength) + { + if (text.Length < maxLength) { return text; } + return text.Substring(text.Length - maxLength - 1, maxLength); + } + } + } +} diff --git a/src/Test/Utilities/Portable/MetadataSignatureUnitTestHelper.cs b/src/Test/Utilities/Portable/Metadata/MetadataSignatureUnitTestHelper.cs similarity index 100% rename from src/Test/Utilities/Portable/MetadataSignatureUnitTestHelper.cs rename to src/Test/Utilities/Portable/Metadata/MetadataSignatureUnitTestHelper.cs diff --git a/src/Test/Utilities/Portable/Metadata/MetadataValidation.cs b/src/Test/Utilities/Portable/Metadata/MetadataValidation.cs index 67203dcb1554..a0d02346162f 100644 --- a/src/Test/Utilities/Portable/Metadata/MetadataValidation.cs +++ b/src/Test/Utilities/Portable/Metadata/MetadataValidation.cs @@ -2,10 +2,15 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using Microsoft.CodeAnalysis; +using Microsoft.Metadata.Tools; +using Roslyn.Utilities; using Xunit; namespace Roslyn.Test.Utilities @@ -144,5 +149,38 @@ internal static IEnumerable GetExportedTypesFullNames(MetadataReader met yield return (ns.Length == 0) ? name : (ns + "." + name); } } + + public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2) + { + peStream1.Position = 0; + peStream2.Position = 0; + + var peReader1 = new PEReader(peStream1); + var peReader2 = new PEReader(peStream2); + + var md1 = peReader1.GetMetadata().GetContent(); + var md2 = peReader2.GetMetadata().GetContent(); + + var mdReader1 = peReader1.GetMetadataReader(); + var mdReader2 = peReader2.GetMetadataReader(); + + var mvidIndex1 = mdReader1.GetModuleDefinition().Mvid; + var mvidIndex2 = mdReader2.GetModuleDefinition().Mvid; + + var mvidOffset1 = mdReader1.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex1) - 1); + var mvidOffset2 = mdReader2.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex2) - 1); + + if (!md1.RemoveRange(mvidOffset1, 16).SequenceEqual(md1.RemoveRange(mvidOffset2, 16))) + { + var mdw1 = new StringWriter(); + var mdw2 = new StringWriter(); + new MetadataVisualizer(mdReader1, mdw1).Visualize(); + new MetadataVisualizer(mdReader2, mdw2).Visualize(); + mdw1.Flush(); + mdw2.Flush(); + + AssertEx.AssertResultsEqual(mdw1.ToString(), mdw2.ToString()); + } + } } } diff --git a/src/Test/Utilities/Portable/TestUtilities.csproj b/src/Test/Utilities/Portable/TestUtilities.csproj index d434232356b0..4ac38ce066ea 100644 --- a/src/Test/Utilities/Portable/TestUtilities.csproj +++ b/src/Test/Utilities/Portable/TestUtilities.csproj @@ -22,10 +22,6 @@ {7fe6b002-89d8-4298-9b1b-0b5c247dd1fd} CompilerTestResources - - {afde6bea-5038-4a4a-a88e-dbd2e4088eed} - PdbUtilities - {1EE8CAD3-55F9-4D91-96B2-084641DA9A6C} CodeAnalysis @@ -47,7 +43,6 @@ - @@ -99,7 +94,7 @@ - + @@ -138,7 +133,7 @@ - + @@ -151,12 +146,14 @@ - + + + @@ -173,9 +170,6 @@ - - - diff --git a/src/VisualStudio/Core/Test.Next/VisualStudioTest.Next.csproj b/src/VisualStudio/Core/Test.Next/VisualStudioTest.Next.csproj index b076f92a0ab8..89ad3a6d312a 100644 --- a/src/VisualStudio/Core/Test.Next/VisualStudioTest.Next.csproj +++ b/src/VisualStudio/Core/Test.Next/VisualStudioTest.Next.csproj @@ -143,10 +143,6 @@ {eba4dfa1-6ded-418f-a485-a3b608978906} InteractiveHost - - {afde6bea-5038-4a4a-a88e-dbd2e4088eed} - PdbUtilities - {12a68549-4e8c-42d6-8703-a09335f97997} Scripting