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 {
|
||||
readonly FieldReference fieldRef;
|
||||
|
||||
|
@ -333,17 +360,14 @@ namespace de4dot.blocks {
|
|||
return string.Format("[{0}]{1}", getCanonicalizedScopeName(scope), fullName);
|
||||
}
|
||||
|
||||
public static string getCanonicalizedScopeName(IMetadataScope scope) {
|
||||
AssemblyNameReference asmRef = null;
|
||||
|
||||
public static AssemblyNameReference getAssemblyNameReference(IMetadataScope scope) {
|
||||
switch (scope.MetadataScopeType) {
|
||||
case MetadataScopeType.AssemblyNameReference:
|
||||
asmRef = (AssemblyNameReference)scope;
|
||||
break;
|
||||
return (AssemblyNameReference)scope;
|
||||
case MetadataScopeType.ModuleDefinition:
|
||||
var module = (ModuleDefinition)scope;
|
||||
if (module.Assembly != null)
|
||||
asmRef = module.Assembly.Name;
|
||||
return module.Assembly.Name;
|
||||
break;
|
||||
case MetadataScopeType.ModuleReference:
|
||||
break;
|
||||
|
@ -351,6 +375,11 @@ namespace de4dot.blocks {
|
|||
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) {
|
||||
// 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.
|
||||
|
@ -359,6 +388,13 @@ namespace de4dot.blocks {
|
|||
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) {
|
||||
if (ReferenceEquals(a, b))
|
||||
return true;
|
||||
|
@ -373,6 +409,20 @@ namespace de4dot.blocks {
|
|||
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) {
|
||||
if (ReferenceEquals(a, b))
|
||||
return true;
|
||||
|
@ -811,6 +861,39 @@ namespace de4dot.blocks {
|
|||
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) {
|
||||
if (ReferenceEquals(a, b))
|
||||
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();
|
||||
TypeDef resolveOther(TypeReference type) {
|
||||
if (type == null)
|
||||
|
@ -233,14 +333,23 @@ namespace de4dot.renamer.asmmodules {
|
|||
type = type.GetElementType();
|
||||
|
||||
TypeDef typeDef;
|
||||
var key = new TypeReferenceKey(type);
|
||||
if (otherTypesDict.TryGetValue(key, out typeDef))
|
||||
if (typeToTypeDefDict.tryGetValue(type, out typeDef))
|
||||
return typeDef;
|
||||
otherTypesDict[key] = null; // In case of a circular reference
|
||||
|
||||
TypeDefinition typeDefinition = externalAssemblies.resolve(type);
|
||||
if (typeDefinition == null)
|
||||
return null;
|
||||
var typeDefinition = externalAssemblies.resolve(type);
|
||||
if (typeDefinition == 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.addMembers();
|
||||
|
@ -253,7 +362,11 @@ namespace de4dot.renamer.asmmodules {
|
|||
var baseDef = resolveOther(typeDef.TypeDefinition.BaseType);
|
||||
if (baseDef != null)
|
||||
typeDef.addBaseType(baseDef, typeDef.TypeDefinition.BaseType);
|
||||
return otherTypesDict[key] = typeDef;
|
||||
|
||||
typeToTypeDefDict[type] = typeDef;
|
||||
if (type != typeDefinition)
|
||||
typeToTypeDefDict[typeDefinition] = typeDef;
|
||||
return typeDef;
|
||||
}
|
||||
|
||||
public MethodNameScopes initializeVirtualMembers() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user