Skip to content

Commit

Permalink
Use MetadataFile instead of PEFile in TypeSystem.
Browse files Browse the repository at this point in the history
  • Loading branch information
siegfriedpammer committed Mar 24, 2024
1 parent 9c82234 commit ca78d4a
Show file tree
Hide file tree
Showing 117 changed files with 885 additions and 763 deletions.
2 changes: 1 addition & 1 deletion ICSharpCode.BamlDecompiler/Baml/KnownThings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public KnownThings(IDecompilerTypeSystem typeSystem)
}
catch (Exception ex)
{
throw new ICSharpCode.Decompiler.DecompilerException(typeSystem.MainModule.PEFile, ex.Message, ex);
throw new ICSharpCode.Decompiler.DecompilerException(typeSystem.MainModule.MetadataFile, ex.Message, ex);
}
}

Expand Down
12 changes: 6 additions & 6 deletions ICSharpCode.BamlDecompiler/BamlDecompilerTypeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ public class BamlDecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
"System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
};

public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
public BamlDecompilerTypeSystem(MetadataFile mainModule, IAssemblyResolver assemblyResolver)
{
if (mainModule == null)
throw new ArgumentNullException(nameof(mainModule));
if (assemblyResolver == null)
throw new ArgumentNullException(nameof(assemblyResolver));
// Load referenced assemblies and type-forwarder references.
// This is necessary to make .NET Core/PCL binaries work better.
var referencedAssemblies = new List<PEFile>();
var assemblyReferenceQueue = new Queue<(bool IsAssembly, PEFile MainModule, object Reference)>();
var referencedAssemblies = new List<MetadataFile>();
var assemblyReferenceQueue = new Queue<(bool IsAssembly, MetadataFile MainModule, object Reference)>();
var mainMetadata = mainModule.Metadata;
foreach (var h in mainMetadata.GetModuleReferences())
{
Expand All @@ -73,16 +73,16 @@ public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyRes
{
assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference)));
}
var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference) reference) =>
var comparer = KeyComparer.Create(((bool IsAssembly, MetadataFile MainModule, object Reference) reference) =>
reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName :
"M:" + reference.Reference);
var processedAssemblyReferences = new HashSet<(bool IsAssembly, PEFile Parent, object Reference)>(comparer);
var processedAssemblyReferences = new HashSet<(bool IsAssembly, MetadataFile Parent, object Reference)>(comparer);
while (assemblyReferenceQueue.Count > 0)
{
var asmRef = assemblyReferenceQueue.Dequeue();
if (!processedAssemblyReferences.Add(asmRef))
continue;
PEFile asm;
MetadataFile asm;
if (asmRef.IsAssembly)
{
asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference);
Expand Down
6 changes: 2 additions & 4 deletions ICSharpCode.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void DecompileConnections(XamlContext ctx, List<(LongSet, FieldAssignment)> fiel

IMethod connectMethod = null;
MethodDefinition connectMetadataEntry = default;
var module = ctx.TypeSystem.MainModule.PEFile;
var module = ctx.TypeSystem.MainModule.MetadataFile;

foreach (IMethod m in type.Methods)
{
Expand Down Expand Up @@ -171,9 +171,7 @@ void DecompileConnections(XamlContext ctx, List<(LongSet, FieldAssignment)> fiel

ctx.GeneratedMembers.Add(connectMethod.MetadataToken);



var body = module.Reader.GetMethodBody(connectMetadataEntry.RelativeVirtualAddress);
var body = module.GetMethodBody(connectMetadataEntry.RelativeVirtualAddress);
var genericContext = new GenericContext(
classTypeParameters: connectMethod.DeclaringType?.TypeParameters,
methodTypeParameters: connectMethod.TypeParameters);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Management.Automation;
using System.Threading;
Expand Down Expand Up @@ -89,7 +88,7 @@ protected override void ProcessRecord()

private void DoDecompile(string path)
{
PEFile module = Decompiler.TypeSystem.MainModule.PEFile;
MetadataFile module = Decompiler.TypeSystem.MainModule.MetadataFile;
var assemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Metadata.DetectTargetFrameworkId());
WholeProjectDecompiler decompiler = new WholeProjectDecompiler(assemblyResolver);
decompiler.ProgressIndicator = this;
Expand Down
28 changes: 14 additions & 14 deletions ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public CSharpDecompiler(string fileName, IAssemblyResolver assemblyResolver, Dec
/// <summary>
/// Creates a new <see cref="CSharpDecompiler"/> instance from the given <paramref name="module"/> using the given <paramref name="assemblyResolver"/> and <paramref name="settings"/>.
/// </summary>
public CSharpDecompiler(PEFile module, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
public CSharpDecompiler(MetadataFile module, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
: this(new DecompilerTypeSystem(module, assemblyResolver, settings), settings)
{
}
Expand All @@ -264,7 +264,7 @@ public CSharpDecompiler(DecompilerTypeSystem typeSystem, DecompilerSettings sett
this.typeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem));
this.settings = settings;
this.module = typeSystem.MainModule;
this.metadata = module.PEFile.Metadata;
this.metadata = module.MetadataFile.Metadata;
if (module.TypeSystemOptions.HasFlag(TypeSystemOptions.Uncached))
throw new ArgumentException("Cannot use an uncached type system in the decompiler.");
}
Expand All @@ -276,7 +276,7 @@ public CSharpDecompiler(DecompilerTypeSystem typeSystem, DecompilerSettings sett
/// <param name="module">The module containing the member.</param>
/// <param name="member">The metadata token/handle of the member. Can be a TypeDef, MethodDef or FieldDef.</param>
/// <param name="settings">THe settings used to determine whether code should be hidden. E.g. if async methods are not transformed, async state machines are included in the decompiled code.</param>
public static bool MemberIsHidden(Metadata.PEFile module, EntityHandle member, DecompilerSettings settings)
public static bool MemberIsHidden(MetadataFile module, EntityHandle member, DecompilerSettings settings)
{
if (module == null || member.IsNil)
return false;
Expand Down Expand Up @@ -539,7 +539,7 @@ IDocumentationProvider CreateDefaultDocumentationProvider()
{
try
{
return XmlDocLoader.LoadDocumentation(module.PEFile);
return XmlDocLoader.LoadDocumentation(module.MetadataFile);
}
catch (System.Xml.XmlException)
{
Expand Down Expand Up @@ -633,7 +633,7 @@ void DoDecompileTypes(IEnumerable<TypeDefinitionHandle> types, DecompileRun deco
var typeDef = module.GetDefinition(typeDefHandle);
if (typeDef.Name == "<Module>" && typeDef.Members.Count == 0)
continue;
if (MemberIsHidden(module.PEFile, typeDefHandle, settings))
if (MemberIsHidden(module.MetadataFile, typeDefHandle, settings))
continue;
if (string.IsNullOrEmpty(typeDef.Namespace))
{
Expand Down Expand Up @@ -702,7 +702,7 @@ public ILTransformContext CreateILTransformContext(ILFunction function)
/// <summary>
/// Determines the "code-mappings" for a given TypeDef or MethodDef. See <see cref="CodeMappingInfo"/> for more information.
/// </summary>
public static CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member)
public static CodeMappingInfo GetCodeMappingInfo(MetadataFile module, EntityHandle member)
{
var declaringType = (TypeDefinitionHandle)member.GetDeclaringType(module.Metadata);

Expand Down Expand Up @@ -744,7 +744,7 @@ public static CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle mem
return info;
}

private static void ReadCodeMappingInfo(PEFile module, CodeMappingInfo info, MethodDefinitionHandle parent, MethodDefinitionHandle part, Queue<MethodDefinitionHandle> connectedMethods, HashSet<TypeDefinitionHandle> processedNestedTypes)
private static void ReadCodeMappingInfo(MetadataFile module, CodeMappingInfo info, MethodDefinitionHandle parent, MethodDefinitionHandle part, Queue<MethodDefinitionHandle> connectedMethods, HashSet<TypeDefinitionHandle> processedNestedTypes)
{
var md = module.Metadata.GetMethodDefinition(part);

Expand All @@ -756,7 +756,7 @@ private static void ReadCodeMappingInfo(PEFile module, CodeMappingInfo info, Met

var declaringType = md.GetDeclaringType();

var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader();
var blob = module.GetMethodBody(md.RelativeVirtualAddress).GetILReader();
while (blob.RemainingBytes > 0)
{
var code = blob.DecodeOpCode();
Expand Down Expand Up @@ -1357,7 +1357,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
// Decompile members that are not compiler-generated.
foreach (var entity in allOrderedEntities)
{
if (entity.MetadataToken.IsNil || MemberIsHidden(module.PEFile, entity.MetadataToken, settings))
if (entity.MetadataToken.IsNil || MemberIsHidden(module.MetadataFile, entity.MetadataToken, settings))
{
continue;
}
Expand Down Expand Up @@ -1403,7 +1403,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
if (typeDecl.ClassType == ClassType.Enum)
{
Debug.Assert(typeDef.Kind == TypeKind.Enum);
EnumValueDisplayMode displayMode = DetectBestEnumValueDisplayMode(typeDef, module.PEFile);
EnumValueDisplayMode displayMode = DetectBestEnumValueDisplayMode(typeDef, module.MetadataFile);
switch (displayMode)
{
case EnumValueDisplayMode.FirstOnly:
Expand Down Expand Up @@ -1532,7 +1532,7 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
}
}

EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, PEFile module)
EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, MetadataFile module)
{
if (typeDef.HasAttribute(KnownAttribute.Flags))
return EnumValueDisplayMode.AllHex;
Expand Down Expand Up @@ -1608,7 +1608,7 @@ EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeRe
}
FixParameterNames(methodDecl);
var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
if (!settings.LocalFunctions && LocalFunctionDecompiler.LocalFunctionNeedsAccessibilityChange(method.ParentModule.PEFile, (MethodDefinitionHandle)method.MetadataToken))
if (!settings.LocalFunctions && LocalFunctionDecompiler.LocalFunctionNeedsAccessibilityChange(method.ParentModule.MetadataFile, (MethodDefinitionHandle)method.MetadataToken))
{
// if local functions are not active and we're dealing with a local function,
// reduce the visibility of the method to private,
Expand Down Expand Up @@ -1701,7 +1701,7 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
MethodBodyBlock methodBody;
try
{
methodBody = module.PEFile.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
methodBody = module.MetadataFile.GetMethodBody(methodDef.RelativeVirtualAddress);
}
catch (BadImageFormatException ex)
{
Expand Down Expand Up @@ -1980,7 +1980,7 @@ EntityDeclaration DoDecompile(IField field, DecompileRun decompileRun, ITypeReso
string message;
try
{
var initVal = fieldDefinition.GetInitialValue(module.PEFile.Reader, TypeSystem);
var initVal = fieldDefinition.GetInitialValue(module.MetadataFile, TypeSystem);
message = string.Format(" Not supported: data({0}) ", BitConverter.ToString(initVal.ReadBytes(initVal.RemainingBytes)).Replace('-', ' '));
}
catch (BadImageFormatException ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,17 +216,17 @@ public static string GetPlatformName(PEFile module)
};

/// <summary>
/// Gets exact <see cref="TargetFramework"/> if <see cref="PEFile.GetRuntime"/> is <see cref="TargetRuntime.Net_2_0"/>
/// Gets exact <see cref="TargetFramework"/> if <see cref="MetadataFile.GetRuntime"/> is <see cref="TargetRuntime.Net_2_0"/>
/// </summary>
public static TargetFramework DetectTargetFrameworkNET20(PEFile module, IAssemblyResolver assemblyResolver, TargetFramework targetFramework)
public static TargetFramework DetectTargetFrameworkNET20(MetadataFile module, IAssemblyResolver assemblyResolver, TargetFramework targetFramework)
{
var resolvedAssemblies = new HashSet<string>();
int version = 200;
GetFrameworkVersionNET20(module, assemblyResolver, resolvedAssemblies, ref version);
return new TargetFramework(targetFramework.Identifier, version, targetFramework.Profile);
}

static void GetFrameworkVersionNET20(PEFile module, IAssemblyResolver assemblyResolver, HashSet<string> resolvedAssemblies, ref int version)
static void GetFrameworkVersionNET20(MetadataFile module, IAssemblyResolver assemblyResolver, HashSet<string> resolvedAssemblies, ref int version)
{
foreach (var r in module.Metadata.AssemblyReferences)
{
Expand All @@ -245,7 +245,7 @@ static void GetFrameworkVersionNET20(PEFile module, IAssemblyResolver assemblyRe
break;
}

PEFile resolvedReference;
MetadataFile resolvedReference;
try
{
resolvedReference = assemblyResolver.Resolve(reference);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;

using Microsoft.Win32;

using static ICSharpCode.Decompiler.Metadata.MetadataExtensions;

namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
Expand Down Expand Up @@ -133,40 +131,48 @@ protected WholeProjectDecompiler(
HashSet<string> directories = new HashSet<string>(Platform.FileNameComparer);
readonly IProjectFileWriter projectWriter;

public void DecompileProject(PEFile moduleDefinition, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
public void DecompileProject(MetadataFile file, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
{
string projectFileName = Path.Combine(targetDirectory, CleanUpFileName(moduleDefinition.Name) + ".csproj");
if (file is not PEFile)
{
throw new NotSupportedException("Module is not a valid PE file!");
}
string projectFileName = Path.Combine(targetDirectory, CleanUpFileName(file.Name) + ".csproj");
using (var writer = new StreamWriter(projectFileName))
{
DecompileProject(moduleDefinition, targetDirectory, writer, cancellationToken);
DecompileProject(file, targetDirectory, writer, cancellationToken);
}
}

public ProjectId DecompileProject(PEFile moduleDefinition, string targetDirectory, TextWriter projectFileWriter, CancellationToken cancellationToken = default(CancellationToken))
public ProjectId DecompileProject(MetadataFile file, string targetDirectory, TextWriter projectFileWriter, CancellationToken cancellationToken = default(CancellationToken))
{
if (file is not PEFile module)
{
throw new NotSupportedException("Module is not a valid PE file!");
}
if (string.IsNullOrEmpty(targetDirectory))
{
throw new InvalidOperationException("Must set TargetDirectory");
}
TargetDirectory = targetDirectory;
directories.Clear();
var resources = WriteResourceFilesInProject(moduleDefinition).ToList();
var files = WriteCodeFilesInProject(moduleDefinition, resources.SelectMany(r => r.PartialTypes ?? Enumerable.Empty<PartialTypeInfo>()).ToList(), cancellationToken).ToList();
var resources = WriteResourceFilesInProject(file).ToList();
var files = WriteCodeFilesInProject(file, resources.SelectMany(r => r.PartialTypes ?? Enumerable.Empty<PartialTypeInfo>()).ToList(), cancellationToken).ToList();
files.AddRange(resources);
files.AddRange(WriteMiscellaneousFilesInProject(moduleDefinition));
files.AddRange(WriteMiscellaneousFilesInProject(module));
if (StrongNameKeyFile != null)
{
File.Copy(StrongNameKeyFile, Path.Combine(targetDirectory, Path.GetFileName(StrongNameKeyFile)), overwrite: true);
}

projectWriter.Write(projectFileWriter, this, files, moduleDefinition);
projectWriter.Write(projectFileWriter, this, files, module);

string platformName = TargetServices.GetPlatformName(moduleDefinition);
string platformName = TargetServices.GetPlatformName(module);
return new ProjectId(platformName, ProjectGuid, ProjectTypeGuids.CSharpWindows);
}

#region WriteCodeFilesInProject
protected virtual bool IncludeTypeWhenDecompilingProject(PEFile module, TypeDefinitionHandle type)
protected virtual bool IncludeTypeWhenDecompilingProject(MetadataFile module, TypeDefinitionHandle type)
{
var metadata = module.Metadata;
var typeDef = metadata.GetTypeDefinition(type);
Expand Down Expand Up @@ -208,7 +214,7 @@ IEnumerable<ProjectItemInfo> WriteAssemblyInfo(DecompilerTypeSystem ts, Cancella
return new[] { new ProjectItemInfo("Compile", assemblyInfo) };
}

IEnumerable<ProjectItemInfo> WriteCodeFilesInProject(Metadata.PEFile module, IList<PartialTypeInfo> partialTypes, CancellationToken cancellationToken)
IEnumerable<ProjectItemInfo> WriteCodeFilesInProject(MetadataFile module, IList<PartialTypeInfo> partialTypes, CancellationToken cancellationToken)
{
var metadata = module.Metadata;
var files = module.Metadata.GetTopLevelTypeDefinitions().Where(td => IncludeTypeWhenDecompilingProject(module, td))
Expand Down Expand Up @@ -306,7 +312,7 @@ void ProcessFiles(List<IGrouping<string, TypeDefinitionHandle>> files)
#endregion

#region WriteResourceFilesInProject
protected virtual IEnumerable<ProjectItemInfo> WriteResourceFilesInProject(Metadata.PEFile module)
protected virtual IEnumerable<ProjectItemInfo> WriteResourceFilesInProject(MetadataFile module)
{
foreach (var r in module.Resources.Where(r => r.ResourceType == ResourceType.Embedded))
{
Expand Down
2 changes: 1 addition & 1 deletion ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,7 @@ Block DecompileBody(IMethod method)
var genericContext = new GenericContext(
classTypeParameters: recordTypeDef.TypeParameters,
methodTypeParameters: null);
var body = typeSystem.MainModule.PEFile.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
var body = typeSystem.MainModule.MetadataFile.GetMethodBody(methodDef.RelativeVirtualAddress);
var ilReader = new ILReader(typeSystem.MainModule);
var il = ilReader.ReadIL(methodDefHandle, body, genericContext, ILFunctionKind.TopLevelFunction, cancellationToken);
var settings = new DecompilerSettings(LanguageVersion.CSharp1);
Expand Down
7 changes: 3 additions & 4 deletions ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ public static void CollectNamespaces(IEntity entity, MetadataModule module, Hash

void CollectNamespaces(IEntity entity, MetadataModule module, CodeMappingInfo mappingInfo = null)
{
if (entity == null || entity.MetadataToken.IsNil)
if (entity == null || entity.MetadataToken.IsNil || module.MetadataFile is not MetadataFile corFile)
return;
if (mappingInfo == null)
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken);
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(corFile, entity.MetadataToken);
switch (entity)
{
case ITypeDefinition td:
Expand Down Expand Up @@ -104,7 +104,6 @@ void CollectNamespaces(IEntity entity, MetadataModule module, CodeMappingInfo ma
CollectNamespacesForTypeReference(field.ReturnType);
break;
case IMethod method:
var reader = module.PEFile.Reader;
var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList();
foreach (var part in parts)
{
Expand All @@ -125,7 +124,7 @@ void CollectNamespaces(IEntity entity, MetadataModule module, CodeMappingInfo ma
MethodBodyBlock body;
try
{
body = reader.GetMethodBody(methodDef.RelativeVirtualAddress);
body = module.MetadataFile.GetMethodBody(methodDef.RelativeVirtualAddress);
}
catch (BadImageFormatException)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ void HandleStaticFieldInitializers(IEnumerable<AstNode> members)
IMethod ctorMethod = staticCtor.GetSymbol() as IMethod;
if (!ctorMethod.MetadataToken.IsNil)
{
var metadata = context.TypeSystem.MainModule.PEFile.Metadata;
var metadata = context.TypeSystem.MainModule.MetadataFile.Metadata;
SRM.MethodDefinition ctorMethodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)ctorMethod.MetadataToken);
SRM.TypeDefinition declaringType = metadata.GetTypeDefinition(ctorMethodDef.GetDeclaringType());
bool declaringTypeIsBeforeFieldInit = declaringType.HasFlag(TypeAttributes.BeforeFieldInit);
Expand Down
Loading

0 comments on commit ca78d4a

Please sign in to comment.