Browse Source

Clean up PEFile, move Pdb related types to DebugInfo namespace

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
bcfb3742eb
  1. 4
      ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs
  2. 13
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 5
      ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs
  4. 45
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  5. 16
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  6. 9
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
  7. 19
      ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs
  8. 6
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  9. 2
      ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs
  10. 15
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  11. 125
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  12. 20
      ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs
  13. 5
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  14. 6
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  15. 8
      ICSharpCode.Decompiler/IL/ILReader.cs
  16. 5
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  17. 16
      ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs
  18. 18
      ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs
  19. 17
      ICSharpCode.Decompiler/Metadata/Dom.cs
  20. 14
      ICSharpCode.Decompiler/Metadata/MetadataResolver.cs
  21. 19
      ICSharpCode.Decompiler/Metadata/PEFile.cs
  22. 2
      ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
  23. 12
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  24. 6
      ICSharpCode.Decompiler/TypeSystem/IAssembly.cs
  25. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs
  26. 3
      ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs
  27. 4
      ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs
  28. 14
      ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
  29. 2
      ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
  30. 7
      ILSpy.BamlDecompiler/CecilTypeResolver.cs
  31. 8
      ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs
  32. 9
      ILSpy/DebugInfo/DiaSymNativeDebugInfoProvider.cs
  33. 7
      ILSpy/DebugInfo/PortableDebugInfoProvider.cs
  34. 2
      ILSpy/ILSpy.csproj
  35. 215
      ILSpy/Languages/CSharpLanguage.cs
  36. 39
      ILSpy/LoadedAssembly.cs
  37. 25
      ILSpy/LoadedAssemblyExtensions.cs
  38. 2
      ILSpy/SearchPane.cs
  39. 6
      ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs
  40. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  41. 8
      ILSpy/TreeNodes/BaseTypesEntryNode.cs
  42. 4
      ILSpy/TreeNodes/GeneratePdbContextMenuEntry.cs

4
ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs

@ -20,7 +20,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using Mono.Cecil; using Mono.Cecil;
@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.PdbProvider.Cecil
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as Mono.Cecil.MethodDefinition; var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as Mono.Cecil.MethodDefinition;
if (method?.DebugInformation == null || !method.DebugInformation.HasSequencePoints) if (method?.DebugInformation == null || !method.DebugInformation.HasSequencePoints)
return EmptyList<SequencePoint>.Instance; return EmptyList<SequencePoint>.Instance;
return method.DebugInformation.SequencePoints.Select(point => new Metadata.SequencePoint { return method.DebugInformation.SequencePoints.Select(point => new SequencePoint {
Offset = point.Offset, Offset = point.Offset,
StartLine = point.StartLine, StartLine = point.StartLine,
StartColumn = point.StartColumn, StartColumn = point.StartColumn,

13
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -348,8 +348,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var emitResult = compilation.Emit(peStream); var emitResult = compilation.Emit(peStream);
peStream.Position = 0; peStream.Position = 0;
var moduleDefinition = new PEFile("TestAssembly.dll", peStream, false, PEStreamOptions.PrefetchEntireImage); var moduleDefinition = new PEFile("TestAssembly.dll", peStream, PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(moduleDefinition, new DecompilerSettings()); var resolver = new UniversalAssemblyResolver("TestAssembly.dll", false, moduleDefinition.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
return decompiler; return decompiler;
} }
@ -394,9 +395,11 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
public static string DecompileCSharp(string assemblyFileName, DecompilerSettings settings = null) public static string DecompileCSharp(string assemblyFileName, DecompilerSettings settings = null)
{ {
using (var file = new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read)) { using (var file = new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read)) {
var module = new PEFile(assemblyFileName, file, false, PEStreamOptions.PrefetchEntireImage); var module = new PEFile(assemblyFileName, file, PEStreamOptions.PrefetchEntireImage);
var typeSystem = new DecompilerTypeSystem(module); var resolver = new UniversalAssemblyResolver(assemblyFileName, false,
CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings ?? new DecompilerSettings()); module.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchMetadata);
var typeSystem = new DecompilerTypeSystem(module, resolver);
CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, resolver, settings ?? new DecompilerSettings());
decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAtttributes()); decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAtttributes());
decompiler.AstTransforms.Insert(0, new RemoveCompilerAttribute()); decompiler.AstTransforms.Insert(0, new RemoveCompilerAttribute());
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());

5
ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs

@ -144,11 +144,12 @@ namespace ICSharpCode.Decompiler.Tests
Console.WriteLine($"Decompiling {fileToRoundtrip}..."); Console.WriteLine($"Decompiling {fileToRoundtrip}...");
Stopwatch w = Stopwatch.StartNew(); Stopwatch w = Stopwatch.StartNew();
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) { using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) {
PEFile module = new PEFile(file, fileStream, false, PEStreamOptions.PrefetchEntireImage); PEFile module = new PEFile(file, fileStream, PEStreamOptions.PrefetchEntireImage);
UniversalAssemblyResolver resolver = (UniversalAssemblyResolver)module.AssemblyResolver; UniversalAssemblyResolver resolver = new UniversalAssemblyResolver(file, false, module.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchMetadata);
resolver.AddSearchDirectory(inputDir); resolver.AddSearchDirectory(inputDir);
resolver.RemoveSearchDirectory("."); resolver.RemoveSearchDirectory(".");
var decompiler = new TestProjectDecompiler(inputDir); var decompiler = new TestProjectDecompiler(inputDir);
decompiler.AssemblyResolver = resolver;
// use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes // use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes
decompiler.ProjectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}"); decompiler.ProjectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}");
decompiler.DecompileProject(module, decompiledDir); decompiler.DecompileProject(module, decompiledDir);

