提交 a4491d2b 编写于 作者: T Tomas Matousek

Remove dependency on PDB reader from TestBase

上级 f68ed5a1
......@@ -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]
......
......@@ -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
<Fact>
......
' 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
......
......@@ -3,35 +3,30 @@
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<byte> MetadataDelta;
public readonly ImmutableArray<byte> ILDelta;
public readonly ImmutableArray<byte> PdbDelta;
public readonly CompilationTestData TestData;
internal readonly CompilationTestData TestData;
public readonly EmitDifferenceResult EmitResult;
public readonly ImmutableArray<MethodDefinitionHandle> UpdatedMethods;
public CompilationDifference(
internal CompilationDifference(
ImmutableArray<byte> metadata,
ImmutableArray<byte> il,
ImmutableArray<byte> pdb,
......@@ -55,7 +50,7 @@ public EmitBaseline NextGeneration
}
}
public PinnedMetadata GetMetadata()
internal PinnedMetadata GetMetadata()
{
return new PinnedMetadata(MetadataDelta);
}
......@@ -80,7 +75,7 @@ public PinnedMetadata GetMetadata()
AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedSignature, actualSignature, escapeQuotes: true, expectedValueSourcePath: callerPath, expectedValueSourceLine: callerLine);
}
public void VerifyIL(
internal void VerifyIL(
string qualifiedMethodName,
string expectedIL,
Func<Cci.ILocalDefinition, ILVisualizer.LocalInfo> mapLocal = null,
......@@ -94,60 +89,13 @@ public PinnedMetadata GetMetadata()
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<MethodDefinitionHandle> methodHandles, string expectedPdb)
{
VerifyPdb(methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb);
}
public void VerifyPdb(IEnumerable<MethodDefinitionHandle> methodHandles, XElement expectedPdb)
{
VerifyPdb(methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb);
}
public void VerifyPdb(
IEnumerable<int> 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<int> 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<int> 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);
......
......@@ -10,9 +10,7 @@
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;
......@@ -170,62 +168,6 @@ private string Emit(IRuntimeEnvironment testEnvironment, IEnumerable<ResourceDes
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.
......@@ -250,7 +192,7 @@ internal string VisualizeIL(CompilationTestData.MethodData methodData, bool real
PdbToXmlOptions.ExcludeScopes,
methodName: sequencePoints);
markers = PdbValidation.GetMarkers(actualPdbXml, source);
markers = ILValidation.GetSequencePointMarkers(actualPdbXml, source);
}
if (!realIL)
......
......@@ -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<string> 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());
}
}
}
}
// 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.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Test.Utilities
{
internal class MetadataSignatureUnitTestHelper
{
/// <summary>
/// Uses Reflection to verify that the specified member signatures are present in emitted metadata
/// </summary>
/// <param name="appDomainHost">Unit test AppDomain host</param>
/// <param name="expectedSignatures">Baseline signatures - use the Signature() factory method to create instances of SignatureDescription</param>
internal static void VerifyMemberSignatures(
IRuntimeEnvironment appDomainHost, params SignatureDescription[] expectedSignatures)
{
Assert.NotNull(expectedSignatures);
Assert.NotEmpty(expectedSignatures);
var succeeded = true;
var expected = new List<string>();
var actual = new List<string>();
foreach (var signature in expectedSignatures)
{
List<string> actualSignatures = null;
var expectedSignature = signature.ExpectedSignature;
if (!VerifyMemberSignatureHelper(
appDomainHost, signature.FullyQualifiedTypeName, signature.MemberName,
ref expectedSignature, out actualSignatures))
{
succeeded = false;
}
expected.Add(expectedSignature);
actual.AddRange(actualSignatures);
}
if (!succeeded)
{
TriggerSignatureMismatchFailure(expected, actual);
}
}
/// <summary>
/// Uses Reflection to verify that the specified member signature is present in emitted metadata
/// </summary>
/// <param name="appDomainHost">Unit test AppDomain host</param>
/// <param name="fullyQualifiedTypeName">
/// Fully qualified type name for member
/// Names must be in format recognized by reflection
/// e.g. MyType&lt;T&gt;.MyNestedType&lt;T, U&gt; => MyType`1+MyNestedType`2
/// </param>
/// <param name="memberName">
/// Name of member on specified type whose signature needs to be verified
/// Names must be in format recognized by reflection
/// e.g. For explicitly implemented member - I1&lt;string&gt;.Method => I1&lt;System.String&gt;.Method
/// </param>
/// <param name="expectedSignature">
/// Baseline string for signature of specified member
/// Skip this argument to get an error message that shows all available signatures for specified member
/// This argument is passed by reference and it will be updated with a formatted form of the baseline signature for error reporting purposes
/// </param>
/// <param name="actualSignatures">List of found signatures matching member name</param>
/// <returns>True if a matching member signature was found, false otherwise</returns>
private static bool VerifyMemberSignatureHelper(
IRuntimeEnvironment appDomainHost, string fullyQualifiedTypeName, string memberName,
ref string expectedSignature, out List<string> actualSignatures)
{
Assert.False(string.IsNullOrWhiteSpace(fullyQualifiedTypeName), "'fullyQualifiedTypeName' can't be null or empty");
Assert.False(string.IsNullOrWhiteSpace(memberName), "'memberName' can't be null or empty");
var retVal = true; actualSignatures = new List<string>();
var signatures = appDomainHost.GetMemberSignaturesFromMetadata(fullyQualifiedTypeName, memberName);
var signatureAssertText = "Signature(\"" + fullyQualifiedTypeName + "\", \"" + memberName + "\", \"{0}\"),";
if (!string.IsNullOrWhiteSpace(expectedSignature))
{
expectedSignature = expectedSignature.Replace("\"", "\\\"");
}
expectedSignature = string.Format(signatureAssertText, expectedSignature);
if (signatures.Count > 1)
{
var found = false;
foreach (var signature in signatures)
{
var actualSignature = signature.Replace("\"", "\\\"");
actualSignature = string.Format(signatureAssertText, actualSignature);
if (actualSignature == expectedSignature)
{
actualSignatures.Clear();
actualSignatures.Add(actualSignature);
found = true; break;
}
else
{
actualSignatures.Add(actualSignature);
}
}
if (!found)
{
retVal = false;
}
}
else if (signatures.Count == 1)
{
var actualSignature = signatures.First().Replace("\"", "\\\"");
actualSignature = string.Format(signatureAssertText, actualSignature);
actualSignatures.Add(actualSignature);
if (expectedSignature != actualSignature)
{
retVal = false;
}
}
else
{
retVal = false;
}
return retVal;
}
/// <summary>
/// Triggers assert when expected and actual signatures don't match
/// </summary>
/// <param name="expectedSignatures">List of baseline signature strings</param>
/// <param name="actualSignatures">List of actually found signature strings</param>
private static void TriggerSignatureMismatchFailure(List<string> expectedSignatures, List<string> actualSignatures)
{
var expectedText = string.Empty;
var actualText = string.Empty;
var distinctSignatures = new HashSet<string>();
foreach (var signature in expectedSignatures)
{
// We need to preserve the order as well as prevent duplicates
if (!distinctSignatures.Contains(signature))
{
expectedText += "\n\t" + signature;
distinctSignatures.Add(signature);
}
}
distinctSignatures.Clear();
foreach (var signature in actualSignatures)
{
// We need to preserve the order as well as prevent duplicates
if (!distinctSignatures.Contains(signature))
{
actualText += "\n\t" + signature;
distinctSignatures.Add(signature);
}
}
expectedText = expectedText.TrimEnd(',');
actualText = actualText.TrimEnd(',');
var diffText = DiffUtil.DiffReport(expectedText, actualText);
Assert.True(false, "\n\nExpected:" + expectedText + "\n\nActual:" + actualText + "\n\nDifferences:\n" + diffText);
}
}
}
......@@ -6,8 +6,10 @@
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;
......@@ -15,6 +17,12 @@ namespace Roslyn.Test.Utilities
{
internal 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;
......
......@@ -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,6 +27,110 @@ namespace Microsoft.CodeAnalysis.Test.Utilities
{
public static class PdbValidation
{
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<MethodDefinitionHandle> methodHandles, string expectedPdb)
{
VerifyPdb(diff, methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb);
}
public static void VerifyPdb(this CompilationDifference diff, IEnumerable<MethodDefinitionHandle> methodHandles, XElement expectedPdb)
{
VerifyPdb(diff, methodHandles.Select(h => MetadataTokens.GetToken(h)), expectedPdb);
}
public static void VerifyPdb(
this CompilationDifference diff,
IEnumerable<int> 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<int> 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<int> 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);
}
internal static void VerifyPdb(
this Compilation compilation,
string 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<int, string> 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<int, string>();
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<int, string> dict, int key, string value)
{
if (dict.TryGetValue(key, out string found))
{
dict[key] = found + value;
}
else
{
dict[key] = value;
}
}
void AddTextual(Dictionary<int, string> 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 "<hidden>";
}
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);
}
}
}
}
......@@ -151,12 +151,13 @@
<Compile Include="ICompilationVerifier.cs" />
<Compile Include="MarkedSource\MarkupTestFile.cs" />
<Compile Include="MarkedSource\SourceWithMarkedNodes.cs" />
<Compile Include="MetadataSignatureUnitTestHelper.cs" />
<Compile Include="Metadata\MetadataSignatureUnitTestHelper.cs" />
<Compile Include="Metadata\CustomAttributeRow.cs" />
<Compile Include="Metadata\DynamicAnalysisDataReader.cs" />
<Compile Include="Metadata\EncValidation.cs" />
<Compile Include="Metadata\IlasmUtilities.cs" />
<Compile Include="Metadata\ILBuilderVisualizer.cs" />
<Compile Include="Metadata\ILValidation.cs" />
<Compile Include="Metadata\MetadataReaderUtils.cs" />
<Compile Include="Metadata\MetadataValidation.cs" />
<Compile Include="Metadata\ModuleData.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册