diff options
| author | 2015-03-30 23:56:21 -0400 | |
|---|---|---|
| committer | 2015-03-30 23:56:21 -0400 | |
| commit | 2fc8ae770442ec3ab91cf0c16cc30917e0d048d3 (patch) | |
| tree | a49e9ede649fb0f350fee1b8336f319df20f4973 /src/cuchaz/enigma/analysis/TranslationIndex.java | |
| parent | add publifier (diff) | |
| download | enigma-fork-2fc8ae770442ec3ab91cf0c16cc30917e0d048d3.tar.gz enigma-fork-2fc8ae770442ec3ab91cf0c16cc30917e0d048d3.tar.xz enigma-fork-2fc8ae770442ec3ab91cf0c16cc30917e0d048d3.zip | |
resolve methods using interfaces as well as superclasses
Diffstat (limited to '')
| -rw-r--r-- | src/cuchaz/enigma/analysis/TranslationIndex.java | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index bd77344..e0e66bf 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java | |||
| @@ -16,6 +16,7 @@ import java.io.ObjectInputStream; | |||
| 16 | import java.io.ObjectOutputStream; | 16 | import java.io.ObjectOutputStream; |
| 17 | import java.io.OutputStream; | 17 | import java.io.OutputStream; |
| 18 | import java.io.Serializable; | 18 | import java.io.Serializable; |
| 19 | import java.util.Collection; | ||
| 19 | import java.util.HashMap; | 20 | import java.util.HashMap; |
| 20 | import java.util.List; | 21 | import java.util.List; |
| 21 | import java.util.Map; | 22 | import java.util.Map; |
| @@ -26,6 +27,7 @@ import java.util.zip.GZIPOutputStream; | |||
| 26 | import javassist.CtBehavior; | 27 | import javassist.CtBehavior; |
| 27 | import javassist.CtClass; | 28 | import javassist.CtClass; |
| 28 | import javassist.CtField; | 29 | import javassist.CtField; |
| 30 | import javassist.bytecode.Descriptor; | ||
| 29 | 31 | ||
| 30 | import com.google.common.collect.HashMultimap; | 32 | import com.google.common.collect.HashMultimap; |
| 31 | import com.google.common.collect.Lists; | 33 | import com.google.common.collect.Lists; |
| @@ -36,8 +38,8 @@ import cuchaz.enigma.mapping.ArgumentEntry; | |||
| 36 | import cuchaz.enigma.mapping.BehaviorEntry; | 38 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 37 | import cuchaz.enigma.mapping.ClassEntry; | 39 | import cuchaz.enigma.mapping.ClassEntry; |
| 38 | import cuchaz.enigma.mapping.Entry; | 40 | import cuchaz.enigma.mapping.Entry; |
| 39 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 40 | import cuchaz.enigma.mapping.EntryFactory; | 41 | import cuchaz.enigma.mapping.EntryFactory; |
| 42 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 41 | import cuchaz.enigma.mapping.Translator; | 43 | import cuchaz.enigma.mapping.Translator; |
| 42 | 44 | ||
| 43 | public class TranslationIndex implements Serializable { | 45 | public class TranslationIndex implements Serializable { |
| @@ -47,11 +49,13 @@ public class TranslationIndex implements Serializable { | |||
| 47 | private Map<ClassEntry,ClassEntry> m_superclasses; | 49 | private Map<ClassEntry,ClassEntry> m_superclasses; |
| 48 | private Multimap<ClassEntry,FieldEntry> m_fieldEntries; | 50 | private Multimap<ClassEntry,FieldEntry> m_fieldEntries; |
| 49 | private Multimap<ClassEntry,BehaviorEntry> m_behaviorEntries; | 51 | private Multimap<ClassEntry,BehaviorEntry> m_behaviorEntries; |
| 52 | private Multimap<ClassEntry,ClassEntry> m_interfaces; | ||
| 50 | 53 | ||
| 51 | public TranslationIndex() { | 54 | public TranslationIndex() { |
| 52 | m_superclasses = Maps.newHashMap(); | 55 | m_superclasses = Maps.newHashMap(); |
| 53 | m_fieldEntries = HashMultimap.create(); | 56 | m_fieldEntries = HashMultimap.create(); |
| 54 | m_behaviorEntries = HashMultimap.create(); | 57 | m_behaviorEntries = HashMultimap.create(); |
| 58 | m_interfaces = HashMultimap.create(); | ||
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | public TranslationIndex(TranslationIndex other, Translator translator) { | 61 | public TranslationIndex(TranslationIndex other, Translator translator) { |
| @@ -65,6 +69,15 @@ public class TranslationIndex implements Serializable { | |||
| 65 | ); | 69 | ); |
| 66 | } | 70 | } |
| 67 | 71 | ||
| 72 | // translate the interfaces | ||
| 73 | m_interfaces = HashMultimap.create(); | ||
| 74 | for (Map.Entry<ClassEntry,ClassEntry> mapEntry : other.m_interfaces.entries()) { | ||
| 75 | m_interfaces.put( | ||
| 76 | translator.translateEntry(mapEntry.getKey()), | ||
| 77 | translator.translateEntry(mapEntry.getValue()) | ||
| 78 | ); | ||
| 79 | } | ||
| 80 | |||
| 68 | // translate the fields | 81 | // translate the fields |
| 69 | m_fieldEntries = HashMultimap.create(); | 82 | m_fieldEntries = HashMultimap.create(); |
| 70 | for (Map.Entry<ClassEntry,FieldEntry> mapEntry : other.m_fieldEntries.entries()) { | 83 | for (Map.Entry<ClassEntry,FieldEntry> mapEntry : other.m_fieldEntries.entries()) { |
| @@ -90,13 +103,24 @@ public class TranslationIndex implements Serializable { | |||
| 90 | public void indexClass(CtClass c, boolean indexMembers) { | 103 | public void indexClass(CtClass c, boolean indexMembers) { |
| 91 | 104 | ||
| 92 | ClassEntry classEntry = EntryFactory.getClassEntry(c); | 105 | ClassEntry classEntry = EntryFactory.getClassEntry(c); |
| 106 | if (isJre(classEntry)) { | ||
| 107 | return; | ||
| 108 | } | ||
| 93 | 109 | ||
| 94 | // add the superclass | 110 | // add the superclass |
| 95 | ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); | 111 | ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); |
| 96 | if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { | 112 | if (superclassEntry != null && !isJre(superclassEntry)) { |
| 97 | m_superclasses.put(classEntry, superclassEntry); | 113 | m_superclasses.put(classEntry, superclassEntry); |
| 98 | } | 114 | } |
| 99 | 115 | ||
| 116 | // add the interfaces | ||
| 117 | for (String interfaceClassName : c.getClassFile().getInterfaces()) { | ||
| 118 | ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName)); | ||
| 119 | if (!isJre(interfaceClassEntry)) { | ||
| 120 | m_interfaces.put(classEntry, interfaceClassEntry); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 100 | if (indexMembers) { | 124 | if (indexMembers) { |
| 101 | // add fields | 125 | // add fields |
| 102 | for (CtField field : c.getDeclaredFields()) { | 126 | for (CtField field : c.getDeclaredFields()) { |
| @@ -134,6 +158,7 @@ public class TranslationIndex implements Serializable { | |||
| 134 | } | 158 | } |
| 135 | 159 | ||
| 136 | public List<ClassEntry> getSubclass(ClassEntry classEntry) { | 160 | public List<ClassEntry> getSubclass(ClassEntry classEntry) { |
| 161 | |||
| 137 | // linear search is fast enough for now | 162 | // linear search is fast enough for now |
| 138 | List<ClassEntry> subclasses = Lists.newArrayList(); | 163 | List<ClassEntry> subclasses = Lists.newArrayList(); |
| 139 | for (Map.Entry<ClassEntry,ClassEntry> entry : m_superclasses.entrySet()) { | 164 | for (Map.Entry<ClassEntry,ClassEntry> entry : m_superclasses.entrySet()) { |
| @@ -160,6 +185,18 @@ public class TranslationIndex implements Serializable { | |||
| 160 | } | 185 | } |
| 161 | } | 186 | } |
| 162 | 187 | ||
| 188 | public Collection<Map.Entry<ClassEntry,ClassEntry>> getClassInterfaces() { | ||
| 189 | return m_interfaces.entries(); | ||
| 190 | } | ||
| 191 | |||
| 192 | public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) { | ||
| 193 | return m_interfaces.get(classEntry); | ||
| 194 | } | ||
| 195 | |||
| 196 | public boolean isInterface(ClassEntry classEntry) { | ||
| 197 | return m_interfaces.containsValue(classEntry); | ||
| 198 | } | ||
| 199 | |||
| 163 | public boolean entryExists(Entry entry) { | 200 | public boolean entryExists(Entry entry) { |
| 164 | if (entry instanceof FieldEntry) { | 201 | if (entry instanceof FieldEntry) { |
| 165 | return fieldExists((FieldEntry)entry); | 202 | return fieldExists((FieldEntry)entry); |
| @@ -185,6 +222,21 @@ public class TranslationIndex implements Serializable { | |||
| 185 | return (ClassEntry)entry; | 222 | return (ClassEntry)entry; |
| 186 | } | 223 | } |
| 187 | 224 | ||
| 225 | ClassEntry superclassEntry = resolveSuperclass(entry); | ||
| 226 | if (superclassEntry != null) { | ||
| 227 | return superclassEntry; | ||
| 228 | } | ||
| 229 | |||
| 230 | ClassEntry interfaceEntry = resolveInterface(entry); | ||
| 231 | if (interfaceEntry != null) { | ||
| 232 | return interfaceEntry; | ||
| 233 | } | ||
| 234 | |||
| 235 | return null; | ||
| 236 | } | ||
| 237 | |||
| 238 | public ClassEntry resolveSuperclass(Entry entry) { | ||
| 239 | |||
| 188 | // this entry could refer to a method on a class where the method is not actually implemented | 240 | // this entry could refer to a method on a class where the method is not actually implemented |
| 189 | // travel up the inheritance tree to find the closest implementation | 241 | // travel up the inheritance tree to find the closest implementation |
| 190 | while (!entryExists(entry)) { | 242 | while (!entryExists(entry)) { |
| @@ -203,6 +255,19 @@ public class TranslationIndex implements Serializable { | |||
| 203 | return entry.getClassEntry(); | 255 | return entry.getClassEntry(); |
| 204 | } | 256 | } |
| 205 | 257 | ||
| 258 | public ClassEntry resolveInterface(Entry entry) { | ||
| 259 | |||
| 260 | // the interfaces for any class is a forest | ||
| 261 | // so let's look at all the trees | ||
| 262 | for (ClassEntry interfaceEntry : m_interfaces.get(entry.getClassEntry())) { | ||
| 263 | ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry)); | ||
| 264 | if (resolvedClassEntry != null) { | ||
| 265 | return resolvedClassEntry; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | return null; | ||
| 269 | } | ||
| 270 | |||
| 206 | private boolean isJre(ClassEntry classEntry) { | 271 | private boolean isJre(ClassEntry classEntry) { |
| 207 | String packageName = classEntry.getPackageName(); | 272 | String packageName = classEntry.getPackageName(); |
| 208 | return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); | 273 | return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); |