summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
diff options
context:
space:
mode:
authorGravatar Gegy2019-01-24 14:48:32 +0200
committerGravatar Adrian Siekierka2019-01-24 13:48:32 +0100
commit00fcd0550fcdda621c2e4662f6ddd55ce673b931 (patch)
tree6f9e4c24dbcc6d118fceec56adf7bf9d747a485c /src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
parentmark as 0.13.0-SNAPSHOT for preliminary development (diff)
downloadenigma-fork-00fcd0550fcdda621c2e4662f6ddd55ce673b931.tar.gz
enigma-fork-00fcd0550fcdda621c2e4662f6ddd55ce673b931.tar.xz
enigma-fork-00fcd0550fcdda621c2e4662f6ddd55ce673b931.zip
[WIP] Mapping rework (#91)
* Move packages * Mapping & entry refactor: first pass * Fix deobf -> obf tree remapping * Resolve various issues * Give all entries the potential for parents and treat inner classes as children * Deobf UI tree elements * Tests pass * Sort mapping output * Fix delta tracking * Index separation and first pass for #97 * Keep track of remapped jar index * Fix child entries not being remapped * Drop non-root entries * Track dropped mappings * Fix enigma mapping ordering * EntryTreeNode interface * Small tweaks * Naive full index remap on rename * Entries can resolve to more than one root entry * Support alternative resolution strategies * Bridge method resolution * Tests pass * Fix mappings being used where there are none * Fix methods with different descriptors being considered unique. closes #89
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/TranslationIndex.java')
-rw-r--r--src/main/java/cuchaz/enigma/analysis/TranslationIndex.java275
1 files changed, 0 insertions, 275 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
deleted file mode 100644
index 984d84b..0000000
--- a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
+++ /dev/null
@@ -1,275 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html
7 * <p>
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11
12package cuchaz.enigma.analysis;
13
14import com.google.common.cache.Cache;
15import com.google.common.cache.CacheBuilder;
16import com.google.common.collect.HashMultimap;
17import com.google.common.collect.Lists;
18import com.google.common.collect.Maps;
19import com.google.common.collect.Multimap;
20import cuchaz.enigma.bytecode.AccessFlags;
21import cuchaz.enigma.mapping.*;
22import cuchaz.enigma.mapping.entry.*;
23
24import java.util.*;
25
26public class TranslationIndex {
27
28 private final ReferencedEntryPool entryPool;
29 private Map<ClassEntry, ClassEntry> superclasses;
30 private Map<Entry, DefEntry> defEntries = new HashMap<>();
31 private Multimap<ClassEntry, FieldDefEntry> fieldEntries;
32 private Multimap<ClassEntry, MethodDefEntry> methodEntries;
33 private Multimap<ClassEntry, ClassEntry> interfaces;
34
35 public TranslationIndex(ReferencedEntryPool entryPool) {
36 this.entryPool = entryPool;
37 this.superclasses = Maps.newHashMap();
38 this.fieldEntries = HashMultimap.create();
39 this.methodEntries = HashMultimap.create();
40 this.interfaces = HashMultimap.create();
41
42 for (FieldDefEntry entry : fieldEntries.values()) {
43 defEntries.put(entry, entry);
44 }
45
46 for (MethodDefEntry entry : methodEntries.values()) {
47 defEntries.put(entry, entry);
48 }
49 }
50
51 public TranslationIndex(TranslationIndex other, Translator translator) {
52 this.entryPool = other.entryPool;
53
54 // translate the superclasses
55 this.superclasses = Maps.newHashMap();
56 for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.superclasses.entrySet()) {
57 this.superclasses.put(translator.getTranslatedClass(mapEntry.getKey()), translator.getTranslatedClass(mapEntry.getValue()));
58 }
59
60 // translate the interfaces
61 this.interfaces = HashMultimap.create();
62 for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.interfaces.entries()) {
63 this.interfaces.put(
64 translator.getTranslatedClass(mapEntry.getKey()),
65 translator.getTranslatedClass(mapEntry.getValue())
66 );
67 }
68
69 // translate the fields
70 this.fieldEntries = HashMultimap.create();
71 for (Map.Entry<ClassEntry, FieldDefEntry> mapEntry : other.fieldEntries.entries()) {
72 this.fieldEntries.put(
73 translator.getTranslatedClass(mapEntry.getKey()),
74 translator.getTranslatedFieldDef(mapEntry.getValue())
75 );
76 }
77
78 this.methodEntries = HashMultimap.create();
79 for (Map.Entry<ClassEntry, MethodDefEntry> mapEntry : other.methodEntries.entries()) {
80 this.methodEntries.put(
81 translator.getTranslatedClass(mapEntry.getKey()),
82 translator.getTranslatedMethodDef(mapEntry.getValue())
83 );
84 }
85
86 for (FieldDefEntry entry : fieldEntries.values()) {
87 defEntries.put(entry, entry);
88 }
89
90 for (MethodDefEntry entry : methodEntries.values()) {
91 defEntries.put(entry, entry);
92 }
93 }
94
95 protected ClassDefEntry indexClass(int access, String name, String signature, String superName, String[] interfaces) {
96 ClassDefEntry classEntry = new ClassDefEntry(name, Signature.createSignature(signature), new AccessFlags(access));
97 if (isJre(classEntry)) {
98 return null;
99 }
100
101 // add the superclass
102 ClassEntry superclassEntry = entryPool.getClass(superName);
103 if (superclassEntry != null) {
104 this.superclasses.put(classEntry, superclassEntry);
105 }
106
107 // add the interfaces
108 for (String interfaceClassName : interfaces) {
109 ClassEntry interfaceClassEntry = entryPool.getClass(interfaceClassName);
110 if (!isJre(interfaceClassEntry)) {
111 this.interfaces.put(classEntry, interfaceClassEntry);
112 }
113 }
114
115 return classEntry;
116 }
117
118 protected void indexField(FieldDefEntry fieldEntry) {
119 this.fieldEntries.put(fieldEntry.getOwnerClassEntry(), fieldEntry);
120 this.defEntries.put(fieldEntry, fieldEntry);
121 }
122
123 protected void indexMethod(MethodDefEntry methodEntry) {
124 this.methodEntries.put(methodEntry.getOwnerClassEntry(), methodEntry);
125 this.defEntries.put(methodEntry, methodEntry);
126 }
127
128 public void renameClasses(Map<String, String> renames) {
129 EntryRenamer.renameClassesInMap(renames, this.superclasses);
130 EntryRenamer.renameClassesInMultimap(renames, this.fieldEntries);
131 EntryRenamer.renameClassesInMultimap(renames, this.methodEntries);
132
133 this.defEntries.clear();
134 for (FieldDefEntry entry : fieldEntries.values()) {
135 defEntries.put(entry, entry);
136 }
137
138 for (MethodDefEntry entry : methodEntries.values()) {
139 defEntries.put(entry, entry);
140 }
141 }
142
143 public ClassEntry getSuperclass(ClassEntry classEntry) {
144 return this.superclasses.get(classEntry);
145 }
146
147 public List<ClassEntry> getAncestry(ClassEntry classEntry) {
148 List<ClassEntry> ancestors = Lists.newArrayList();
149 while (classEntry != null) {
150 classEntry = getSuperclass(classEntry);
151 if (classEntry != null) {
152 ancestors.add(classEntry);
153 }
154 }
155 return ancestors;
156 }
157
158 public List<ClassEntry> getImplementers(ClassEntry classEntry) {
159 // linear search is fast enough for now
160 List<ClassEntry> implementers = Lists.newArrayList();
161 for (ClassEntry itf : this.interfaces.keySet()) {
162 if (this.interfaces.containsEntry(itf, classEntry)) {
163 implementers.add(itf);
164 }
165 }
166 return implementers;
167 }
168
169 public List<ClassEntry> getSubclass(ClassEntry classEntry) {
170 // linear search is fast enough for now
171 List<ClassEntry> subclasses = Lists.newArrayList();
172 for (Map.Entry<ClassEntry, ClassEntry> entry : this.superclasses.entrySet()) {
173 ClassEntry subclass = entry.getKey();
174 ClassEntry superclass = entry.getValue();
175 if (classEntry.equals(superclass)) {
176 subclasses.add(subclass);
177 }
178 }
179 return subclasses;
180 }
181
182 public void getSubclassesRecursively(Set<ClassEntry> out, ClassEntry classEntry) {
183 for (ClassEntry subclassEntry : getSubclass(classEntry)) {
184 out.add(subclassEntry);
185 getSubclassesRecursively(out, subclassEntry);
186 }
187 }
188
189 public void getSubclassNamesRecursively(Set<String> out, ClassEntry classEntry) {
190 for (ClassEntry subclassEntry : getSubclass(classEntry)) {
191 out.add(subclassEntry.getName());
192 getSubclassNamesRecursively(out, subclassEntry);
193 }
194 }
195
196 public Collection<Map.Entry<ClassEntry, ClassEntry>> getClassInterfaces() {
197 return this.interfaces.entries();
198 }
199
200 public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) {
201 return this.interfaces.get(classEntry);
202 }
203
204 public boolean isInterface(ClassEntry classEntry) {
205 return this.interfaces.containsValue(classEntry);
206 }
207
208 public boolean entryExists(Entry entry) {
209 if (entry == null) {
210 return false;
211 }
212
213 if (entry instanceof FieldEntry) {
214 return fieldExists((FieldEntry) entry);
215 } else if (entry instanceof MethodEntry) {
216 return methodExists((MethodEntry) entry);
217 } else if (entry instanceof LocalVariableEntry) {
218 return methodExists(((LocalVariableEntry) entry).getOwnerEntry());
219 }
220 throw new IllegalArgumentException("Cannot check existence for " + entry.getClass());
221 }
222
223 public boolean fieldExists(FieldEntry fieldEntry) {
224 return this.fieldEntries.containsEntry(fieldEntry.getOwnerClassEntry(), fieldEntry);
225 }
226
227 public boolean methodExists(MethodEntry methodEntry) {
228 return this.methodEntries.containsEntry(methodEntry.getOwnerClassEntry(), methodEntry);
229 }
230
231 public ClassEntry resolveEntryOwner(Entry entry) {
232 if (entry instanceof ClassEntry) {
233 return (ClassEntry) entry;
234 }
235
236 if (entryExists(entry)) {
237 return entry.getOwnerClassEntry();
238 }
239
240 DefEntry def = defEntries.get(entry);
241 if (def != null && (def.getAccess().isPrivate())) {
242 return null;
243 }
244
245 // if we're protected/public/non-static, chances are we're somewhere down
246 LinkedList<ClassEntry> classEntries = new LinkedList<>();
247 classEntries.add(entry.getOwnerClassEntry());
248 while (!classEntries.isEmpty()) {
249 ClassEntry c = classEntries.remove();
250 Entry cEntry = entry.updateOwnership(c);
251
252 if (entryExists(cEntry)) {
253 def = defEntries.get(cEntry);
254 if (def == null || (!def.getAccess().isPrivate())) {
255 return cEntry.getOwnerClassEntry();
256 }
257 }
258
259 ClassEntry superC = getSuperclass(c);
260 if (superC != null) {
261 classEntries.add(superC);
262 }
263 if (entry instanceof MethodEntry) {
264 classEntries.addAll(getInterfaces(c));
265 }
266 }
267
268 return null;
269 }
270
271 private boolean isJre(ClassEntry classEntry) {
272 String packageName = classEntry.getPackageName();
273 return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax"));
274 }
275}