Update the code that resolves typedefs

This commit is contained in:
de4dot 2011-12-01 22:32:09 +01:00
parent d6ba1fa2d5
commit 2734a9ee95
2 changed files with 210 additions and 14 deletions

View File

@ -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;

View File

@ -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() {