Update the code that resolves typedefs
This commit is contained in:
parent
d6ba1fa2d5
commit
2734a9ee95
|
@ -117,6 +117,33 @@ namespace de4dot.blocks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TypeReferenceSameVersionKey {
|
||||||
|
readonly TypeReference typeRef;
|
||||||
|
|
||||||
|
public TypeReference TypeReference {
|
||||||
|
get { return typeRef; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeReferenceSameVersionKey(TypeReference typeRef) {
|
||||||
|
this.typeRef = typeRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() {
|
||||||
|
return MemberReferenceHelper.typeReferenceHashCodeSameVersion(typeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj) {
|
||||||
|
var other = obj as TypeReferenceSameVersionKey;
|
||||||
|
if (other == null)
|
||||||
|
return false;
|
||||||
|
return MemberReferenceHelper.compareTypeReferenceSameVersion(typeRef, other.typeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return typeRef.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class FieldReferenceKey {
|
public class FieldReferenceKey {
|
||||||
readonly FieldReference fieldRef;
|
readonly FieldReference fieldRef;
|
||||||
|
|
||||||
|
@ -333,17 +360,14 @@ namespace de4dot.blocks {
|
||||||
return string.Format("[{0}]{1}", getCanonicalizedScopeName(scope), fullName);
|
return string.Format("[{0}]{1}", getCanonicalizedScopeName(scope), fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string getCanonicalizedScopeName(IMetadataScope scope) {
|
public static AssemblyNameReference getAssemblyNameReference(IMetadataScope scope) {
|
||||||
AssemblyNameReference asmRef = null;
|
|
||||||
|
|
||||||
switch (scope.MetadataScopeType) {
|
switch (scope.MetadataScopeType) {
|
||||||
case MetadataScopeType.AssemblyNameReference:
|
case MetadataScopeType.AssemblyNameReference:
|
||||||
asmRef = (AssemblyNameReference)scope;
|
return (AssemblyNameReference)scope;
|
||||||
break;
|
|
||||||
case MetadataScopeType.ModuleDefinition:
|
case MetadataScopeType.ModuleDefinition:
|
||||||
var module = (ModuleDefinition)scope;
|
var module = (ModuleDefinition)scope;
|
||||||
if (module.Assembly != null)
|
if (module.Assembly != null)
|
||||||
asmRef = module.Assembly.Name;
|
return module.Assembly.Name;
|
||||||
break;
|
break;
|
||||||
case MetadataScopeType.ModuleReference:
|
case MetadataScopeType.ModuleReference:
|
||||||
break;
|
break;
|
||||||
|
@ -351,6 +375,11 @@ namespace de4dot.blocks {
|
||||||
throw new ApplicationException(string.Format("Invalid scope type: {0}", scope.GetType()));
|
throw new ApplicationException(string.Format("Invalid scope type: {0}", scope.GetType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string getCanonicalizedScopeName(IMetadataScope scope) {
|
||||||
|
var asmRef = getAssemblyNameReference(scope);
|
||||||
if (asmRef != null) {
|
if (asmRef != null) {
|
||||||
// The version number should be ignored. Older code may reference an old version of
|
// The version number should be ignored. Older code may reference an old version of
|
||||||
// the assembly, but if the newer one has been loaded, that one is used.
|
// the assembly, but if the newer one has been loaded, that one is used.
|
||||||
|
@ -359,6 +388,13 @@ namespace de4dot.blocks {
|
||||||
return string.Format("{0}", scope.ToString().ToLowerInvariant());
|
return string.Format("{0}", scope.ToString().ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string getCanonicalizedScopeAndVersion(IMetadataScope scope) {
|
||||||
|
var asmRef = getAssemblyNameReference(scope);
|
||||||
|
if (asmRef != null)
|
||||||
|
return string.Format("{0}, Version={1}", asmRef.Name.ToLowerInvariant(), asmRef.Version);
|
||||||
|
return string.Format("{0}, Version=", scope.ToString().ToLowerInvariant());
|
||||||
|
}
|
||||||
|
|
||||||
public static bool compareScope(IMetadataScope a, IMetadataScope b) {
|
public static bool compareScope(IMetadataScope a, IMetadataScope b) {
|
||||||
if (ReferenceEquals(a, b))
|
if (ReferenceEquals(a, b))
|
||||||
return true;
|
return true;
|
||||||
|
@ -373,6 +409,20 @@ namespace de4dot.blocks {
|
||||||
return getCanonicalizedScopeName(a).GetHashCode();
|
return getCanonicalizedScopeName(a).GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool compareScopeSameVersion(IMetadataScope a, IMetadataScope b) {
|
||||||
|
if (ReferenceEquals(a, b))
|
||||||
|
return true;
|
||||||
|
if (a == null || b == null)
|
||||||
|
return false;
|
||||||
|
return getCanonicalizedScopeAndVersion(a) == getCanonicalizedScopeAndVersion(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int scopeHashCodeSameVersion(IMetadataScope a) {
|
||||||
|
if (a == null)
|
||||||
|
return 0;
|
||||||
|
return getCanonicalizedScopeAndVersion(a).GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
public static bool compareEventReference(EventReference a, EventReference b) {
|
public static bool compareEventReference(EventReference a, EventReference b) {
|
||||||
if (ReferenceEquals(a, b))
|
if (ReferenceEquals(a, b))
|
||||||
return true;
|
return true;
|
||||||
|
@ -811,6 +861,39 @@ namespace de4dot.blocks {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool compareTypeReferenceSameVersion(TypeReference a, TypeReference b) {
|
||||||
|
if (ReferenceEquals(a, b))
|
||||||
|
return true;
|
||||||
|
if (a == null || b == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((a.GetType() != typeof(TypeReference) && a.GetType() != typeof(TypeDefinition)) ||
|
||||||
|
(b.GetType() != typeof(TypeReference) && b.GetType() != typeof(TypeDefinition)))
|
||||||
|
throw new ApplicationException("arg must be exactly of type TypeReference or TypeDefinition");
|
||||||
|
|
||||||
|
return a.Name == b.Name &&
|
||||||
|
a.Namespace == b.Namespace &&
|
||||||
|
compareTypeReferenceSameVersion(a.DeclaringType, b.DeclaringType) &&
|
||||||
|
compareScopeSameVersion(a.Scope, b.Scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int typeReferenceHashCodeSameVersion(TypeReference a) {
|
||||||
|
if (a == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (a.GetType() != typeof(TypeReference) && a.GetType() != typeof(TypeDefinition))
|
||||||
|
throw new ApplicationException("arg must be exactly of type TypeReference or TypeDefinition");
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
res += a.Name.GetHashCode();
|
||||||
|
res += a.Namespace.GetHashCode();
|
||||||
|
res += typeReferenceHashCodeSameVersion(a.DeclaringType);
|
||||||
|
res += scopeHashCodeSameVersion(a.Scope);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static bool compareGenericParameterProvider(IGenericParameterProvider a, IGenericParameterProvider b) {
|
static bool compareGenericParameterProvider(IGenericParameterProvider a, IGenericParameterProvider b) {
|
||||||
if (ReferenceEquals(a, b))
|
if (ReferenceEquals(a, b))
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -225,7 +225,107 @@ namespace de4dot.renamer.asmmodules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<TypeReferenceKey, TypeDef> otherTypesDict = new Dictionary<TypeReferenceKey, TypeDef>();
|
class AssemblyKeyDictionary<T> where T : class {
|
||||||
|
Dictionary<TypeReferenceSameVersionKey, T> dict = new Dictionary<TypeReferenceSameVersionKey, T>();
|
||||||
|
Dictionary<TypeReferenceKey, List<TypeReference>> refs = new Dictionary<TypeReferenceKey, List<TypeReference>>();
|
||||||
|
|
||||||
|
public T this[TypeReference type] {
|
||||||
|
get {
|
||||||
|
T value;
|
||||||
|
if (tryGetValue(type, out value))
|
||||||
|
return value;
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
var key = new TypeReferenceSameVersionKey(type);
|
||||||
|
dict[key] = value;
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
var key2 = new TypeReferenceKey(type);
|
||||||
|
List<TypeReference> list;
|
||||||
|
if (!refs.TryGetValue(key2, out list))
|
||||||
|
refs[key2] = list = new List<TypeReference>();
|
||||||
|
list.Add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool tryGetValue(TypeReference type, out T value) {
|
||||||
|
var key = new TypeReferenceSameVersionKey(type);
|
||||||
|
if (dict.TryGetValue(key, out value))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool tryGetSimilarValue(TypeReference type, out T value) {
|
||||||
|
var key2 = new TypeReferenceKey(type);
|
||||||
|
List<TypeReference> list;
|
||||||
|
if (!refs.TryGetValue(key2, out list)) {
|
||||||
|
value = default(T);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a type whose version is >= type's version and closest to it.
|
||||||
|
|
||||||
|
TypeReference foundType = null;
|
||||||
|
var typeAsmName = MemberReferenceHelper.getAssemblyNameReference(type.Scope);
|
||||||
|
AssemblyNameReference foundAsmName = null;
|
||||||
|
foreach (var otherRef in list) {
|
||||||
|
var key = new TypeReferenceSameVersionKey(otherRef);
|
||||||
|
if (!dict.TryGetValue(key, out value))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (typeAsmName == null) {
|
||||||
|
foundType = otherRef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var otherAsmName = MemberReferenceHelper.getAssemblyNameReference(otherRef.Scope);
|
||||||
|
if (otherAsmName == null)
|
||||||
|
continue;
|
||||||
|
// Check pkt or we could return a type in eg. a SL assembly when it's not a SL app.
|
||||||
|
if (!same(typeAsmName.PublicKeyToken, otherAsmName.PublicKeyToken))
|
||||||
|
continue;
|
||||||
|
if (typeAsmName.Version > otherAsmName.Version)
|
||||||
|
continue; // old version
|
||||||
|
|
||||||
|
if (foundType == null) {
|
||||||
|
foundAsmName = otherAsmName;
|
||||||
|
foundType = otherRef;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundAsmName.Version <= otherAsmName.Version)
|
||||||
|
continue;
|
||||||
|
foundAsmName = otherAsmName;
|
||||||
|
foundType = otherRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundType != null) {
|
||||||
|
value = dict[new TypeReferenceSameVersionKey(foundType)];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default(T);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool same(byte[] a, byte[] b) {
|
||||||
|
if (ReferenceEquals(a, b))
|
||||||
|
return true;
|
||||||
|
if (a == null || b == null)
|
||||||
|
return false;
|
||||||
|
if (a.Length != b.Length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < a.Length; i++) {
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssemblyKeyDictionary<TypeDef> typeToTypeDefDict = new AssemblyKeyDictionary<TypeDef>();
|
||||||
ExternalAssemblies externalAssemblies = new ExternalAssemblies();
|
ExternalAssemblies externalAssemblies = new ExternalAssemblies();
|
||||||
TypeDef resolveOther(TypeReference type) {
|
TypeDef resolveOther(TypeReference type) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
|
@ -233,14 +333,23 @@ namespace de4dot.renamer.asmmodules {
|
||||||
type = type.GetElementType();
|
type = type.GetElementType();
|
||||||
|
|
||||||
TypeDef typeDef;
|
TypeDef typeDef;
|
||||||
var key = new TypeReferenceKey(type);
|
if (typeToTypeDefDict.tryGetValue(type, out typeDef))
|
||||||
if (otherTypesDict.TryGetValue(key, out typeDef))
|
|
||||||
return typeDef;
|
return typeDef;
|
||||||
otherTypesDict[key] = null; // In case of a circular reference
|
|
||||||
|
|
||||||
TypeDefinition typeDefinition = externalAssemblies.resolve(type);
|
var typeDefinition = externalAssemblies.resolve(type);
|
||||||
if (typeDefinition == null)
|
if (typeDefinition == null) {
|
||||||
return null;
|
typeToTypeDefDict.tryGetSimilarValue(type, out typeDef);
|
||||||
|
typeToTypeDefDict[type] = typeDef;
|
||||||
|
return typeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeToTypeDefDict.tryGetValue(typeDefinition, out typeDef)) {
|
||||||
|
typeToTypeDefDict[type] = typeDef;
|
||||||
|
return typeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
typeToTypeDefDict[type] = null; // In case of a circular reference
|
||||||
|
typeToTypeDefDict[typeDefinition] = null;
|
||||||
|
|
||||||
typeDef = new TypeDef(typeDefinition, null, 0);
|
typeDef = new TypeDef(typeDefinition, null, 0);
|
||||||
typeDef.addMembers();
|
typeDef.addMembers();
|
||||||
|
@ -253,7 +362,11 @@ namespace de4dot.renamer.asmmodules {
|
||||||
var baseDef = resolveOther(typeDef.TypeDefinition.BaseType);
|
var baseDef = resolveOther(typeDef.TypeDefinition.BaseType);
|
||||||
if (baseDef != null)
|
if (baseDef != null)
|
||||||
typeDef.addBaseType(baseDef, typeDef.TypeDefinition.BaseType);
|
typeDef.addBaseType(baseDef, typeDef.TypeDefinition.BaseType);
|
||||||
return otherTypesDict[key] = typeDef;
|
|
||||||
|
typeToTypeDefDict[type] = typeDef;
|
||||||
|
if (type != typeDefinition)
|
||||||
|
typeToTypeDefDict[typeDefinition] = typeDef;
|
||||||
|
return typeDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodNameScopes initializeVirtualMembers() {
|
public MethodNameScopes initializeVirtualMembers() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user