提交 38017cba 编写于 作者: T Tomas Matousek

Test both native and Portable PDB in UsingDebugInfoTests (C#)

上级 59bb3273
......@@ -95,7 +95,7 @@ internal static CSharpCompilation ToCompilationReferencedModulesOnly(this Immuta
return references.ToCompilation();
}
private static CSharpCompilation ToCompilation(this ImmutableArray<MetadataReference> references)
internal static CSharpCompilation ToCompilation(this ImmutableArray<MetadataReference> references)
{
return CSharpCompilation.Create(
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName(),
......
......@@ -344,5 +344,17 @@ internal static Alias Alias(DkmClrAliasKind kind, string name, string fullName,
{
return new Alias(kind, name, fullName, type, customTypeInfo);
}
internal static MethodDebugInfo<TypeSymbol, LocalSymbol> GetMethodDebugInfo(RuntimeInstance runtime, string qualifiedMethodName)
{
var peCompilation = runtime.Modules.SelectAsArray(m => m.MetadataBlock).ToCompilation();
var peMethod = peCompilation.GlobalNamespace.GetMember<PEMethodSymbol>(qualifiedMethodName);
var peModule = (PEModuleSymbol)peMethod.ContainingModule;
var symReader = runtime.Modules.Single(mi => mi.ModuleVersionId == peModule.Module.GetModuleVersionIdOrThrow()).SymReader;
var symbolProvider = new CSharpEESymbolProvider((SourceAssemblySymbol)peCompilation.Assembly, peModule, peMethod);
return MethodDebugInfo<TypeSymbol, LocalSymbol>.ReadMethodDebugInfo((ISymUnmanagedReader)symReader, symbolProvider, MetadataTokens.GetToken(peMethod.Handle), methodVersion: 1, ilOffset: 0, isVisualBasicMethod: false);
}
}
}
// 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.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
......@@ -16,12 +14,13 @@
using Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.DiaSymReader;
using Roslyn.Test.PdbUtilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests
{
using static MethodDebugInfoValidation;
public class UsingDebugInfoTests : ExpressionCompilerTestBase
{
#region Grouped import strings
......@@ -40,10 +39,13 @@ void M()
}
";
var comp = CreateCompilationWithMscorlib(source);
comp.GetDiagnostics().Where(d => d.Severity > DiagnosticSeverity.Info).Verify();
var importStrings = GetGroupedImportStrings(comp, "M");
Assert.Equal("USystem", importStrings.Single().Single());
WithRuntimeInstance(comp, runtime =>
{
GetMethodDebugInfo(runtime, "C.M").ImportRecordGroups.Verify(@"
{
Namespace: string='System'
}");
});
}
[Fact]
......@@ -66,12 +68,17 @@ void M()
}
";
var comp = CreateCompilationWithMscorlib(source);
comp.GetDiagnostics().Where(d => d.Severity > DiagnosticSeverity.Info).Verify();
var importStrings = GetGroupedImportStrings(comp, "M");
Assert.Equal(2, importStrings.Length);
AssertEx.Equal(importStrings[0], new[] { "USystem.IO", "USystem.Text" });
AssertEx.Equal(importStrings[1], new[] { "USystem" });
WithRuntimeInstance(comp, runtime =>
{
GetMethodDebugInfo(runtime, "A.C.M").ImportRecordGroups.Verify(@"
{
Namespace: string='System.IO'
Namespace: string='System.Text'
}
{
Namespace: string='System'
}");
});
}
[Fact]
......@@ -94,17 +101,26 @@ class C
}
";
var comp = CreateCompilationWithMscorlib(source);
comp.GetDiagnostics().Where(d => d.Severity > DiagnosticSeverity.Info).Verify();
var importStrings1 = GetGroupedImportStrings(comp, "M1");
Assert.Equal(2, importStrings1.Length);
AssertEx.Equal(importStrings1[0], new[] { "USystem.IO", "USystem.Text" });
AssertEx.Equal(importStrings1[1], new[] { "USystem" });
WithRuntimeInstance(comp, runtime =>
{
GetMethodDebugInfo(runtime, "A.C.M1").ImportRecordGroups.Verify(@"
{
Namespace: string='System.IO'
Namespace: string='System.Text'
}
{
Namespace: string='System'
}");
var importStrings2 = GetGroupedImportStrings(comp, "M2");
Assert.Equal(2, importStrings2.Length);
AssertEx.Equal(importStrings2[0], importStrings1[0]);
AssertEx.Equal(importStrings2[1], importStrings1[1]);
GetMethodDebugInfo(runtime, "A.C.M2").ImportRecordGroups.Verify(@"
{
Namespace: string='System.IO'
Namespace: string='System.Text'
}
{
Namespace: string='System'
}");
});
}
[Fact]
......@@ -127,16 +143,25 @@ void M()
}
}
";
var aliasedRef = new CSharpCompilationReference(CreateCompilation("", assemblyName: "Lib"), aliases: ImmutableArray.Create("A"));
var aliasedRef = CreateCompilation("", assemblyName: "Lib").EmitToImageReference(aliases: ImmutableArray.Create("A"));
var comp = CreateCompilationWithMscorlib(source, new[] { aliasedRef });
comp.GetDiagnostics().Where(d => d.Severity > DiagnosticSeverity.Info).Verify();
WithRuntimeInstance(comp, runtime =>
{
var info = GetMethodDebugInfo(runtime, "B.C.M");
ImmutableArray<string> externAliasStrings;
var importStrings = GetGroupedImportStrings(comp, "M", out externAliasStrings);
Assert.Equal(2, importStrings.Length);
AssertEx.Equal(importStrings[0], new[] { "USystem.Text", "AF TSystem.IO.File, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" });
AssertEx.Equal(importStrings[1], new[] { "XA", "AS USystem" });
Assert.Equal("ZA Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", externAliasStrings.Single());
info.ImportRecordGroups.Verify(@"
{
Namespace: string='System.Text'
Type: alias='F' type='System.IO.File'
}
{
Assembly: alias='A'
Namespace: alias='S' string='System'
}");
info.ExternAliasRecords.Verify(
"A = 'Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'");
});
}
[WorkItem(1084059, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1084059")]
......@@ -168,16 +193,25 @@ void M()
}
}
";
var aliasedRef = new CSharpCompilationReference(CreateCompilation(libSource, assemblyName: "Lib"), aliases: ImmutableArray.Create("A"));
var aliasedRef = CreateCompilationWithMscorlib(libSource, assemblyName: "Lib").EmitToImageReference(aliases: ImmutableArray.Create("A"));
var comp = CreateCompilationWithMscorlib(source, new[] { aliasedRef });
comp.GetDiagnostics().Where(d => d.Severity > DiagnosticSeverity.Info).Verify();
ImmutableArray<string> externAliasStrings;
var importStrings = GetGroupedImportStrings(comp, "M", out externAliasStrings);
Assert.Equal(2, importStrings.Length);
AssertEx.Equal(importStrings[0], new[] { "TN.Static, Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" });
AssertEx.Equal(importStrings[1], new[] { "XA", "TSystem.Math, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" });
Assert.Equal("ZA Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", externAliasStrings.Single());
WithRuntimeInstance(comp, runtime =>
{
var info = GetMethodDebugInfo(runtime, "B.C.M");
info.ImportRecordGroups.Verify(@"
{
Type: type='N.Static'
}
{
Assembly: alias='A'
Type: type='System.Math'
}");
info.ExternAliasRecords.Verify(
"A = 'Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'");
});
}
[Fact]
......@@ -210,64 +244,40 @@ void M2()
}
}
";
var aliasedRef = new CSharpCompilationReference(CreateCompilation("", assemblyName: "Lib"), aliases: ImmutableArray.Create("A"));
var aliasedRef = CreateCompilation("", assemblyName: "Lib").EmitToImageReference(aliases: ImmutableArray.Create("A"));
var comp = CreateCompilationWithMscorlib(source, new[] { aliasedRef });
comp.GetDiagnostics().Where(d => d.Severity > DiagnosticSeverity.Info).Verify();
ImmutableArray<string> externAliasStrings1;
var importStrings1 = GetGroupedImportStrings(comp, "M1", out externAliasStrings1);
Assert.Equal(2, importStrings1.Length);
AssertEx.Equal("USystem", importStrings1[0].Single());
AssertEx.Equal("XA", importStrings1[1].Single());
Assert.Equal("ZA Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", externAliasStrings1.Single());
ImmutableArray<string> externAliasStrings2;
var importStrings2 = GetGroupedImportStrings(comp, "M2", out externAliasStrings2);
Assert.Equal(2, importStrings2.Length);
AssertEx.Equal("USystem.Text", importStrings2[0].Single());
AssertEx.Equal(importStrings1[1].Single(), importStrings2[1].Single());
Assert.Equal(externAliasStrings1.Single(), externAliasStrings2.Single());
}
WithRuntimeInstance(comp, runtime =>
{
var debugInfo1 = GetMethodDebugInfo(runtime, "B.C.M1");
private static ImmutableArray<ImmutableArray<string>> GetGroupedImportStrings(Compilation compilation, string methodName)
debugInfo1.ImportRecordGroups.Verify(@"
{
ImmutableArray<string> externAliasStrings;
ImmutableArray<ImmutableArray<string>> result = GetGroupedImportStrings(compilation, methodName, out externAliasStrings);
Assert.Equal(0, externAliasStrings.Length);
return result;
Namespace: string='System'
}
private static ImmutableArray<ImmutableArray<string>> GetGroupedImportStrings(Compilation compilation, string methodName, out ImmutableArray<string> externAliasStrings)
{
Assert.NotNull(compilation);
Assert.NotNull(methodName);
Assembly: alias='A'
}");
using (var exebits = new MemoryStream())
{
using (var pdbbits = new MemoryStream())
{
compilation.Emit(exebits, pdbbits);
debugInfo1.ExternAliasRecords.Verify(
"A = 'Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'");
exebits.Position = 0;
using (var metadata = ModuleMetadata.CreateFromStream(exebits, leaveOpen: true))
{
var module = metadata.Module;
var metadataReader = module.MetadataReader;
MethodDefinitionHandle methodHandle = metadataReader.MethodDefinitions.Single(mh => metadataReader.GetString(metadataReader.GetMethodDefinition(mh).Name) == methodName);
int methodToken = metadataReader.GetToken(methodHandle);
var debugInfo2 = GetMethodDebugInfo(runtime, "D.E.M2");
// Create a SymReader, rather than a raw COM object, because
// SymReader implements ISymUnmanagedReader3 and the COM object
// might not.
pdbbits.Position = 0;
var reader = SymReaderFactory.CreateReader(pdbbits);
return reader.GetCSharpGroupedImportStrings(methodToken, methodVersion: 1, externAliasStrings: out externAliasStrings);
}
}
debugInfo2.ImportRecordGroups.Verify(@"
{
Namespace: string='System.Text'
}
{
Assembly: alias='A'
}");
debugInfo2.ExternAliasRecords.Verify(
"A = 'Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'");
});
}
#endregion Grouped import strings
#endregion
#region Invalid PDBs
......
......@@ -65,7 +65,8 @@
</Compile>
<Compile Include="CustomDiagnosticFormatter.cs" />
<Compile Include="ExpressionCompilerTestHelpers.cs" />
<Compile Include="MethodDebugInfo.cs" />
<Compile Include="MethodDebugInfoBytes.cs" />
<Compile Include="MethodDebugInfoValidation.cs" />
<Compile Include="NotImplementedSymUnmanaged.cs" />
<Compile Include="ModuleInstance.cs" />
<Compile Include="MockSymUnmanaged.cs" />
......
// 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 Roslyn.Test.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests
{
internal static class MethodDebugInfoValidation
{
internal static void Verify(this ImmutableArray<ExternAliasRecord> actual, params string[] expected)
{
AssertEx.Equal(expected, actual.Select(r => $"{r.Alias} = '{r.TargetAssembly}'"));
}
internal static void Verify(this ImmutableArray<ImmutableArray<ImportRecord>> actual, string expected)
{
AssertEx.AssertEqualToleratingWhitespaceDifferences(expected,
string.Join(Environment.NewLine,
actual.Select(g => string.Join(Environment.NewLine,
new[] { "{" }.Concat(g.Select(i => " " + DisplayImport(i))).Concat(new[] { "}" })))));
}
private static string DisplayImport(ImportRecord record)
{
return
record.TargetKind + ":" +
(record.Alias != null ? $" alias='{record.Alias}'" : "") +
(record.TargetAssembly != null ? $" assembly='{record.TargetAssembly}'" : "") +
(record.TargetAssemblyAlias != null ? $" assembly-alias='{record.TargetAssemblyAlias}'" : "") +
(record.TargetType != null ? $" type='{record.TargetType}'" : "") +
(record.TargetString != null ? $" string='{record.TargetString}'" : "");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册