45
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -39,6 +39,8 @@ using System.Reflection.Metadata;
using SRM = System.Reflection.Metadata; using SRM = System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.DebugInfo;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
@ -179,6 +181,18 @@ namespace ICSharpCode.Decompiler.CSharp
public IDecompilerTypeSystem TypeSystem => typeSystem; public IDecompilerTypeSystem TypeSystem => typeSystem;
public IAssemblyResolver AssemblyResolver { get; }
/// <summary>
/// Gets or sets the optional provider for debug info.
/// </summary>
public IDebugInfoProvider DebugInfoProvider { get; set; }
/// <summary>
/// Gets or sets the optional provider for XML documentation strings.
/// </summary>
public IDocumentationProvider DocumentationProvider { get; set; }
/// <summary> /// <summary>
/// IL transforms. /// IL transforms.
/// </summary> /// </summary>
@ -193,21 +207,20 @@ namespace ICSharpCode.Decompiler.CSharp
get { return astTransforms; } get { return astTransforms; }
} }
public CSharpDecompiler(string fileName, DecompilerSettings settings) public CSharpDecompiler(string fileName, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
: this(LoadPEFile(fileName, settings), settings) : this(LoadPEFile(fileName, settings), assemblyResolver, settings)
{ {
} }
public CSharpDecompiler(Metadata.PEFile module, DecompilerSettings settings) public CSharpDecompiler(PEFile module, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
: this(new DecompilerTypeSystem(module, settings), settings) : this(new DecompilerTypeSystem(module, assemblyResolver, settings), assemblyResolver, settings)
{ {
} }
public CSharpDecompiler(DecompilerTypeSystem typeSystem, DecompilerSettings settings) public CSharpDecompiler(DecompilerTypeSystem typeSystem, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
{ {
if (typeSystem == null) this.typeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem));
throw new ArgumentNullException(nameof(typeSystem)); this.AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver));
this.typeSystem = typeSystem;
this.settings = settings; this.settings = settings;
} }
@ -318,7 +331,6 @@ namespace ICSharpCode.Decompiler.CSharp
return new PEFile( return new PEFile(
fileName, fileName,
new FileStream(fileName, FileMode.Open, FileAccess.Read), new FileStream(fileName, FileMode.Open, FileAccess.Read),
settings.ThrowOnAssemblyResolveErrors,
options: settings.LoadInMemory ? PEStreamOptions.PrefetchEntireImage : PEStreamOptions.Default options: settings.LoadInMemory ? PEStreamOptions.PrefetchEntireImage : PEStreamOptions.Default
); );
} }
@ -436,7 +448,7 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
var decompileRun = new DecompileRun(settings) { CancellationToken = CancellationToken }; var decompileRun = new DecompileRun(settings) { CancellationToken = CancellationToken };
RequiredNamespaceCollector.CollectNamespaces(function.Method, typeSystem, decompileRun.Namespaces); RequiredNamespaceCollector.CollectNamespaces(function.Method, typeSystem, decompileRun.Namespaces);
return new ILTransformContext(function, typeSystem, settings) { return new ILTransformContext(function, typeSystem, DebugInfoProvider, settings) {
CancellationToken = CancellationToken, CancellationToken = CancellationToken,
DecompileRun = decompileRun DecompileRun = decompileRun
}; };
@ -887,10 +899,13 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
try { try {
var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(decompilationContext); var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(decompilationContext);
var ilReader = new ILReader(specializingTypeSystem); var ilReader = new ILReader(specializingTypeSystem) {
ilReader.UseDebugSymbols = settings.UseDebugSymbols; UseDebugSymbols = settings.UseDebugSymbols,
DebugInfo = DebugInfoProvider
};
var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
var function = ilReader.ReadIL(typeSystem.ModuleDefinition, (MethodDefinitionHandle)method.MetadataToken, typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), CancellationToken); var methodBody = typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
var function = ilReader.ReadIL(typeSystem.ModuleDefinition, (MethodDefinitionHandle)method.MetadataToken, methodBody, CancellationToken);
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal);
if (entityDecl != null) { if (entityDecl != null) {
@ -911,7 +926,7 @@ namespace ICSharpCode.Decompiler.CSharp
localSettings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls = true; localSettings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls = true;
} }
var context = new ILTransformContext(function, specializingTypeSystem, localSettings) { var context = new ILTransformContext(function, specializingTypeSystem, DebugInfoProvider, localSettings) {
CancellationToken = CancellationToken, CancellationToken = CancellationToken,
DecompileRun = decompileRun DecompileRun = decompileRun
}; };
@ -1126,7 +1141,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// ///
/// This only works correctly when the nodes in the syntax tree have line/column information. /// This only works correctly when the nodes in the syntax tree have line/column information.
/// </summary> /// </summary>
public Dictionary<ILFunction, List<Metadata.SequencePoint>> CreateSequencePoints(SyntaxTree syntaxTree) public Dictionary<ILFunction, List<DebugInfo.SequencePoint>> CreateSequencePoints(SyntaxTree syntaxTree)
{ {
SequencePointBuilder spb = new SequencePointBuilder(); SequencePointBuilder spb = new SequencePointBuilder();
syntaxTree.AcceptVisitor(spb); syntaxTree.AcceptVisitor(spb);

16
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
readonly List<(ILFunction, Metadata.SequencePoint)> sequencePoints = new List<(ILFunction, Metadata.SequencePoint)>(); readonly List<(ILFunction, DebugInfo.SequencePoint)> sequencePoints = new List<(ILFunction, DebugInfo.SequencePoint)>();
readonly HashSet<ILInstruction> mappedInstructions = new HashSet<ILInstruction>(); readonly HashSet<ILInstruction> mappedInstructions = new HashSet<ILInstruction>();
// Stack holding information for outer statements. // Stack holding information for outer statements.
@ -219,7 +219,7 @@ namespace ICSharpCode.Decompiler.CSharp
// use LongSet to deduplicate and merge the intervals // use LongSet to deduplicate and merge the intervals
var longSet = new LongSet(current.Intervals.Select(i => new LongInterval(i.Start, i.End))); var longSet = new LongSet(current.Intervals.Select(i => new LongInterval(i.Start, i.End)));
Debug.Assert(!longSet.IsEmpty); Debug.Assert(!longSet.IsEmpty);
sequencePoints.Add((current.Function, new Metadata.SequencePoint { sequencePoints.Add((current.Function, new DebugInfo.SequencePoint {
Offset = (int)longSet.Intervals[0].Start, Offset = (int)longSet.Intervals[0].Start,
EndOffset = (int)longSet.Intervals[0].End, EndOffset = (int)longSet.Intervals[0].End,
StartLine = startLocation.Line, StartLine = startLocation.Line,
@ -277,18 +277,18 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary> /// <summary>
/// Called after the visitor is done to return the results. /// Called after the visitor is done to return the results.
/// </summary> /// </summary>
internal Dictionary<ILFunction, List<Metadata.SequencePoint>> GetSequencePoints() internal Dictionary<ILFunction, List<DebugInfo.SequencePoint>> GetSequencePoints()
{ {
var dict = new Dictionary<ILFunction, List<Metadata.SequencePoint>>(); var dict = new Dictionary<ILFunction, List<DebugInfo.SequencePoint>>();
foreach (var (function, sequencePoint) in this.sequencePoints) { foreach (var (function, sequencePoint) in this.sequencePoints) {
if (!dict.TryGetValue(function, out var list)) { if (!dict.TryGetValue(function, out var list)) {
dict.Add(function, list = new List<Metadata.SequencePoint>()); dict.Add(function, list = new List<DebugInfo.SequencePoint>());
} }
list.Add(sequencePoint); list.Add(sequencePoint);
} }
foreach (var (function, list) in dict.ToList()) { foreach (var (function, list) in dict.ToList()) {
// For each function, sort sequence points and fix overlaps+gaps // For each function, sort sequence points and fix overlaps+gaps
var newList = new List<Metadata.SequencePoint>(); var newList = new List<DebugInfo.SequencePoint>();
int pos = 0; int pos = 0;
foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) { foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) {
if (sequencePoint.Offset < pos) { if (sequencePoint.Offset < pos) {
@ -305,7 +305,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} else if (sequencePoint.Offset > pos) { } else if (sequencePoint.Offset > pos) {
// insert hidden sequence point in the gap. // insert hidden sequence point in the gap.
var hidden = new Metadata.SequencePoint(); var hidden = new DebugInfo.SequencePoint();
hidden.Offset = pos; hidden.Offset = pos;
hidden.EndOffset = sequencePoint.Offset; hidden.EndOffset = sequencePoint.Offset;
hidden.SetHidden(); hidden.SetHidden();
@ -315,7 +315,7 @@ namespace ICSharpCode.Decompiler.CSharp
pos = sequencePoint.EndOffset; pos = sequencePoint.EndOffset;
} }
if (pos < function.CodeSize) { if (pos < function.CodeSize) {
var hidden = new Metadata.SequencePoint(); var hidden = new DebugInfo.SequencePoint();
hidden.Offset = pos; hidden.Offset = pos;
hidden.EndOffset = function.CodeSize; hidden.EndOffset = function.CodeSize;
hidden.SetHidden(); hidden.SetHidden();

9
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -34,6 +34,7 @@ using System.Reflection.PortableExecutable;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using static ICSharpCode.Decompiler.Metadata.DotNetCorePathFinderExtensions; using static ICSharpCode.Decompiler.Metadata.DotNetCorePathFinderExtensions;
using static ICSharpCode.Decompiler.Metadata.MetadataExtensions; using static ICSharpCode.Decompiler.Metadata.MetadataExtensions;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
@ -56,6 +57,8 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
public IAssemblyResolver AssemblyResolver { get; set; }
/// <summary> /// <summary>
/// The MSBuild ProjectGuid to use for the new project. /// The MSBuild ProjectGuid to use for the new project.
/// <c>null</c> to automatically generate a new GUID. /// <c>null</c> to automatically generate a new GUID.
@ -218,7 +221,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (r.Name != "mscorlib") { if (r.Name != "mscorlib") {
w.WriteStartElement("Reference"); w.WriteStartElement("Reference");
w.WriteAttributeString("Include", r.Name); w.WriteAttributeString("Include", r.Name);
var asm = module.AssemblyResolver.Resolve(r); var asm = AssemblyResolver.Resolve(r);
if (!IsGacAssembly(r, asm)) { if (!IsGacAssembly(r, asm)) {
if (asm != null) { if (asm != null) {
w.WriteElementString("HintPath", asm.FileName); w.WriteElementString("HintPath", asm.FileName);
@ -275,7 +278,7 @@ namespace ICSharpCode.Decompiler.CSharp
CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts) CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
{ {
var decompiler = new CSharpDecompiler(ts, settings); var decompiler = new CSharpDecompiler(ts, AssemblyResolver, settings);
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());
decompiler.AstTransforms.Add(new RemoveCLSCompliantAttribute()); decompiler.AstTransforms.Add(new RemoveCLSCompliantAttribute());
return decompiler; return decompiler;
@ -314,7 +317,7 @@ namespace ICSharpCode.Decompiler.CSharp
return Path.Combine(dir, file); return Path.Combine(dir, file);
} }
}, StringComparer.OrdinalIgnoreCase).ToList(); }, StringComparer.OrdinalIgnoreCase).ToList();
DecompilerTypeSystem ts = new DecompilerTypeSystem(module); DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver);
Parallel.ForEach( Parallel.ForEach(
files, files,
new ParallelOptions { new ParallelOptions {

19
ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Text;
namespace ICSharpCode.Decompiler.DebugInfo
{
public struct Variable
{
public string Name { get; set; }
}
public interface IDebugInfoProvider
{
IList<SequencePoint> GetSequencePoints(MethodDefinitionHandle method);
IList<Variable> GetVariables(MethodDefinitionHandle method);
bool TryGetName(MethodDefinitionHandle method, int index, out string name);
}
}

6
ICSharpCode.Decompiler/Pdb/PortablePdbWriter.cs → ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -17,7 +17,7 @@ using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.Pdb namespace ICSharpCode.Decompiler.DebugInfo
{ {
public class PortablePdbWriter public class PortablePdbWriter
{ {
@ -39,7 +39,7 @@ namespace ICSharpCode.Decompiler.Pdb
var hasher = SHA256.Create(); var hasher = SHA256.Create();
var sequencePointBlobs = new Dictionary<MethodDefinitionHandle, (DocumentHandle Document, BlobHandle SequencePoints)>(); var sequencePointBlobs = new Dictionary<MethodDefinitionHandle, (DocumentHandle Document, BlobHandle SequencePoints)>();
var importScopeBlobs = new Dictionary<MethodDefinitionHandle, (DocumentHandle Document, BlobHandle ImportScope)>(); var importScopeBlobs = new Dictionary<MethodDefinitionHandle, (DocumentHandle Document, BlobHandle ImportScope)>();
var emptyList = new List<Metadata.SequencePoint>(); var emptyList = new List<SequencePoint>();
foreach (var handle in reader.GetTopLevelTypeDefinitions()) { foreach (var handle in reader.GetTopLevelTypeDefinitions()) {
var type = reader.GetTypeDefinition(handle); var type = reader.GetTypeDefinition(handle);
@ -156,7 +156,7 @@ namespace ICSharpCode.Decompiler.Pdb
return metadata.GetOrAddBlob(writer); return metadata.GetOrAddBlob(writer);
} }
static BlobHandle EncodeSequencePoints(MetadataBuilder metadata, int localSignatureRowId, List<Metadata.SequencePoint> sequencePoints) static BlobHandle EncodeSequencePoints(MetadataBuilder metadata, int localSignatureRowId, List<SequencePoint> sequencePoints)
{ {
if (sequencePoints.Count == 0) if (sequencePoints.Count == 0)
return default; return default;

2
ICSharpCode.Decompiler/Metadata/SequencePoint.cs → ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs

@ -18,7 +18,7 @@
using System; using System;
namespace ICSharpCode.Decompiler.Metadata namespace ICSharpCode.Decompiler.DebugInfo
{ {
/// <summary> /// <summary>
/// A sequence point read from a PDB file or produced by the decompiler. /// A sequence point read from a PDB file or produced by the decompiler.

15
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -21,7 +21,7 @@ using System.Collections.Generic;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -51,7 +51,12 @@ namespace ICSharpCode.Decompiler.Disassembler
/// </summary> /// </summary>
public bool ShowMetadataTokens { get; set; } public bool ShowMetadataTokens { get; set; }
IList<Metadata.SequencePoint> sequencePoints; /// <summary>
/// Optional provider for sequence points.
/// </summary>
public IDebugInfoProvider DebugInfo { get; set; }
IList<DebugInfo.SequencePoint> sequencePoints;
int nextSequencePointIndex; int nextSequencePointIndex;
// cache info // cache info
@ -68,7 +73,7 @@ namespace ICSharpCode.Decompiler.Disassembler
public virtual void Disassemble(PEFile module, MethodDefinitionHandle handle) public virtual void Disassemble(PEFile module, MethodDefinitionHandle handle)
{ {
this.module = module; this.module = module ?? throw new ArgumentNullException(nameof(module));
metadata = module.Metadata; metadata = module.Metadata;
genericContext = new GenericContext(handle, module); genericContext = new GenericContext(handle, module);
signatureDecoder = new DisassemblerSignatureProvider(module, output); signatureDecoder = new DisassemblerSignatureProvider(module, output);
@ -94,7 +99,7 @@ namespace ICSharpCode.Decompiler.Disassembler
DisassembleLocalsBlock(body); DisassembleLocalsBlock(body);
output.WriteLine(); output.WriteLine();
sequencePoints = module.DebugInfo?.GetSequencePoints(handle) ?? EmptyList<Metadata.SequencePoint>.Instance; sequencePoints = DebugInfo?.GetSequencePoints(handle) ?? EmptyList<DebugInfo.SequencePoint>.Instance;
nextSequencePointIndex = 0; nextSequencePointIndex = 0;
if (DetectControlStructure && blob.Length > 0) { if (DetectControlStructure && blob.Length > 0) {
blob.Reset(); blob.Reset();
@ -278,7 +283,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
int offset = blob.Offset; int offset = blob.Offset;
if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) { if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) {
Metadata.SequencePoint sp = sequencePoints[nextSequencePointIndex]; var sp = sequencePoints[nextSequencePointIndex];
if (sp.Offset <= offset) { if (sp.Offset <= offset) {
output.Write("// sequence point: "); output.Write("// sequence point: ");
if (sp.Offset != offset) { if (sp.Offset != offset) {

125
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -27,6 +27,7 @@ using System.Threading;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.DebugInfo;
namespace ICSharpCode.Decompiler.Disassembler namespace ICSharpCode.Decompiler.Disassembler
{ {
@ -55,8 +56,15 @@ namespace ICSharpCode.Decompiler.Disassembler
set => methodBodyDisassembler.ShowMetadataTokens = value; set => methodBodyDisassembler.ShowMetadataTokens = value;
} }
public IDebugInfoProvider DebugInfo {
get => methodBodyDisassembler.DebugInfo;
set => methodBodyDisassembler.DebugInfo = value;
}
public bool ExpandMemberDefinitions { get; set; } = false; public bool ExpandMemberDefinitions { get; set; } = false;
public IAssemblyResolver AssemblyResolver { get; set; }
public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken) public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken)
: this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken) : this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken)
{ {
@ -362,59 +370,61 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(secdecl.Action.ToString()); output.Write(secdecl.Action.ToString());
break; break;
} }
output.WriteLine(" = {"); if (AssemblyResolver == null) {
output.Indent(); output.Write(" = ");
var blob = metadata.GetBlobReader(secdecl.PermissionSet); WriteBlob(secdecl.PermissionSet, metadata);
if ((char)blob.ReadByte() != '.') {
blob.Reset();
WriteXmlSecurityDeclaration(blob.ReadUTF8(blob.RemainingBytes));
} else { } else {
string currentAssemblyName = null; output.WriteLine(" = {");
string currentFullAssemblyName = null; output.Indent();
if (metadata.IsAssembly) { var blob = metadata.GetBlobReader(secdecl.PermissionSet);
currentAssemblyName = metadata.GetString(metadata.GetAssemblyDefinition().Name); if ((char)blob.ReadByte() != '.') {
currentFullAssemblyName = metadata.GetFullAssemblyName(); blob.Reset();
} WriteXmlSecurityDeclaration(blob.ReadUTF8(blob.RemainingBytes));
int count = blob.ReadCompressedInteger(); } else {
for (int i = 0; i < count; i++) { string currentAssemblyName = null;
var typeName = blob.ReadSerializedString(); string currentFullAssemblyName = null;
string[] nameParts = typeName.Split(new[] { ", " }, StringSplitOptions.None); if (metadata.IsAssembly) {
if (nameParts.Length < 2 || nameParts[1] == currentAssemblyName) { currentAssemblyName = metadata.GetString(metadata.GetAssemblyDefinition().Name);
output.Write("class "); currentFullAssemblyName = metadata.GetFullAssemblyName();
output.Write(DisassemblerHelpers.Escape(typeName + ", " + currentFullAssemblyName));
} else {
string[] typeNameParts = typeName.Split(new[] { ", " }, StringSplitOptions.None);
if (typeNameParts.Length < 2)
throw new NotImplementedException();
output.Write('[');
output.Write(typeNameParts[1]);
output.Write(']');
output.WriteReference(typeNameParts[0], null); // TODO : hyperlink!
} }
output.Write(" = {"); int count = blob.ReadCompressedInteger();
blob.ReadCompressedInteger(); // ? for (int i = 0; i < count; i++) {
// The specification seems to be incorrect here, so I'm using the logic from Cecil instead. var typeName = blob.ReadSerializedString();
int argCount = blob.ReadCompressedInteger(); string[] nameParts = typeName.Split(new[] { ", " }, StringSplitOptions.None);
if (argCount > 0) { if (nameParts.Length < 2 || nameParts[1] == currentAssemblyName) {
output.WriteLine(); output.Write("class ");
output.Indent(); output.Write(DisassemblerHelpers.Escape(typeName + ", " + currentFullAssemblyName));
} else {
for (int j = 0; j < argCount; j++) { output.Write('[');
WriteSecurityDeclarationArgument(module, ref blob); output.Write(nameParts[1]);
output.Write(']');
output.WriteReference(nameParts[0], null); // TODO : hyperlink!
}
output.Write(" = {");
blob.ReadCompressedInteger(); // ?
// The specification seems to be incorrect here, so I'm using the logic from Cecil instead.
int argCount = blob.ReadCompressedInteger();
if (argCount > 0) {
output.WriteLine(); output.WriteLine();
output.Indent();
for (int j = 0; j < argCount; j++) {
WriteSecurityDeclarationArgument(module, ref blob);
output.WriteLine();
}
output.Unindent();
} }
output.Write('}');
output.Unindent(); if (i + 1 < count)
output.Write(',');
output.WriteLine();
} }
output.Write('}');
if (i + 1 < count)
output.Write(',');
output.WriteLine();
} }
output.Unindent();
output.WriteLine("}");
} }
output.Unindent();
output.WriteLine("}");
} }
} }
@ -525,7 +535,7 @@ namespace ICSharpCode.Decompiler.Disassembler
PEFile containingModule = null; PEFile containingModule = null;
// if we deal with an assembly-qualified name, resolve the assembly // if we deal with an assembly-qualified name, resolve the assembly
if (nameParts.Length == 2) if (nameParts.Length == 2)
containingModule = module.AssemblyResolver.Resolve(AssemblyNameReference.Parse(nameParts[1])); containingModule = AssemblyResolver.Resolve(AssemblyNameReference.Parse(nameParts[1]));
if (containingModule != null) { if (containingModule != null) {
// try to find the type in the assembly // try to find the type in the assembly
var handle = FindType(containingModule, typeNameParts); var handle = FindType(containingModule, typeNameParts);
@ -539,7 +549,7 @@ namespace ICSharpCode.Decompiler.Disassembler
var handle = FindType(module, typeNameParts); var handle = FindType(module, typeNameParts);
if (handle.IsNil) { if (handle.IsNil) {
// otherwise try mscorlib // otherwise try mscorlib
var mscorlib = module.AssemblyResolver.Resolve(AssemblyNameReference.Parse("mscorlib")); var mscorlib = AssemblyResolver.Resolve(AssemblyNameReference.Parse("mscorlib"));
handle = FindType(mscorlib, typeNameParts); handle = FindType(mscorlib, typeNameParts);
if (handle.IsNil) if (handle.IsNil)
throw new NotImplementedException(); throw new NotImplementedException();
@ -1352,27 +1362,27 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(".custom "); output.Write(".custom ");
var attr = metadata.GetCustomAttribute(a); var attr = metadata.GetCustomAttribute(a);
attr.Constructor.WriteTo(module, output, GenericContext.Empty); attr.Constructor.WriteTo(module, output, GenericContext.Empty);
byte[] blob = metadata.GetBlobBytes(attr.Value); if (!attr.Value.IsNil) {
if (blob.Length > 0) {
output.Write(" = "); output.Write(" = ");
WriteBlob(blob); WriteBlob(attr.Value, metadata);
} }
output.WriteLine(); output.WriteLine();
} }
} }
void WriteBlob(byte[] blob) void WriteBlob(BlobHandle blob, MetadataReader metadata)
{ {
var reader = metadata.GetBlobReader(blob);
output.Write("("); output.Write("(");
output.Indent(); output.Indent();
for (int i = 0; i < blob.Length; i++) { for (int i = 0; i < reader.Length; i++) {
if (i % 16 == 0 && i < blob.Length - 1) { if (i % 16 == 0 && i < reader.Length - 1) {
output.WriteLine(); output.WriteLine();
} else { } else {
output.Write(' '); output.Write(' ');
} }
output.Write(blob[i].ToString("x2")); output.Write(reader.ReadByte().ToString("x2"));
} }
output.WriteLine(); output.WriteLine();
@ -1484,10 +1494,9 @@ namespace ICSharpCode.Decompiler.Disassembler
OpenBlock(false); OpenBlock(false);
WriteAttributes(module, asm.GetCustomAttributes()); WriteAttributes(module, asm.GetCustomAttributes());
WriteSecurityDeclarations(module, asm.GetDeclarativeSecurityAttributes()); WriteSecurityDeclarations(module, asm.GetDeclarativeSecurityAttributes());
var publicKey = metadata.GetBlobBytes(asm.PublicKey); if (!asm.PublicKey.IsNil) {
if (publicKey.Length > 0) {
output.Write(".publickey = "); output.Write(".publickey = ");
WriteBlob(publicKey); WriteBlob(asm.PublicKey, metadata);
output.WriteLine(); output.WriteLine();
} }
if (asm.HashAlgorithm != AssemblyHashAlgorithm.None) { if (asm.HashAlgorithm != AssemblyHashAlgorithm.None) {
@ -1518,7 +1527,7 @@ namespace ICSharpCode.Decompiler.Disassembler
OpenBlock(false); OpenBlock(false);
if (!aref.PublicKeyOrToken.IsNil) { if (!aref.PublicKeyOrToken.IsNil) {
output.Write(".publickeytoken = "); output.Write(".publickeytoken = ");
WriteBlob(metadata.GetBlobBytes(aref.PublicKeyOrToken)); WriteBlob(aref.PublicKeyOrToken, metadata);
output.WriteLine(); output.WriteLine();
} }
if (aref.Version != null) { if (aref.Version != null) {

20
ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs

@ -23,9 +23,15 @@ using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Documentation namespace ICSharpCode.Decompiler.Documentation
{ {
public interface IDocumentationProvider
{
string GetDocumentation(IEntity entity);
}
/// <summary> /// <summary>
/// Provides documentation from an .xml file (as generated by the Microsoft C# compiler). /// Provides documentation from an .xml file (as generated by the Microsoft C# compiler).
/// </summary> /// </summary>
@ -36,7 +42,7 @@ namespace ICSharpCode.Decompiler.Documentation
/// If the .xml file is changed, the index will automatically be recreated. /// If the .xml file is changed, the index will automatically be recreated.
/// </remarks> /// </remarks>
[Serializable] [Serializable]
public class XmlDocumentationProvider : IDeserializationCallback public class XmlDocumentationProvider : IDeserializationCallback, IDocumentationProvider
{ {
#region Cache #region Cache
sealed class XmlDocumentationCache sealed class XmlDocumentationCache
@ -316,7 +322,17 @@ namespace ICSharpCode.Decompiler.Documentation
throw new ArgumentNullException("key"); throw new ArgumentNullException("key");
return GetDocumentation(key, true); return GetDocumentation(key, true);
} }
/// <summary>
/// Get the documentation for the specified member.
/// </summary>
public string GetDocumentation(IEntity entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));
return GetDocumentation(XmlDocKeyProvider.GetKey(entity));
}
string GetDocumentation(string key, bool allowReload) string GetDocumentation(string key, bool allowReload)
{ {
int hashcode = GetHashCode(key); int hashcode = GetHashCode(key);

5
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -306,7 +306,7 @@
<Compile Include="IL\Instructions\LdFlda.cs" /> <Compile Include="IL\Instructions\LdFlda.cs" />
<Compile Include="IL\Instructions\NullableInstructions.cs" /> <Compile Include="IL\Instructions\NullableInstructions.cs" />
<Compile Include="IL\Instructions\StLoc.cs" /> <Compile Include="IL\Instructions\StLoc.cs" />
<Compile Include="Metadata\SequencePoint.cs" /> <Compile Include="DebugInfo\SequencePoint.cs" />
<Compile Include="IL\Instructions\CallIndirect.cs" /> <Compile Include="IL\Instructions\CallIndirect.cs" />
<Compile Include="IL\Instructions\DefaultValue.cs" /> <Compile Include="IL\Instructions\DefaultValue.cs" />
<Compile Include="IL\Transforms\DynamicCallSiteTransform.cs" /> <Compile Include="IL\Transforms\DynamicCallSiteTransform.cs" />
@ -342,7 +342,8 @@
<Compile Include="IL\Transforms\StatementTransform.cs" /> <Compile Include="IL\Transforms\StatementTransform.cs" />
<Compile Include="IL\Transforms\TransformCollectionAndObjectInitializers.cs" /> <Compile Include="IL\Transforms\TransformCollectionAndObjectInitializers.cs" />
<Compile Include="Output\TextTokenWriter.cs" /> <Compile Include="Output\TextTokenWriter.cs" />
<Compile Include="Pdb\PortablePdbWriter.cs" /> <Compile Include="DebugInfo\IDebugInfoProvider.cs" />
<Compile Include="DebugInfo\PortablePdbWriter.cs" />
<Compile Include="SRMExtensions.cs" /> <Compile Include="SRMExtensions.cs" />
<Compile Include="SRMHacks.cs" /> <Compile Include="SRMHacks.cs" />
<Compile Include="TypeSystem\ApplyAttributeTypeVisitor.cs" /> <Compile Include="TypeSystem\ApplyAttributeTypeVisitor.cs" />

6
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -384,9 +384,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
) )
); );
} }
var il = new ILReader(typeSystem).ReadIL(typeSystem.ModuleDefinition, method, typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), context.CancellationToken); var body = typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
var il = context.CreateILReader(typeSystem)
.ReadIL(typeSystem.ModuleDefinition, method, body, context.CancellationToken);
il.RunTransforms(CSharpDecompiler.EarlyILTransforms(true), il.RunTransforms(CSharpDecompiler.EarlyILTransforms(true),
new ILTransformContext(il, typeSystem, context.Settings) { new ILTransformContext(il, typeSystem, context.DebugInfo, context.Settings) {
CancellationToken = context.CancellationToken, CancellationToken = context.CancellationToken,
DecompileRun = context.DecompileRun DecompileRun = context.DecompileRun
}); });

8
ICSharpCode.Decompiler/IL/ILReader.cs

@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.IL
readonly IDecompilerTypeSystem typeSystem; readonly IDecompilerTypeSystem typeSystem;
public bool UseDebugSymbols { get; set; } public bool UseDebugSymbols { get; set; }
public DebugInfo.IDebugInfoProvider DebugInfo { get; set; }
public List<string> Warnings { get; } = new List<string>(); public List<string> Warnings { get; } = new List<string>();
public ILReader(IDecompilerTypeSystem typeSystem) public ILReader(IDecompilerTypeSystem typeSystem)
@ -53,7 +54,6 @@ namespace ICSharpCode.Decompiler.IL
MetadataReader metadata; MetadataReader metadata;
IMethod method; IMethod method;
MethodBodyBlock body; MethodBodyBlock body;
Metadata.IDebugInfoProvider debugInfo;
StackType methodReturnStackType; StackType methodReturnStackType;
BlobReader reader; BlobReader reader;
ImmutableStack<ILVariable> currentStack; ImmutableStack<ILVariable> currentStack;
@ -79,7 +79,6 @@ namespace ICSharpCode.Decompiler.IL
var methodDefinition = metadata.GetMethodDefinition(methodDefinitionHandle); var methodDefinition = metadata.GetMethodDefinition(methodDefinitionHandle);
this.body = body; this.body = body;
this.reader = body.GetILReader(); this.reader = body.GetILReader();
this.debugInfo = module.DebugInfo;
this.currentStack = ImmutableStack<ILVariable>.Empty; this.currentStack = ImmutableStack<ILVariable>.Empty;
this.unionFind = new UnionFind<ILVariable>(); this.unionFind = new UnionFind<ILVariable>();
this.stackMismatchPairs = new List<(ILVariable, ILVariable)>(); this.stackMismatchPairs = new List<(ILVariable, ILVariable)>();
@ -177,7 +176,7 @@ namespace ICSharpCode.Decompiler.IL
kind = VariableKind.Local; kind = VariableKind.Local;
} }
ILVariable ilVar = new ILVariable(kind, type, index); ILVariable ilVar = new ILVariable(kind, type, index);
if (!UseDebugSymbols || debugInfo == null || !debugInfo.TryGetName((MethodDefinitionHandle)method.MetadataToken, index, out string name)) { if (!UseDebugSymbols || DebugInfo == null || !DebugInfo.TryGetName((MethodDefinitionHandle)method.MetadataToken, index, out string name)) {
ilVar.Name = "V_" + index; ilVar.Name = "V_" + index;
ilVar.HasGeneratedName = true; ilVar.HasGeneratedName = true;
} else if (string.IsNullOrWhiteSpace(name)) { } else if (string.IsNullOrWhiteSpace(name)) {
@ -410,7 +409,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Debugging helper: writes the decoded instruction stream interleaved with the inferred evaluation stack layout. /// Debugging helper: writes the decoded instruction stream interleaved with the inferred evaluation stack layout.
/// </summary> /// </summary>
public void WriteTypedIL(Metadata.PEFile module, MethodDefinitionHandle method, MethodBodyBlock body, ITextOutput output, CancellationToken cancellationToken = default(CancellationToken)) public void WriteTypedIL(Metadata.PEFile module,
MethodDefinitionHandle method, MethodBodyBlock body, ITextOutput output, CancellationToken cancellationToken = default)
{ {
Init(module, method, body); Init(module, method, body);
ReadInstructions(cancellationToken); ReadInstructions(cancellationToken);

5
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -145,8 +145,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!methodDefinition.HasBody()) if (!methodDefinition.HasBody())
return null; return null;
var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(targetMethod.Substitution); var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(targetMethod.Substitution);
var ilReader = new ILReader(localTypeSystem); var ilReader = context.CreateILReader(localTypeSystem);
ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols;
var function = ilReader.ReadIL(context.TypeSystem.ModuleDefinition, (MethodDefinitionHandle)targetMethod.MetadataToken, context.TypeSystem.ModuleDefinition.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress), context.CancellationToken); var function = ilReader.ReadIL(context.TypeSystem.ModuleDefinition, (MethodDefinitionHandle)targetMethod.MetadataToken, context.TypeSystem.ModuleDefinition.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress), context.CancellationToken);
function.DelegateType = value.Method.DeclaringType; function.DelegateType = value.Method.DeclaringType;
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal);
@ -156,7 +155,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
v.Name = contextPrefix + v.Name; v.Name = contextPrefix + v.Name;
} }
var nestedContext = new ILTransformContext(function, localTypeSystem, context.Settings) { var nestedContext = new ILTransformContext(function, localTypeSystem, context.DebugInfo, context.Settings) {
CancellationToken = context.CancellationToken, CancellationToken = context.CancellationToken,
DecompileRun = context.DecompileRun DecompileRun = context.DecompileRun
}; };

16
ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs

@ -22,6 +22,7 @@ using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.CSharp.TypeSystem; using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -42,6 +43,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
public ILFunction Function { get; } public ILFunction Function { get; }
public IDecompilerTypeSystem TypeSystem { get; } public IDecompilerTypeSystem TypeSystem { get; }
public IDebugInfoProvider DebugInfo { get; }
public DecompilerSettings Settings { get; } public DecompilerSettings Settings { get; }
public CancellationToken CancellationToken { get; set; } public CancellationToken CancellationToken { get; set; }
public Stepper Stepper { get; set; } public Stepper Stepper { get; set; }
@ -49,11 +51,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
internal DecompileRun DecompileRun { get; set; } internal DecompileRun DecompileRun { get; set; }
internal ResolvedUsingScope UsingScope => DecompileRun.UsingScope.Resolve(TypeSystem.Compilation); internal ResolvedUsingScope UsingScope => DecompileRun.UsingScope.Resolve(TypeSystem.Compilation);
public ILTransformContext(ILFunction function, IDecompilerTypeSystem typeSystem, DecompilerSettings settings = null) public ILTransformContext(ILFunction function, IDecompilerTypeSystem typeSystem, IDebugInfoProvider debugInfo, DecompilerSettings settings = null)
{ {
this.Function = function ?? throw new ArgumentNullException(nameof(function)); this.Function = function ?? throw new ArgumentNullException(nameof(function));
this.TypeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem)); this.TypeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem));
this.Settings = settings ?? new DecompilerSettings(); this.Settings = settings ?? new DecompilerSettings();
this.DebugInfo = debugInfo;
Stepper = new Stepper(); Stepper = new Stepper();
} }
@ -61,12 +64,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
this.Function = context.Function; this.Function = context.Function;
this.TypeSystem = context.TypeSystem; this.TypeSystem = context.TypeSystem;
this.DebugInfo = context.DebugInfo;
this.Settings = context.Settings; this.Settings = context.Settings;
this.DecompileRun = context.DecompileRun; this.DecompileRun = context.DecompileRun;
this.CancellationToken = context.CancellationToken; this.CancellationToken = context.CancellationToken;
this.Stepper = context.Stepper; this.Stepper = context.Stepper;
} }
public ILReader CreateILReader(IDecompilerTypeSystem typeSystem = null)
{
if (typeSystem == null)
typeSystem = this.TypeSystem;
return new ILReader(typeSystem) {
UseDebugSymbols = Settings.UseDebugSymbols,
DebugInfo = DebugInfo
};
}
/// <summary> /// <summary>
/// Call this method immediately before performing a transform step. /// Call this method immediately before performing a transform step.
/// Unlike <c>context.Stepper.Step()</c>, calls to this method are only compiled in debug builds. /// Unlike <c>context.Stepper.Step()</c>, calls to this method are only compiled in debug builds.

18
ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs

@ -31,20 +31,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return; return;
// partially copied from CSharpDecompiler // partially copied from CSharpDecompiler
var specializingTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(inst.Method.Substitution); var specializingTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(inst.Method.Substitution);
var ilReader = new ILReader(specializingTypeSystem); var ilReader = context.CreateILReader(specializingTypeSystem);
System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken(); var body = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
var proxyFunction = ilReader.ReadIL(module, handle, module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), cancellationToken); var proxyFunction = ilReader.ReadIL(module, handle, body, context.CancellationToken);
var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, context.Settings) { var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, context.DebugInfo, context.Settings) {
CancellationToken = cancellationToken, CancellationToken = context.CancellationToken,
DecompileRun = context.DecompileRun DecompileRun = context.DecompileRun
}; };
foreach (var transform in CSharp.CSharpDecompiler.GetILTransforms()) { proxyFunction.RunTransforms(CSharp.CSharpDecompiler.EarlyILTransforms(), transformContext);
if (transform.GetType() != typeof(ProxyCallReplacer)) { // don't call itself on itself
cancellationToken.ThrowIfCancellationRequested();
transform.Run(proxyFunction, transformContext);
}
}
if (!(proxyFunction.Body is BlockContainer blockContainer)) if (!(proxyFunction.Body is BlockContainer blockContainer))
return; return;
if (blockContainer.Blocks.Count != 1) if (blockContainer.Blocks.Count != 1)

17
ICSharpCode.Decompiler/Metadata/Dom.cs

@ -15,23 +15,6 @@ using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.Metadata namespace ICSharpCode.Decompiler.Metadata
{ {
public interface IAssemblyDocumentationResolver
{
XmlDocumentationProvider GetProvider();
}
public struct Variable
{
public string Name { get; set; }
}
public interface IDebugInfoProvider
{
IList<SequencePoint> GetSequencePoints(MethodDefinitionHandle method);
IList<Variable> GetVariables(MethodDefinitionHandle method);
bool TryGetName(MethodDefinitionHandle method, int index, out string name);
}
public enum TargetRuntime public enum TargetRuntime
{ {
Unknown, Unknown,

14
ICSharpCode.Decompiler/Metadata/MetadataResolver.cs

@ -40,18 +40,18 @@ namespace ICSharpCode.Decompiler.Metadata
readonly IAssemblyResolver assemblyResolver; readonly IAssemblyResolver assemblyResolver;
readonly Dictionary<IAssemblyReference, PEFile> loadedModules; readonly Dictionary<IAssemblyReference, PEFile> loadedModules;
public SimpleMetadataResolveContext(PEFile mainModule) public SimpleMetadataResolveContext(PEFile mainModule, IAssemblyResolver assemblyResolver)
{ {
this.mainModule = mainModule; this.mainModule = mainModule ?? throw new ArgumentNullException(nameof(mainModule));
this.assemblyResolver = mainModule.AssemblyResolver; this.assemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver));
this.loadedModules = new Dictionary<IAssemblyReference, PEFile>(); this.loadedModules = new Dictionary<IAssemblyReference, PEFile>();
} }
public SimpleMetadataResolveContext(PEFile mainModule, IMetadataResolveContext parentContext) public SimpleMetadataResolveContext(PEFile mainModule, SimpleMetadataResolveContext parentContext)
{ {
this.mainModule = mainModule; this.mainModule = mainModule ?? throw new ArgumentNullException(nameof(mainModule));
this.assemblyResolver = mainModule.AssemblyResolver; this.assemblyResolver = parentContext.assemblyResolver;
this.loadedModules = parentContext is SimpleMetadataResolveContext simple ? simple.loadedModules : new Dictionary<IAssemblyReference, PEFile>(); this.loadedModules = parentContext.loadedModules;
} }
public PEFile CurrentModule => mainModule; public PEFile CurrentModule => mainModule;

19
ICSharpCode.Decompiler/Metadata/PEFile.cs

@ -33,24 +33,17 @@ namespace ICSharpCode.Decompiler.Metadata
public string FileName { get; } public string FileName { get; }
public PEReader Reader { get; } public PEReader Reader { get; }
public MetadataReader Metadata { get; } public MetadataReader Metadata { get; }
public IAssemblyResolver AssemblyResolver { get; }
public IAssemblyDocumentationResolver DocumentationResolver { get; set; }
public IDebugInfoProvider DebugInfo { get; set; }
public PEFile(string fileName, Stream stream, bool throwOnResolveError = false, PEStreamOptions options = PEStreamOptions.Default) public PEFile(string fileName, Stream stream, PEStreamOptions options = PEStreamOptions.Default)
: this(fileName, new PEReader(stream, options))
{ {
this.FileName = fileName;
this.Reader = new PEReader(stream, options);
this.Metadata = Reader.GetMetadataReader();
this.AssemblyResolver = new UniversalAssemblyResolver(fileName, throwOnResolveError, Reader.DetectTargetFrameworkId(), options);
} }
public PEFile(string fileName, Stream stream, IAssemblyResolver assemblyResolver, PEStreamOptions options = PEStreamOptions.Default) public PEFile(string fileName, PEReader reader)
{ {
this.FileName = fileName; this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
this.Reader = new PEReader(stream, options); this.Reader = reader ?? throw new ArgumentNullException(nameof(reader));
this.Metadata = Reader.GetMetadataReader(); this.Metadata = reader.GetMetadataReader();
this.AssemblyResolver = assemblyResolver;
} }
public bool IsAssembly => Metadata.IsAssembly; public bool IsAssembly => Metadata.IsAssembly;

2
ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs

@ -90,7 +90,7 @@ namespace ICSharpCode.Decompiler.Metadata
throw new AssemblyResolutionException(name); throw new AssemblyResolutionException(name);
return null; return null;
} }
return new PEFile(file, new FileStream(file, FileMode.Open, FileAccess.Read), this, options); return new PEFile(file, new FileStream(file, FileMode.Open, FileAccess.Read), options);
} }
public string FindAssemblyFile(IAssemblyReference name) public string FindAssemblyFile(IAssemblyReference name)

12
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -26,6 +26,7 @@ using ICSharpCode.Decompiler.Util;
using static ICSharpCode.Decompiler.Metadata.MetadataExtensions; using static ICSharpCode.Decompiler.Metadata.MetadataExtensions;
using System.Diagnostics; using System.Diagnostics;
using System.Collections.Immutable; using System.Collections.Immutable;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.TypeSystem namespace ICSharpCode.Decompiler.TypeSystem
{ {
@ -77,18 +78,21 @@ namespace ICSharpCode.Decompiler.TypeSystem
{ {
readonly Metadata.PEFile moduleDefinition; readonly Metadata.PEFile moduleDefinition;
readonly ICompilation compilation; readonly ICompilation compilation;
readonly IAssemblyResolver assemblyResolver;
readonly TypeSystemOptions typeSystemOptions; readonly TypeSystemOptions typeSystemOptions;
readonly MetadataAssembly mainAssembly; readonly MetadataAssembly mainAssembly;
public DecompilerTypeSystem(Metadata.PEFile moduleDefinition) : this(moduleDefinition, new DecompilerSettings()) public DecompilerTypeSystem(Metadata.PEFile moduleDefinition, IAssemblyResolver assemblyResolver)
: this(moduleDefinition, assemblyResolver, new DecompilerSettings())
{ {
} }
public DecompilerTypeSystem(Metadata.PEFile moduleDefinition, DecompilerSettings settings) public DecompilerTypeSystem(PEFile moduleDefinition, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
{ {
if (settings == null) if (settings == null)
throw new ArgumentNullException(nameof(settings)); throw new ArgumentNullException(nameof(settings));
this.moduleDefinition = moduleDefinition; this.moduleDefinition = moduleDefinition ?? throw new ArgumentNullException(nameof(moduleDefinition));
this.assemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver));
typeSystemOptions = TypeSystemOptions.None; typeSystemOptions = TypeSystemOptions.None;
if (settings.Dynamic) if (settings.Dynamic)
typeSystemOptions |= TypeSystemOptions.Dynamic; typeSystemOptions |= TypeSystemOptions.Dynamic;
@ -106,7 +110,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
var asmRef = assemblyReferenceQueue.Dequeue(); var asmRef = assemblyReferenceQueue.Dequeue();
if (!processedAssemblyReferences.Add(asmRef)) if (!processedAssemblyReferences.Add(asmRef))
continue; continue;
var asm = moduleDefinition.AssemblyResolver.Resolve(asmRef); var asm = assemblyResolver.Resolve(asmRef);
if (asm != null) { if (asm != null) {
referencedAssemblies.Add(asm.WithOptions(typeSystemOptions)); referencedAssemblies.Add(asm.WithOptions(typeSystemOptions));
var metadata = asm.Metadata; var metadata = asm.Metadata;

6
ICSharpCode.Decompiler/TypeSystem/IAssembly.cs

@ -18,6 +18,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.TypeSystem namespace ICSharpCode.Decompiler.TypeSystem
{ {
@ -65,6 +66,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
public interface IAssembly : ICompilationProvider public interface IAssembly : ICompilationProvider
{ {
/// <summary>
/// Gets the underlying metadata file. May return null, if the IAssembly was not created from a PE file.
/// </summary>
PEFile PEFile { get; }
/// <summary> /// <summary>
/// Gets whether this assembly is the main assembly of the compilation. /// Gets whether this assembly is the main assembly of the compilation.
/// </summary> /// </summary>

2
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs

@ -329,6 +329,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.AssemblyAttributes = unresolved.AssemblyAttributes.CreateResolvedAttributes(context); this.AssemblyAttributes = unresolved.AssemblyAttributes.CreateResolvedAttributes(context);
this.ModuleAttributes = unresolved.ModuleAttributes.CreateResolvedAttributes(context); this.ModuleAttributes = unresolved.ModuleAttributes.CreateResolvedAttributes(context);
} }
public Metadata.PEFile PEFile => null;
public IUnresolvedAssembly UnresolvedAssembly { public IUnresolvedAssembly UnresolvedAssembly {
get { return unresolvedAssembly; } get { return unresolvedAssembly; }

3
ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs

@ -38,7 +38,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
public class MetadataAssembly : IAssembly public class MetadataAssembly : IAssembly
{ {
public ICompilation Compilation { get; } public ICompilation Compilation { get; }
public readonly Metadata.PEFile PEFile;
internal readonly MetadataReader metadata; internal readonly MetadataReader metadata;
readonly TypeSystemOptions options; readonly TypeSystemOptions options;
internal readonly TypeProvider TypeProvider; internal readonly TypeProvider TypeProvider;
@ -86,6 +85,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
public TypeSystemOptions TypeSystemOptions => options; public TypeSystemOptions TypeSystemOptions => options;
#region IAssembly interface #region IAssembly interface
public PEFile PEFile { get; }
public bool IsMainAssembly => this == Compilation.MainAssembly; public bool IsMainAssembly => this == Compilation.MainAssembly;
public string AssemblyName { get; } public string AssemblyName { get; }

4
ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs

@ -114,13 +114,13 @@ namespace ILSpy.BamlDecompiler.Tests
{ {
using (var fileStream = new FileStream(asmPath, FileMode.Open, FileAccess.Read)) { using (var fileStream = new FileStream(asmPath, FileMode.Open, FileAccess.Read)) {
var module = new PEFile(asmPath, fileStream); var module = new PEFile(asmPath, fileStream);
var resolver = (UniversalAssemblyResolver)module.AssemblyResolver; var resolver = new UniversalAssemblyResolver(asmPath, false, module.Reader.DetectTargetFrameworkId());
resolver.RemoveSearchDirectory("."); resolver.RemoveSearchDirectory(".");
resolver.AddSearchDirectory(Path.GetDirectoryName(asmPath)); resolver.AddSearchDirectory(Path.GetDirectoryName(asmPath));
var res = module.Resources.First(); var res = module.Resources.First();
Stream bamlStream = LoadBaml(res, name + ".baml"); Stream bamlStream = LoadBaml(res, name + ".baml");
Assert.IsNotNull(bamlStream); Assert.IsNotNull(bamlStream);
XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, bamlStream, CancellationToken.None); XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, resolver, bamlStream, CancellationToken.None);
XamlIsEqual(File.ReadAllText(sourcePath), document.ToString()); XamlIsEqual(File.ReadAllText(sourcePath), document.ToString());
} }

14
ILSpy.BamlDecompiler/BamlResourceEntryNode.cs

@ -50,30 +50,32 @@ namespace ILSpy.BamlDecompiler
{ {
var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly; var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly;
Data.Position = 0; Data.Position = 0;
XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), Data, cancellationToken); XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), asm.GetAssemblyResolver(), Data, cancellationToken);
output.Write(xamlDocument.ToString()); output.Write(xamlDocument.ToString());
return true; return true;
} }
internal static XDocument LoadIntoDocument(PEFile module, Stream stream, CancellationToken cancellationToken) internal static XDocument LoadIntoDocument(PEFile module, IAssemblyResolver assemblyResolver,
Stream stream, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
XDocument xamlDocument; XDocument xamlDocument;
using (XmlBamlReader reader = new XmlBamlReader(stream, new NRTypeResolver(module))) { using (XmlBamlReader reader = new XmlBamlReader(stream, new NRTypeResolver(module, assemblyResolver))) {
xamlDocument = XDocument.Load(reader); xamlDocument = XDocument.Load(reader);
ConvertConnectionIds(xamlDocument, module, cancellationToken); ConvertConnectionIds(xamlDocument, module, assemblyResolver, cancellationToken);
ConvertToEmptyElements(xamlDocument.Root); ConvertToEmptyElements(xamlDocument.Root);
MoveNamespacesToRoot(xamlDocument, reader.XmlnsDefinitions); MoveNamespacesToRoot(xamlDocument, reader.XmlnsDefinitions);
return xamlDocument; return xamlDocument;
} }
} }
static void ConvertConnectionIds(XDocument xamlDocument, PEFile asm, CancellationToken cancellationToken) static void ConvertConnectionIds(XDocument xamlDocument, PEFile asm, IAssemblyResolver assemblyResolver,
CancellationToken cancellationToken)
{ {
var attr = xamlDocument.Root.Attribute(XName.Get("Class", XmlBamlReader.XWPFNamespace)); var attr = xamlDocument.Root.Attribute(XName.Get("Class", XmlBamlReader.XWPFNamespace));
if (attr != null) { if (attr != null) {
string fullTypeName = attr.Value; string fullTypeName = attr.Value;
var mappings = new ConnectMethodDecompiler().DecompileEventMappings(asm, fullTypeName, cancellationToken); var mappings = new ConnectMethodDecompiler().DecompileEventMappings(asm, assemblyResolver, fullTypeName, cancellationToken);
RemoveConnectionIds(xamlDocument.Root, mappings); RemoveConnectionIds(xamlDocument.Root, mappings);
} }
} }

2
ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs

@ -36,7 +36,7 @@ namespace ILSpy.BamlDecompiler
public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options) public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options)
{ {
var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetPEFileOrNull(), stream, options.CancellationToken); var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver(), stream, options.CancellationToken);
fileName = Path.ChangeExtension(fileName, ".xaml"); fileName = Path.ChangeExtension(fileName, ".xaml");
document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName)); document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName));
return fileName; return fileName;

7
ILSpy.BamlDecompiler/CecilTypeResolver.cs

@ -4,6 +4,7 @@
using System; using System;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy;
using Ricciolo.StylesExplorer.MarkupReflection; using Ricciolo.StylesExplorer.MarkupReflection;
namespace ILSpy.BamlDecompiler namespace ILSpy.BamlDecompiler
@ -17,10 +18,10 @@ namespace ILSpy.BamlDecompiler
readonly DecompilerTypeSystem typeSystem; readonly DecompilerTypeSystem typeSystem;
readonly ICompilation compilation; readonly ICompilation compilation;
public NRTypeResolver(PEFile module) public NRTypeResolver(PEFile module, IAssemblyResolver resolver)
{ {
this.module = module; this.module = module ?? throw new ArgumentNullException(nameof(module));
this.typeSystem = new DecompilerTypeSystem(module); this.typeSystem = new DecompilerTypeSystem(module, resolver);
this.compilation = typeSystem.Compilation; this.compilation = typeSystem.Compilation;
} }

8
ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs

@ -9,9 +9,11 @@ using System.Threading;
using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy;
using Metadata = ICSharpCode.Decompiler.Metadata; using Metadata = ICSharpCode.Decompiler.Metadata;
namespace ILSpy.BamlDecompiler namespace ILSpy.BamlDecompiler
@ -29,11 +31,11 @@ namespace ILSpy.BamlDecompiler
/// </summary> /// </summary>
sealed class ConnectMethodDecompiler sealed class ConnectMethodDecompiler
{ {
public List<(LongSet, EventRegistration[])> DecompileEventMappings(Metadata.PEFile module, public List<(LongSet, EventRegistration[])> DecompileEventMappings(Metadata.PEFile module, IAssemblyResolver assemblyResolver,
string fullTypeName, CancellationToken cancellationToken) string fullTypeName, CancellationToken cancellationToken)
{ {
var result = new List<(LongSet, EventRegistration[])>(); var result = new List<(LongSet, EventRegistration[])>();
var typeSystem = new DecompilerTypeSystem(module); var typeSystem = new DecompilerTypeSystem(module, assemblyResolver);
var typeDefinition = typeSystem.Compilation.FindType(new FullTypeName(fullTypeName)).GetDefinition(); var typeDefinition = typeSystem.Compilation.FindType(new FullTypeName(fullTypeName)).GetDefinition();
if (typeDefinition == null) if (typeDefinition == null)
@ -58,7 +60,7 @@ namespace ILSpy.BamlDecompiler
var function = ilReader.ReadIL(module, (MethodDefinitionHandle)method.MetadataToken, var function = ilReader.ReadIL(module, (MethodDefinitionHandle)method.MetadataToken,
module.Reader.GetMethodBody(metadataEntry.RelativeVirtualAddress), cancellationToken); module.Reader.GetMethodBody(metadataEntry.RelativeVirtualAddress), cancellationToken);
var context = new ILTransformContext(function, typeSystem) { var context = new ILTransformContext(function, typeSystem, null) {
CancellationToken = cancellationToken CancellationToken = cancellationToken
}; };
function.RunTransforms(CSharpDecompiler.GetILTransforms(), context); function.RunTransforms(CSharpDecompiler.GetILTransforms(), context);

9
ILSpy/DebugInfo/DiaSymNativeDebugInfoProvider.cs

@ -25,6 +25,7 @@ using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using Microsoft.DiaSymReader; using Microsoft.DiaSymReader;
@ -48,12 +49,12 @@ namespace ICSharpCode.ILSpy.DebugInfo
this.reader = SymUnmanagedReaderFactory.CreateReader<ISymUnmanagedReader5>(stream, this); this.reader = SymUnmanagedReaderFactory.CreateReader<ISymUnmanagedReader5>(stream, this);
} }
public IList<Decompiler.Metadata.SequencePoint> GetSequencePoints(MethodDefinitionHandle handle) public IList<Decompiler.DebugInfo.SequencePoint> GetSequencePoints(MethodDefinitionHandle handle)
{ {
var method = reader.GetMethod(MetadataTokens.GetToken(handle)); var method = reader.GetMethod(MetadataTokens.GetToken(handle));
if (method == null || method.GetSequencePointCount(out int count) != 0) if (method == null || method.GetSequencePointCount(out int count) != 0)
return Empty<Decompiler.Metadata.SequencePoint>.Array; return Empty<Decompiler.DebugInfo.SequencePoint>.Array;
var sequencePoints = new Decompiler.Metadata.SequencePoint[count]; var sequencePoints = new Decompiler.DebugInfo.SequencePoint[count];
var points = method.GetSequencePoints(); var points = method.GetSequencePoints();
int i = 0; int i = 0;
var buffer = new char[1024]; var buffer = new char[1024];
@ -64,7 +65,7 @@ namespace ICSharpCode.ILSpy.DebugInfo
} else { } else {
url = ""; url = "";
} }
sequencePoints[i] = new Decompiler.Metadata.SequencePoint() { sequencePoints[i] = new Decompiler.DebugInfo.SequencePoint() {
Offset = point.Offset, Offset = point.Offset,
StartLine = point.StartLine, StartLine = point.StartLine,
StartColumn = point.StartColumn, StartColumn = point.StartColumn,

7
ILSpy/DebugInfo/PortableDebugInfoProvider.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.DebugInfo namespace ICSharpCode.ILSpy.DebugInfo
@ -34,11 +35,11 @@ namespace ICSharpCode.ILSpy.DebugInfo
this.provider = provider; this.provider = provider;
} }
public IList<Decompiler.Metadata.SequencePoint> GetSequencePoints(MethodDefinitionHandle method) public IList<Decompiler.DebugInfo.SequencePoint> GetSequencePoints(MethodDefinitionHandle method)
{ {
var metadata = provider.GetMetadataReader(); var metadata = provider.GetMetadataReader();
var debugInfo = metadata.GetMethodDebugInformation(method); var debugInfo = metadata.GetMethodDebugInformation(method);
var sequencePoints = new List<Decompiler.Metadata.SequencePoint>(); var sequencePoints = new List<Decompiler.DebugInfo.SequencePoint>();
foreach (var point in debugInfo.GetSequencePoints()) { foreach (var point in debugInfo.GetSequencePoints()) {
string documentFileName; string documentFileName;
@ -50,7 +51,7 @@ namespace ICSharpCode.ILSpy.DebugInfo
documentFileName = ""; documentFileName = "";
} }
sequencePoints.Add(new Decompiler.Metadata.SequencePoint() { sequencePoints.Add(new Decompiler.DebugInfo.SequencePoint() {
Offset = point.Offset, Offset = point.Offset,
StartLine = point.StartLine, StartLine = point.StartLine,
StartColumn = point.StartColumn, StartColumn = point.StartColumn,

2
ILSpy/ILSpy.csproj

@ -120,6 +120,7 @@
<Compile Include="GacInterop.cs" /> <Compile Include="GacInterop.cs" />
<Compile Include="GuessFileType.cs" /> <Compile Include="GuessFileType.cs" />
<Compile Include="ContextMenuEntry.cs" /> <Compile Include="ContextMenuEntry.cs" />
<Compile Include="Languages\CSharpLanguage.cs" />
<Compile Include="Languages\CSharpLexer.cs" /> <Compile Include="Languages\CSharpLexer.cs" />
<Compile Include="Languages\CSharpHighlightingTokenWriter.cs" /> <Compile Include="Languages\CSharpHighlightingTokenWriter.cs" />
<Compile Include="ILSpySettings.cs" /> <Compile Include="ILSpySettings.cs" />
@ -135,6 +136,7 @@
<Compile Include="Languages\Language.cs" /> <Compile Include="Languages\Language.cs" />
<Compile Include="Languages\Languages.cs" /> <Compile Include="Languages\Languages.cs" />
<Compile Include="LoadedAssembly.cs" /> <Compile Include="LoadedAssembly.cs" />
<Compile Include="LoadedAssemblyExtensions.cs" />
<Compile Include="LoadedNugetPackage.cs" /> <Compile Include="LoadedNugetPackage.cs" />
<Compile Include="NativeMethods.cs" /> <Compile Include="NativeMethods.cs" />
<Compile Include="NavigationHistory.cs" /> <Compile Include="NavigationHistory.cs" />

215
ILSpy/Languages/CSharpLanguage.cs

@ -110,9 +110,9 @@ namespace ICSharpCode.ILSpy
} }
} }
CSharpDecompiler CreateDecompiler(Decompiler.Metadata.PEFile module, DecompilationOptions options) CSharpDecompiler CreateDecompiler(PEFile module, DecompilationOptions options)
{ {
CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); CSharpDecompiler decompiler = new CSharpDecompiler(module, module.GetAssemblyResolver(), options.DecompilerSettings);
decompiler.CancellationToken = options.CancellationToken; decompiler.CancellationToken = options.CancellationToken;
while (decompiler.AstTransforms.Count > transformCount) while (decompiler.AstTransforms.Count > transformCount)
decompiler.AstTransforms.RemoveAt(decompiler.AstTransforms.Count - 1); decompiler.AstTransforms.RemoveAt(decompiler.AstTransforms.Count - 1);
@ -129,19 +129,19 @@ namespace ICSharpCode.ILSpy
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, settings.CSharpFormattingOptions)); syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, settings.CSharpFormattingOptions));
} }
public override void DecompileMethod(Decompiler.Metadata.MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options)
{ {
AddReferenceWarningMessage(method.Module, output); PEFile assembly = method.ParentAssembly.PEFile;
var md = method.Module.Metadata.GetMethodDefinition(method.Handle); AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, TypeToString(new Entity(method.Module, md.GetDeclaringType()), includeNamespace: true)); WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(method.Module, options); CSharpDecompiler decompiler = CreateDecompiler(assembly, options);
var methodDefinition = decompiler.TypeSystem.ResolveAsMethod(method.Handle); var methodDefinition = decompiler.TypeSystem.ResolveAsMethod(method.MetadataToken);
if (methodDefinition.IsConstructor && methodDefinition.DeclaringType.IsReferenceType != false) { if (methodDefinition.IsConstructor && methodDefinition.DeclaringType.IsReferenceType != false) {
var members = CollectFieldsAndCtors(methodDefinition.DeclaringTypeDefinition, methodDefinition.IsStatic); var members = CollectFieldsAndCtors(methodDefinition.DeclaringTypeDefinition, methodDefinition.IsStatic);
decompiler.AstTransforms.Add(new SelectCtorTransform(methodDefinition)); decompiler.AstTransforms.Add(new SelectCtorTransform(methodDefinition));
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(members), decompiler.TypeSystem); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(members), decompiler.TypeSystem);
} else { } else {
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method.Handle), decompiler.TypeSystem); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method.MetadataToken), decompiler.TypeSystem);
} }
} }
@ -196,28 +196,26 @@ namespace ICSharpCode.ILSpy
} }
} }
public override void DecompileProperty(Decompiler.Metadata.PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(IProperty property, ITextOutput output, DecompilationOptions options)
{ {
AddReferenceWarningMessage(property.Module, output); PEFile assembly = property.ParentAssembly.PEFile;
CSharpDecompiler decompiler = CreateDecompiler(property.Module, options); AddReferenceWarningMessage(assembly, output);
var metadata = property.Module.Metadata; CSharpDecompiler decompiler = CreateDecompiler(assembly, options);
var accessorHandle = metadata.GetPropertyDefinition(property.Handle).GetAccessors().GetAny(); WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
WriteCommentLine(output, TypeToString(new Decompiler.Metadata.TypeDefinition(property.Module, metadata.GetMethodDefinition(accessorHandle).GetDeclaringType()), includeNamespace: true)); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property.MetadataToken), decompiler.TypeSystem);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property.Handle), decompiler.TypeSystem);
} }
public override void DecompileField(Decompiler.Metadata.FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(IField field, ITextOutput output, DecompilationOptions options)
{ {
AddReferenceWarningMessage(field.Module, output); PEFile assembly = field.ParentAssembly.PEFile;
var fd = field.Module.Metadata.GetFieldDefinition(field.Handle); AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, TypeToString(new Decompiler.Metadata.TypeDefinition(field.Module, fd.GetDeclaringType()), includeNamespace: true)); WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(field.Module, options); CSharpDecompiler decompiler = CreateDecompiler(assembly, options);
var fieldDefinition = decompiler.TypeSystem.ResolveAsField(field.Handle); if (field.IsConst) {
if (fd.HasFlag(FieldAttributes.Literal)) { WriteCode(output, options.DecompilerSettings, decompiler.Decompile(field.MetadataToken), decompiler.TypeSystem);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(field.Handle), decompiler.TypeSystem);
} else { } else {
var members = CollectFieldsAndCtors(fieldDefinition.DeclaringTypeDefinition, fieldDefinition.IsStatic); var members = CollectFieldsAndCtors(field.DeclaringTypeDefinition, field.IsStatic);
decompiler.AstTransforms.Add(new SelectFieldTransform(fieldDefinition)); decompiler.AstTransforms.Add(new SelectFieldTransform(field));
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(members), decompiler.TypeSystem); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(members), decompiler.TypeSystem);
} }
} }
@ -266,25 +264,25 @@ namespace ICSharpCode.ILSpy
} }
} }
public override void DecompileEvent(Decompiler.Metadata.EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(IEvent @event, ITextOutput output, DecompilationOptions options)
{ {
AddReferenceWarningMessage(ev.Module, output); PEFile assembly = @event.ParentAssembly.PEFile;
var metadata = ev.Module.Metadata; AddReferenceWarningMessage(assembly, output);
var accessorHandle = metadata.GetEventDefinition(ev.Handle).GetAccessors().GetAny(); base.WriteCommentLine(output, TypeToString(@event.DeclaringType, includeNamespace: true));
base.WriteCommentLine(output, TypeToString(new Decompiler.Metadata.TypeDefinition(ev.Module, metadata.GetMethodDefinition(accessorHandle).GetDeclaringType()), includeNamespace: true)); CSharpDecompiler decompiler = CreateDecompiler(assembly, options);
CSharpDecompiler decompiler = CreateDecompiler(ev.Module, options); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(@event.MetadataToken), decompiler.TypeSystem);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(ev.Handle), decompiler.TypeSystem);
} }
public override void DecompileType(Decompiler.Metadata.TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AddReferenceWarningMessage(type.Module, output); PEFile assembly = type.ParentAssembly.PEFile;
AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, TypeToString(type, includeNamespace: true)); WriteCommentLine(output, TypeToString(type, includeNamespace: true));
CSharpDecompiler decompiler = CreateDecompiler(type.Module, options); CSharpDecompiler decompiler = CreateDecompiler(assembly, options);
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type.Handle), decompiler.TypeSystem); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type.MetadataToken), decompiler.TypeSystem);
} }
void AddReferenceWarningMessage(Decompiler.Metadata.PEFile assembly, ITextOutput output) void AddReferenceWarningMessage(PEFile assembly, ITextOutput output)
{ {
var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetPEFileOrNull() == assembly); var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetPEFileOrNull() == assembly);
if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors) if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors)
@ -320,7 +318,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{ {
var module = assembly.GetPEFileAsync().Result; var module = assembly.GetPEFileOrNull();
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) { if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
var decompiler = new ILSpyWholeProjectDecompiler(assembly, options); var decompiler = new ILSpyWholeProjectDecompiler(assembly, options);
decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken); decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken);
@ -328,23 +326,24 @@ namespace ICSharpCode.ILSpy
AddReferenceWarningMessage(module, output); AddReferenceWarningMessage(module, output);
output.WriteLine(); output.WriteLine();
base.DecompileAssembly(assembly, output, options); base.DecompileAssembly(assembly, output, options);
var metadata = module.Metadata; IAssemblyResolver assemblyResolver = assembly.GetAssemblyResolver();
var typeSystem = new DecompilerTypeSystem(module, assemblyResolver, options.DecompilerSettings);
if (metadata.TypeDefinitions.Count > 0) { var globalType = typeSystem.MainAssembly.TypeDefinitions.FirstOrDefault();
if (globalType != null) {
output.Write("// Global type: "); output.Write("// Global type: ");
var globalType = metadata.TypeDefinitions.First(); output.WriteReference(globalType.FullName, globalType);
output.WriteReference(globalType.GetFullTypeName(metadata).ToString(), new Decompiler.Metadata.TypeDefinition(module, globalType));
output.WriteLine(); output.WriteLine();
} }
var metadata = module.Metadata;
var corHeader = module.Reader.PEHeaders.CorHeader; var corHeader = module.Reader.PEHeaders.CorHeader;
var entrypointHandle = MetadataTokenHelpers.EntityHandleOrNil(corHeader.EntryPointTokenOrRelativeVirtualAddress); var entrypointHandle = MetadataTokenHelpers.EntityHandleOrNil(corHeader.EntryPointTokenOrRelativeVirtualAddress);
if (!entrypointHandle.IsNil && entrypointHandle.Kind == HandleKind.MethodDefinition) { if (!entrypointHandle.IsNil && entrypointHandle.Kind == HandleKind.MethodDefinition) {
var entrypoint = metadata.GetMethodDefinition((MethodDefinitionHandle)entrypointHandle); var entrypoint = typeSystem.ResolveAsMethod(entrypointHandle);
output.Write("// Entry point: "); if (entrypoint != null) {
string name = entrypoint.GetDeclaringType().GetFullTypeName(metadata) + "." + metadata.GetString(entrypoint.Name); output.Write("// Entry point: ");
var entrypointEntity = new Decompiler.Metadata.MethodDefinition(module, (MethodDefinitionHandle)entrypointHandle); output.WriteReference(entrypoint.DeclaringType.FullName + "." + entrypoint.Name, entrypoint);
output.WriteReference(name, entrypointEntity); output.WriteLine();
output.WriteLine(); }
} }
output.WriteLine("// Architecture: " + GetPlatformDisplayName(module)); output.WriteLine("// Architecture: " + GetPlatformDisplayName(module));
if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.ILOnly) == 0) { if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.ILOnly) == 0) {
@ -358,7 +357,7 @@ namespace ICSharpCode.ILSpy
// don't automatically load additional assemblies when an assembly node is selected in the tree view // don't automatically load additional assemblies when an assembly node is selected in the tree view
using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) { using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) {
CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, assemblyResolver, options.DecompilerSettings);
decompiler.CancellationToken = options.CancellationToken; decompiler.CancellationToken = options.CancellationToken;
SyntaxTree st; SyntaxTree st;
if (options.FullDecompilation) { if (options.FullDecompilation) {
@ -405,82 +404,35 @@ namespace ICSharpCode.ILSpy
} }
} }
public override string TypeToString(Entity type, Decompiler.Metadata.GenericContext genericContext = null, bool includeNamespace = true) public override string TypeToString(IType type, bool includeNamespace)
{ {
if (type.Handle.IsNil) if (type == null)
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
var metadata = type.Module.Metadata; TypeSystemAstBuilder builder = new TypeSystemAstBuilder();
ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; AstType astType = builder.ConvertType(type);
if (includeNamespace) StringWriter w = new StringWriter();
convertTypeOptions |= ConvertTypeOptions.IncludeNamespace;
//if (includeTypeName)
// convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName;
var builder = new AstTypeBuilder(convertTypeOptions);
AstType astType;
switch (type.Handle.Kind) {
case HandleKind.TypeReference:
astType = builder.GetTypeFromReference(metadata, (TypeReferenceHandle)type.Handle, 0);
return TypeToString(astType, metadata, null);
case HandleKind.TypeDefinition:
var td = metadata.GetTypeDefinition((TypeDefinitionHandle)type.Handle);
var genericParams = td.GetGenericParameters();
var buffer = new System.Text.StringBuilder();
var name = td.GetFullTypeName(metadata);
if (includeNamespace)
buffer.Append(name.ToString());
else
buffer.Append(name.Name);
if (genericParams.Count > 0) {
buffer.Append('<');
int i = 0;
foreach (var h in genericParams) {
var gp = metadata.GetGenericParameter(h);
if (i > 0)
buffer.Append(", ");
buffer.Append(metadata.GetString(gp.Name));
i++;
}
buffer.Append('>');
}
return buffer.ToString(); astType.AcceptVisitor(new CSharpOutputVisitor(w, FormattingOptionsFactory.CreateAllman()));
case HandleKind.TypeSpecification: return w.ToString();
var ts = metadata.GetTypeSpecification((TypeSpecificationHandle)type.Handle);
astType = builder.GetTypeFromSpecification(metadata, genericContext ?? GenericContext.Empty, (TypeSpecificationHandle)type.Handle, 0);
return TypeToString(astType, metadata, ts.GetCustomAttributes());
default:
throw new NotSupportedException();
}
} }
public override string FieldToString(Decompiler.Metadata.FieldDefinition field, bool includeTypeName, bool includeNamespace) public override string FieldToString(IField field, bool includeTypeName, bool includeNamespace)
{ {
if (field.Handle.IsNil) if (field == null)
throw new ArgumentNullException(nameof(field)); throw new ArgumentNullException(nameof(field));
ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions;
if (includeNamespace) string simple = field.Name + " : " + TypeToString(field.Type, includeNamespace);
convertTypeOptions |= ConvertTypeOptions.IncludeNamespace;
if (includeTypeName)
convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName;
var metadata = field.Module.Metadata;
var fd = metadata.GetFieldDefinition(field.Handle);
AstType fieldType = fd.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(fd.GetDeclaringType(), field.Module));
string simple = metadata.GetString(fd.Name) + " : " + TypeToString(fieldType, metadata, fd.GetCustomAttributes());
if (!includeTypeName) if (!includeTypeName)
return simple; return simple;
var typeName = fd.GetDeclaringType().GetFullTypeName(metadata); var typeName = field.DeclaringTypeDefinition.FullTypeName;
if (!includeNamespace) if (!includeNamespace)
return typeName.Name + "." + simple; return typeName.Name + "." + simple;
return typeName + "." + simple; return typeName + "." + simple;
} }
/*
public override string PropertyToString(Decompiler.Metadata.PropertyDefinition property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) public override string PropertyToString(IProperty property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null)
{ {
if (property.IsNil) if (property == null)
throw new ArgumentNullException(nameof(property)); throw new ArgumentNullException(nameof(property));
ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions;
if (includeNamespace) if (includeNamespace)
@ -699,43 +651,18 @@ namespace ICSharpCode.ILSpy
buffer.Append(" : "); buffer.Append(" : ");
buffer.Append(TypeToString(signature, metadata, returnTypeAttributes)); buffer.Append(TypeToString(signature, metadata, returnTypeAttributes));
return buffer.ToString(); return buffer.ToString();
} }*/
public override bool ShowMember(IMetadataEntity member) public override bool ShowMember(IEntity member)
{ {
return showAllMembers || !CSharpDecompiler.MemberIsHidden(member.Module, member.Handle, new DecompilationOptions().DecompilerSettings); PEFile assembly = member.ParentAssembly.PEFile;
return showAllMembers || !CSharpDecompiler.MemberIsHidden(assembly, member.MetadataToken, new DecompilationOptions().DecompilerSettings);
} }
public override string GetTooltip(Entity entity) public override string GetTooltip(IEntity entity)
{ {
var decompilerTypeSystem = new DecompilerTypeSystem(entity.Module);
ISymbol symbol;
switch (entity.Handle.Kind) {
case HandleKind.MethodDefinition:
symbol = decompilerTypeSystem.ResolveAsMethod(entity.Handle);
if (symbol == null) return base.GetTooltip(entity);
break;
case HandleKind.PropertyDefinition:
symbol = decompilerTypeSystem.ResolveAsProperty(entity.Handle);
if (symbol == null) return base.GetTooltip(entity);
break;
case HandleKind.EventDefinition:
symbol = decompilerTypeSystem.ResolveAsEvent(entity.Handle);
if (symbol == null) return base.GetTooltip(entity);
break;
case HandleKind.FieldDefinition:
symbol = decompilerTypeSystem.ResolveAsField(entity.Handle);
if (symbol == null) return base.GetTooltip(entity);
break;
case HandleKind.TypeDefinition:
symbol = decompilerTypeSystem.ResolveAsType(entity.Handle).GetDefinition();
if (symbol == null) return base.GetTooltip(entity);
break;
default:
return base.GetTooltip(entity);
}
var flags = ConversionFlags.All & ~ConversionFlags.ShowBody; var flags = ConversionFlags.All & ~ConversionFlags.ShowBody;
return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(symbol); return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(entity);
} }
public override CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member) public override CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member)

