mirror of https://github.com/icsharpcode/ILSpy.git
23 changed files with 672 additions and 492 deletions
@ -1,116 +0,0 @@
@@ -1,116 +0,0 @@
|
||||
// Copyright (c) 2014 Daniel Grunwald
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
||||
using Mono.Cecil; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// Maps from cecil types to NRefactory and vice versa.
|
||||
/// </summary>
|
||||
class NRefactoryCecilMapper |
||||
{ |
||||
readonly ITypeResolveContext context; |
||||
readonly CecilLoader cecilLoader = new CecilLoader(); |
||||
readonly Func<IUnresolvedEntity, MemberReference> nr2cecilLookup; |
||||
|
||||
/// <param name="compilation">Compilation to use for Cecil->NRefactory lookups</param>
|
||||
/// <param name="module">Compilation to use for Cecil->NRefactory lookups</param>
|
||||
/// <param name = "nr2cecilLookup">NRefactory->Cecil lookup function</param>
|
||||
internal NRefactoryCecilMapper(ICompilation compilation, ModuleDefinition module, Func<IUnresolvedEntity, MemberReference> nr2cecilLookup) |
||||
{ |
||||
this.nr2cecilLookup = nr2cecilLookup; |
||||
this.context = new SimpleTypeResolveContext(compilation.MainAssembly); |
||||
this.cecilLoader.SetCurrentModule(module); |
||||
} |
||||
|
||||
public MemberReference GetCecil(IMember member) |
||||
{ |
||||
if (member == null) |
||||
return null; |
||||
return nr2cecilLookup(member.UnresolvedMember); |
||||
} |
||||
|
||||
public MemberReference GetCecil(ITypeDefinition typeDefinition) |
||||
{ |
||||
if (typeDefinition == null) |
||||
return null; |
||||
return nr2cecilLookup(typeDefinition.Parts[0]); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Retrieves a type definition for a type defined in the compilation's main assembly.
|
||||
/// </summary>
|
||||
public IType GetType(TypeReference typeReference) |
||||
{ |
||||
if (typeReference == null) |
||||
return SpecialType.UnknownType; |
||||
var typeRef = cecilLoader.ReadTypeReference(typeReference); |
||||
return typeRef.Resolve(context); |
||||
} |
||||
|
||||
public IMethod GetMethod(MethodReference methodReference) |
||||
{ |
||||
var method = GetNonGenericMethod(methodReference.GetElementMethod()); |
||||
// TODO: specialize the method
|
||||
return method; |
||||
} |
||||
|
||||
IMethod GetNonGenericMethod(MethodReference methodReference) |
||||
{ |
||||
ITypeDefinition typeDef = GetType(methodReference.DeclaringType).GetDefinition(); |
||||
if (typeDef == null) |
||||
return null; |
||||
IEnumerable<IMethod> methods; |
||||
if (methodReference.Name == ".ctor") { |
||||
methods = typeDef.GetConstructors(); |
||||
} else if (methodReference.Name == ".cctor") { |
||||
return typeDef.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); |
||||
} else { |
||||
methods = typeDef.GetMethods(m => m.Name == methodReference.Name, GetMemberOptions.IgnoreInheritedMembers) |
||||
.Concat(typeDef.GetAccessors(m => m.Name == methodReference.Name, GetMemberOptions.IgnoreInheritedMembers)); |
||||
} |
||||
foreach (var method in methods) { |
||||
if (GetCecil(method) == methodReference) |
||||
return method; |
||||
} |
||||
var parameterTypes = methodReference.Parameters.SelectArray(p => GetType(p.ParameterType)); |
||||
foreach (var method in methods) { |
||||
if (parameterTypes.Length == method.Parameters.Count) { |
||||
bool signatureMatches = true; |
||||
for (int i = 0; i < parameterTypes.Length; i++) { |
||||
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(parameterTypes[i]); |
||||
IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(method.Parameters[i].Type); |
||||
if (!type1.Equals(type2)) { |
||||
signatureMatches = false; |
||||
break; |
||||
} |
||||
} |
||||
if (signatureMatches) |
||||
return method; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,296 @@
@@ -0,0 +1,296 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
||||
using Mono.Cecil; |
||||
|
||||
namespace ICSharpCode.Decompiler |
||||
{ |
||||
/// <summary>
|
||||
/// Manages the NRefactory type system for the decompiler.
|
||||
/// This class is thread-safe.
|
||||
/// </summary>
|
||||
public class DecompilerTypeSystem |
||||
{ |
||||
readonly ModuleDefinition moduleDefinition; |
||||
readonly ICompilation compilation; |
||||
readonly ITypeResolveContext context; |
||||
|
||||
/// <summary>
|
||||
/// CecilLoader used for converting cecil type references to ITypeReference.
|
||||
/// May only be accessed within lock(cecilLoader).
|
||||
/// </summary>
|
||||
CecilLoader typeReferenceCecilLoader = new CecilLoader(); |
||||
|
||||
/// <summary>
|
||||
/// Dictionary for NRefactory->Cecil lookup. Only contains entities from the main module.
|
||||
/// May only be accessed within lock(entityDict)
|
||||
/// </summary>
|
||||
Dictionary<IUnresolvedEntity, MemberReference> entityDict = new Dictionary<IUnresolvedEntity, MemberReference>(); |
||||
|
||||
Dictionary<FieldReference, IField> fieldLookupCache = new Dictionary<FieldReference, IField>(); |
||||
Dictionary<MethodReference, IMethod> methodLookupCache = new Dictionary<MethodReference, IMethod>(); |
||||
|
||||
public DecompilerTypeSystem(ModuleDefinition moduleDefinition) |
||||
{ |
||||
if (moduleDefinition == null) |
||||
throw new ArgumentNullException("moduleDefinition"); |
||||
this.moduleDefinition = moduleDefinition; |
||||
CecilLoader mainAssemblyCecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference }; |
||||
CecilLoader referencedAssemblyCecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true }; |
||||
typeReferenceCecilLoader.SetCurrentModule(moduleDefinition); |
||||
IUnresolvedAssembly mainAssembly = mainAssemblyCecilLoader.LoadModule(moduleDefinition); |
||||
var referencedAssemblies = new List<IUnresolvedAssembly>(); |
||||
foreach (var asmRef in moduleDefinition.AssemblyReferences) { |
||||
var asm = moduleDefinition.AssemblyResolver.Resolve(asmRef); |
||||
if (asm != null) |
||||
referencedAssemblies.Add(referencedAssemblyCecilLoader.LoadAssembly(asm)); |
||||
} |
||||
compilation = new SimpleCompilation(mainAssembly, referencedAssemblies); |
||||
context = new SimpleTypeResolveContext(compilation.MainAssembly); |
||||
} |
||||
|
||||
public ICompilation Compilation |
||||
{ |
||||
get { return compilation; } |
||||
} |
||||
|
||||
public ModuleDefinition ModuleDefinition |
||||
{ |
||||
get { return moduleDefinition; } |
||||
} |
||||
|
||||
void StoreMemberReference(IUnresolvedEntity entity, MemberReference mr) |
||||
{ |
||||
// This is a callback from the type system, which is multi-threaded and may be accessed externally
|
||||
lock (entityDict) |
||||
entityDict[entity] = mr; |
||||
} |
||||
|
||||
MemberReference GetCecil(IUnresolvedEntity member) |
||||
{ |
||||
lock (entityDict) { |
||||
MemberReference mr; |
||||
if (member != null && entityDict.TryGetValue(member, out mr)) |
||||
return mr; |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Retrieves the Cecil member definition for the specified member.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns null if the member is not defined in the module being decompiled.
|
||||
/// </remarks>
|
||||
public MemberReference GetCecil(IMember member) |
||||
{ |
||||
if (member == null) |
||||
return null; |
||||
return GetCecil(member.UnresolvedMember); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Retrieves the Cecil type definition.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns null if the type is not defined in the module being decompiled.
|
||||
/// </remarks>
|
||||
public TypeDefinition GetCecil(ITypeDefinition typeDefinition) |
||||
{ |
||||
if (typeDefinition == null) |
||||
return null; |
||||
return GetCecil(typeDefinition.Parts[0]) as TypeDefinition; |
||||
} |
||||
|
||||
#region Resolve Type
|
||||
/// <summary>
|
||||
/// Retrieves a type definition for a type defined in the compilation's main assembly.
|
||||
/// </summary>
|
||||
public IType GetType(TypeReference typeReference) |
||||
{ |
||||
if (typeReference == null) |
||||
return SpecialType.UnknownType; |
||||
ITypeReference typeRef; |
||||
lock (typeReferenceCecilLoader) |
||||
typeRef = typeReferenceCecilLoader.ReadTypeReference(typeReference); |
||||
return typeRef.Resolve(context); |
||||
} |
||||
#endregion
|
||||
|
||||
#region Resolve Field
|
||||
public IField GetField(FieldReference fieldReference) |
||||
{ |
||||
if (fieldReference == null) |
||||
throw new ArgumentNullException("fieldReference"); |
||||
lock (fieldLookupCache) { |
||||
IField field; |
||||
if (!fieldLookupCache.TryGetValue(fieldReference, out field)) { |
||||
field = GetNonGenericField(fieldReference); |
||||
// TODO: specialize the field if necessary
|
||||
fieldLookupCache[fieldReference] = field; |
||||
} |
||||
return field; |
||||
} |
||||
} |
||||
|
||||
IField GetNonGenericField(FieldReference fieldReference) |
||||
{ |
||||
Debug.Assert(Monitor.IsEntered(fieldLookupCache)); |
||||
IField field; |
||||
if (!fieldLookupCache.TryGetValue(fieldReference, out field)) { |
||||
field = FindNonGenericField(fieldReference); |
||||
fieldLookupCache.Add(fieldReference, field); |
||||
} |
||||
return field; |
||||
} |
||||
|
||||
IField FindNonGenericField(FieldReference fieldReference) |
||||
{ |
||||
ITypeDefinition typeDef = GetType(fieldReference.DeclaringType).GetDefinition(); |
||||
if (typeDef == null) |
||||
return CreateFakeField(fieldReference); |
||||
foreach (IField field in typeDef.Fields) |
||||
if (field.Name == fieldReference.Name) |
||||
return field; |
||||
return CreateFakeField(fieldReference); |
||||
} |
||||
|
||||
IField CreateFakeField(FieldReference fieldReference) |
||||
{ |
||||
var declaringType = GetType(fieldReference.DeclaringType); |
||||
var f = new DefaultUnresolvedField(); |
||||
f.Name = fieldReference.Name; |
||||
f.ReturnType = typeReferenceCecilLoader.ReadTypeReference(fieldReference.FieldType); |
||||
return new ResolvedFakeField(f, context, declaringType); |
||||
} |
||||
|
||||
class ResolvedFakeField : DefaultResolvedField |
||||
{ |
||||
readonly IType declaringType; |
||||
|
||||
public ResolvedFakeField(DefaultUnresolvedField unresolved, ITypeResolveContext parentContext, IType declaringType) |
||||
: base(unresolved, parentContext) |
||||
{ |
||||
this.declaringType = declaringType; |
||||
} |
||||
|
||||
public override IType DeclaringType |
||||
{ |
||||
get { return declaringType; } |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region Resolve Method
|
||||
public IMethod GetMethod(MethodReference methodReference) |
||||
{ |
||||
if (methodReference == null) |
||||
throw new ArgumentNullException("methodReference"); |
||||
lock (methodLookupCache) { |
||||
IMethod method; |
||||
if (!methodLookupCache.TryGetValue(methodReference, out method)) { |
||||
method = GetNonGenericMethod(methodReference.GetElementMethod()); |
||||
// TODO: specialize the method
|
||||
|
||||
methodLookupCache[methodReference] = method; |
||||
} |
||||
return method; |
||||
} |
||||
} |
||||
|
||||
IMethod GetNonGenericMethod(MethodReference methodReference) |
||||
{ |
||||
Debug.Assert(Monitor.IsEntered(methodLookupCache)); |
||||
IMethod method; |
||||
if (!methodLookupCache.TryGetValue(methodReference, out method)) { |
||||
method = FindNonGenericMethod(methodReference); |
||||
methodLookupCache.Add(methodReference, method); |
||||
} |
||||
return method; |
||||
} |
||||
|
||||
IMethod FindNonGenericMethod(MethodReference methodReference) |
||||
{ |
||||
ITypeDefinition typeDef = GetType(methodReference.DeclaringType).GetDefinition(); |
||||
if (typeDef == null) |
||||
return CreateFakeMethod(methodReference); |
||||
IEnumerable<IMethod> methods; |
||||
if (methodReference.Name == ".ctor") { |
||||
methods = typeDef.GetConstructors(); |
||||
} else if (methodReference.Name == ".cctor") { |
||||
return typeDef.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); |
||||
} else { |
||||
methods = typeDef.GetMethods(m => m.Name == methodReference.Name, GetMemberOptions.IgnoreInheritedMembers) |
||||
.Concat(typeDef.GetAccessors(m => m.Name == methodReference.Name, GetMemberOptions.IgnoreInheritedMembers)); |
||||
} |
||||
foreach (var method in methods) { |
||||
if (GetCecil(method) == methodReference) |
||||
return method; |
||||
} |
||||
var parameterTypes = methodReference.Parameters.SelectArray(p => GetType(p.ParameterType)); |
||||
foreach (var method in methods) { |
||||
if (CompareSignatures(method.Parameters, parameterTypes)) |
||||
return method; |
||||
} |
||||
return CreateFakeMethod(methodReference); |
||||
} |
||||
|
||||
static bool CompareSignatures(IList<IParameter> parameters, IType[] parameterTypes) |
||||
{ |
||||
if (parameterTypes.Length != parameters.Count) |
||||
return false; |
||||
for (int i = 0; i < parameterTypes.Length; i++) { |
||||
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(parameterTypes[i]); |
||||
IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(parameters[i].Type); |
||||
if (!type1.Equals(type2)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Create a dummy IMethod from the specified MethodReference
|
||||
/// </summary>
|
||||
IMethod CreateFakeMethod(MethodReference methodReference) |
||||
{ |
||||
var declaringTypeReference = typeReferenceCecilLoader.ReadTypeReference(methodReference.DeclaringType); |
||||
var m = new DefaultUnresolvedMethod(); |
||||
if (methodReference.Name == ".ctor" || methodReference.Name == ".cctor") |
||||
m.SymbolKind = SymbolKind.Constructor; |
||||
m.Name = methodReference.Name; |
||||
m.ReturnType = typeReferenceCecilLoader.ReadTypeReference(methodReference.ReturnType); |
||||
m.IsStatic = !methodReference.HasThis; |
||||
for (int i = 0; i < methodReference.GenericParameters.Count; i++) { |
||||
m.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, i, methodReference.GenericParameters[i].Name)); |
||||
} |
||||
foreach (var p in methodReference.Parameters) { |
||||
m.Parameters.Add(new DefaultUnresolvedParameter(typeReferenceCecilLoader.ReadTypeReference(p.ParameterType), p.Name)); |
||||
} |
||||
return new ResolvedFakeMethod(m, context, declaringTypeReference.Resolve(context)); |
||||
} |
||||
|
||||
class ResolvedFakeMethod : DefaultResolvedMethod |
||||
{ |
||||
readonly IType declaringType; |
||||
|
||||
public ResolvedFakeMethod(DefaultUnresolvedMethod unresolved, ITypeResolveContext parentContext, IType declaringType) |
||||
: base(unresolved, parentContext) |
||||
{ |
||||
this.declaringType = declaringType; |
||||
} |
||||
|
||||
public override IType DeclaringType |
||||
{ |
||||
get { return declaringType; } |
||||
} |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
Loading…
Reference in new issue