39
ILSpy/LoadedAssembly.cs

@ -21,9 +21,11 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
@ -39,6 +41,8 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public sealed class LoadedAssembly public sealed class LoadedAssembly
{ {
internal static readonly ConditionalWeakTable<PEFile, LoadedAssembly> loadedAssemblies = new ConditionalWeakTable<PEFile, LoadedAssembly>();
readonly Task<PEFile> assemblyTask; readonly Task<PEFile> assemblyTask;
readonly AssemblyList assemblyList; readonly AssemblyList assemblyList;
readonly string fileName; readonly string fileName;
@ -65,6 +69,8 @@ namespace ICSharpCode.ILSpy
public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo(); public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo();
IDebugInfoProvider debugInfoProvider;
/// <summary> /// <summary>
/// Gets the Cecil ModuleDefinition. /// Gets the Cecil ModuleDefinition.
/// </summary> /// </summary>
@ -87,12 +93,20 @@ namespace ICSharpCode.ILSpy
} }
} }
public ICompilation GetTypeSystem() ICompilation typeSystem;
/// <summary>
/// Gets a type system containing all types from this assembly + primitve types from mscorlib.
/// Returns null in case of load errors.
/// </summary>
public ICompilation GetTypeSystemOrNull()
{ {
if (typeSystem != null)
return typeSystem;
var module = GetPEFileOrNull(); var module = GetPEFileOrNull();
if (module == null) if (module == null)
return null; return null;
return new SimpleCompilation(module, MinimalCorlib.Instance); return typeSystem = new SimpleCompilation(module, MinimalCorlib.Instance);
} }
public AssemblyList AssemblyList => assemblyList; public AssemblyList AssemblyList => assemblyList;
@ -129,12 +143,12 @@ namespace ICSharpCode.ILSpy
if (stream != null) if (stream != null)
{ {
// Read the module from a precrafted stream // Read the module from a precrafted stream
module = new PEFile(fileName, stream, new MyAssemblyResolver(this), PEStreamOptions.Default); module = new PEFile(fileName, stream);
} }
else else
{ {
// Read the module from disk (by default) // Read the module from disk (by default)
module = new PEFile(fileName, new FileStream(fileName, FileMode.Open, FileAccess.Read), new MyAssemblyResolver(this), PEStreamOptions.PrefetchEntireImage); module = new PEFile(fileName, new FileStream(fileName, FileMode.Open, FileAccess.Read), PEStreamOptions.PrefetchEntireImage);
} }
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) { if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
@ -146,6 +160,9 @@ namespace ICSharpCode.ILSpy
// ignore any errors during symbol loading // ignore any errors during symbol loading
} }
} }
lock (loadedAssemblies) {
loadedAssemblies.Add(module, this);
}
return module; return module;
} }
@ -154,13 +171,13 @@ namespace ICSharpCode.ILSpy
var reader = module.Reader; var reader = module.Reader;
// try to open portable pdb file/embedded pdb info: // try to open portable pdb file/embedded pdb info:
if (reader.TryOpenAssociatedPortablePdb(fileName, OpenStream, out var provider, out var pdbFileName)) { if (reader.TryOpenAssociatedPortablePdb(fileName, OpenStream, out var provider, out var pdbFileName)) {
module.DebugInfo = new PortableDebugInfoProvider(pdbFileName, provider); debugInfoProvider = new PortableDebugInfoProvider(pdbFileName, provider);
} else { } else {
// search for pdb in same directory as dll // search for pdb in same directory as dll
string pdbDirectory = Path.GetDirectoryName(fileName); string pdbDirectory = Path.GetDirectoryName(fileName);
pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb"); pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb");
if (File.Exists(pdbFileName)) { if (File.Exists(pdbFileName)) {
module.DebugInfo = new DiaSymNativeDebugInfoProvider(module, pdbFileName, OpenStream(pdbFileName)); debugInfoProvider = new DiaSymNativeDebugInfoProvider(module, pdbFileName, OpenStream(pdbFileName));
return; return;
} }
@ -222,6 +239,16 @@ namespace ICSharpCode.ILSpy
{ {
return new MyAssemblyResolver(this); return new MyAssemblyResolver(this);
} }
/// <summary>
/// Returns the debug info for this assembly. Returns null in case of load errors or no debug info is available.
/// </summary>
public IDebugInfoProvider GetDebugInfoOrNull()
{
if (GetPEFileOrNull() == null)
return null;
return debugInfoProvider;
}
public LoadedAssembly LookupReferencedAssembly(Decompiler.Metadata.IAssemblyReference reference) public LoadedAssembly LookupReferencedAssembly(Decompiler.Metadata.IAssemblyReference reference)
{ {

25
ILSpy/LoadedAssemblyExtensions.cs

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy
{
public static class LoadedAssemblyExtensions
{
public static IAssemblyResolver GetAssemblyResolver(this PEFile file)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
LoadedAssembly loadedAssembly;
lock (LoadedAssembly.loadedAssemblies) {
if (!LoadedAssembly.loadedAssemblies.TryGetValue(file, out loadedAssembly))
throw new ArgumentException("The specified file is not associated with a LoadedAssembly!");
}
return loadedAssembly.GetAssemblyResolver();
}
}
}

2
ILSpy/SearchPane.cs

@ -217,7 +217,7 @@ namespace ICSharpCode.ILSpy
try { try {
var searcher = GetSearchStrategy(searchMode, searchTerm); var searcher = GetSearchStrategy(searchMode, searchTerm);
foreach (var loadedAssembly in assemblies) { foreach (var loadedAssembly in assemblies) {
var typeSystem = loadedAssembly.GetTypeSystem(); var typeSystem = loadedAssembly.GetTypeSystemOrNull();
if (typeSystem == null) if (typeSystem == null)
continue; continue;
CancellationToken cancellationToken = cts.Token; CancellationToken cancellationToken = cts.Token;

6
ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

@ -233,7 +233,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
IEnumerable<T> FindReferencesInAssembly(Decompiler.Metadata.PEFile module, CancellationToken ct) IEnumerable<T> FindReferencesInAssembly(Decompiler.Metadata.PEFile module, CancellationToken ct)
{ {
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module) : null; IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module, module.GetAssemblyResolver()) : null;
var metadata = module.Metadata; var metadata = module.Metadata;
foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) { foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
@ -247,7 +247,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct) IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct)
{ {
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null; IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope, assemblyScope.GetAssemblyResolver()) : null;
foreach (var type in TreeTraversal.PreOrder(typeScopeHandle, t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { foreach (var type in TreeTraversal.PreOrder(typeScopeHandle, t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type); var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type);
@ -260,7 +260,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
IEnumerable<T> FindReferencesInEnclosingTypeScope(CancellationToken ct) IEnumerable<T> FindReferencesInEnclosingTypeScope(CancellationToken ct)
{ {
IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null; IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope, assemblyScope.GetAssemblyResolver()) : null;
var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, typeScope.GetDeclaringType()); var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, typeScope.GetDeclaringType());
foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -135,7 +135,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
// if we crashed on loading, then we don't have any children // if we crashed on loading, then we don't have any children
return; return;
} }
typeSystem = new SimpleCompilation(module, MinimalCorlib.Instance); typeSystem = LoadedAssembly.GetTypeSystemOrNull();
var assembly = (MetadataAssembly)typeSystem.MainAssembly; var assembly = (MetadataAssembly)typeSystem.MainAssembly;
var metadata = module.Metadata; var metadata = module.Metadata;

8
ILSpy/TreeNodes/BaseTypesEntryNode.cs

@ -65,16 +65,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
var t = typeSystem.ResolveAsType(handle).GetDefinition(); var t = typeSystem.ResolveAsType(handle).GetDefinition();
if (t != null) { if (t != null) {
BaseTypesTreeNode.AddBaseTypes(this.Children, ((MetadataAssembly)t.ParentAssembly).PEFile, t); BaseTypesTreeNode.AddBaseTypes(this.Children, t.ParentAssembly.PEFile, t);
} }
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)
{ {
DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
var t = typeSystem.ResolveAsType(handle).GetDefinition(); var t = typeSystem.ResolveAsType(handle).GetDefinition();
e.Handled = ActivateItem(this, t); e.Handled = ActivateItem(this, t);
} }
@ -98,7 +98,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
IEntity IMemberTreeNode.Member { IEntity IMemberTreeNode.Member {
get { get {
DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
var t = typeSystem.ResolveAsType(handle).GetDefinition(); var t = typeSystem.ResolveAsType(handle).GetDefinition();
return t; return t;
} }

4
ILSpy/TreeNodes/GeneratePdbContextMenuEntry.cs

@ -7,7 +7,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.Pdb; using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using Microsoft.Win32; using Microsoft.Win32;
@ -33,7 +33,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) { using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) {
try { try {
var file = assembly.GetPEFileOrNull(); var file = assembly.GetPEFileOrNull();
var decompiler = new CSharpDecompiler(file, options.DecompilerSettings); var decompiler = new CSharpDecompiler(file, assembly.GetAssemblyResolver(), options.DecompilerSettings);
PortablePdbWriter.WritePdb(file, decompiler, options.DecompilerSettings, stream); PortablePdbWriter.WritePdb(file, decompiler, options.DecompilerSettings, stream);
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
output.WriteLine(); output.WriteLine();

Loading…
Cancel
Save