summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar jeff2015-02-09 22:23:45 -0500
committerGravatar jeff2015-02-09 22:23:45 -0500
commitaf1041731c8c0ce1846ff7e7b6052ed7327a5dbc (patch)
treee781b93f526a6c1ba7b6f5e14c319450199aa1df
parentDon't automatically move mappings around. We're more interested in stability ... (diff)
downloadenigma-af1041731c8c0ce1846ff7e7b6052ed7327a5dbc.tar.gz
enigma-af1041731c8c0ce1846ff7e7b6052ed7327a5dbc.tar.xz
enigma-af1041731c8c0ce1846ff7e7b6052ed7327a5dbc.zip
fix translation issues, particularly with fields
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java25
-rw-r--r--src/cuchaz/enigma/MainFormatConverter.java4
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java57
-rw-r--r--src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java1
-rw-r--r--src/cuchaz/enigma/analysis/RelatedMethodChecker.java96
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java11
-rw-r--r--src/cuchaz/enigma/analysis/TranslationIndex.java10
-rw-r--r--src/cuchaz/enigma/bytecode/ClassTranslator.java9
-rw-r--r--src/cuchaz/enigma/bytecode/MethodParameterWriter.java4
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java6
-rw-r--r--src/cuchaz/enigma/convert/ClassMatcher.java6
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java9
-rw-r--r--src/cuchaz/enigma/mapping/BehaviorEntryFactory.java57
-rw-r--r--src/cuchaz/enigma/mapping/EntryFactory.java184
-rw-r--r--src/cuchaz/enigma/mapping/JavassistUtil.java85
-rw-r--r--test/cuchaz/enigma/TestEntryFactory.java (renamed from test/cuchaz/enigma/EntryFactory.java)2
-rw-r--r--test/cuchaz/enigma/TestJarIndexConstructorReferences.java2
-rw-r--r--test/cuchaz/enigma/TestJarIndexInheritanceTree.java2
-rw-r--r--test/cuchaz/enigma/TestJarIndexLoneClass.java5
-rw-r--r--test/cuchaz/enigma/TestTokensConstructors.java2
-rw-r--r--test/cuchaz/enigma/TestTranslator.java86
-rw-r--r--test/cuchaz/enigma/TestType.java2
-rw-r--r--test/cuchaz/enigma/inputs/translation/A.java8
-rw-r--r--test/cuchaz/enigma/inputs/translation/A_Basic.java22
-rw-r--r--test/cuchaz/enigma/inputs/translation/B_BaseClass.java15
-rw-r--r--test/cuchaz/enigma/inputs/translation/C_SubClass.java17
-rw-r--r--test/cuchaz/enigma/resources/translation.mappings23
27 files changed, 507 insertions, 243 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index b4ac501f..b54a94ac 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -42,16 +42,17 @@ import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor;
42import cuchaz.enigma.analysis.EntryReference; 42import cuchaz.enigma.analysis.EntryReference;
43import cuchaz.enigma.analysis.JarClassIterator; 43import cuchaz.enigma.analysis.JarClassIterator;
44import cuchaz.enigma.analysis.JarIndex; 44import cuchaz.enigma.analysis.JarIndex;
45import cuchaz.enigma.analysis.RelatedMethodChecker;
45import cuchaz.enigma.analysis.SourceIndex; 46import cuchaz.enigma.analysis.SourceIndex;
46import cuchaz.enigma.analysis.SourceIndexVisitor; 47import cuchaz.enigma.analysis.SourceIndexVisitor;
47import cuchaz.enigma.analysis.Token; 48import cuchaz.enigma.analysis.Token;
48import cuchaz.enigma.mapping.ArgumentEntry; 49import cuchaz.enigma.mapping.ArgumentEntry;
49import cuchaz.enigma.mapping.BehaviorEntry; 50import cuchaz.enigma.mapping.BehaviorEntry;
50import cuchaz.enigma.mapping.BehaviorEntryFactory;
51import cuchaz.enigma.mapping.ClassEntry; 51import cuchaz.enigma.mapping.ClassEntry;
52import cuchaz.enigma.mapping.ClassMapping; 52import cuchaz.enigma.mapping.ClassMapping;
53import cuchaz.enigma.mapping.ConstructorEntry; 53import cuchaz.enigma.mapping.ConstructorEntry;
54import cuchaz.enigma.mapping.Entry; 54import cuchaz.enigma.mapping.Entry;
55import cuchaz.enigma.mapping.EntryFactory;
55import cuchaz.enigma.mapping.FieldEntry; 56import cuchaz.enigma.mapping.FieldEntry;
56import cuchaz.enigma.mapping.FieldMapping; 57import cuchaz.enigma.mapping.FieldMapping;
57import cuchaz.enigma.mapping.Mappings; 58import cuchaz.enigma.mapping.Mappings;
@@ -115,25 +116,27 @@ public class Deobfuscator {
115 } 116 }
116 117
117 // drop mappings that don't match the jar 118 // drop mappings that don't match the jar
119 RelatedMethodChecker relatedMethodChecker = new RelatedMethodChecker(m_jarIndex);
118 for (ClassMapping classMapping : Lists.newArrayList(val.classes())) { 120 for (ClassMapping classMapping : Lists.newArrayList(val.classes())) {
119 if (!checkClassMapping(classMapping)) { 121 if (!checkClassMapping(relatedMethodChecker, classMapping)) {
120 val.removeClassMapping(classMapping); 122 val.removeClassMapping(classMapping);
121 } 123 }
122 } 124 }
123 125
126 // check for related method inconsistencies
127 if (relatedMethodChecker.hasProblems()) {
128 throw new Error("Related methods are inconsistent! Need to fix the mappings manually.\n" + relatedMethodChecker.getReport());
129 }
130
124 m_mappings = val; 131 m_mappings = val;
125 m_renamer = new MappingsRenamer(m_jarIndex, val); 132 m_renamer = new MappingsRenamer(m_jarIndex, val);
126 m_translatorCache.clear(); 133 m_translatorCache.clear();
127 } 134 }
128 135
129 private boolean checkClassMapping(ClassMapping classMapping) { 136 private boolean checkClassMapping(RelatedMethodChecker relatedMethodChecker, ClassMapping classMapping) {
130 137
131 // check the class 138 // check the class
132 ClassEntry classEntry = new ClassEntry(classMapping.getObfName()); 139 ClassEntry classEntry = EntryFactory.getObfClassEntry(m_jarIndex, classMapping);
133 String outerClassName = m_jarIndex.getOuterClass(classEntry.getSimpleName());
134 if (outerClassName != null) {
135 classEntry = new ClassEntry(outerClassName + "$" + classMapping.getObfName());
136 }
137 if (!m_jarIndex.getObfClassEntries().contains(classEntry)) { 140 if (!m_jarIndex.getObfClassEntries().contains(classEntry)) {
138 return false; 141 return false;
139 } 142 }
@@ -149,16 +152,18 @@ public class Deobfuscator {
149 152
150 // check methods 153 // check methods
151 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { 154 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
152 BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf(classEntry, methodMapping); 155 BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping);
153 if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) { 156 if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) {
154 System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping."); 157 System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping.");
155 classMapping.removeMethodMapping(methodMapping); 158 classMapping.removeMethodMapping(methodMapping);
156 } 159 }
160
161 relatedMethodChecker.checkMethod(classEntry, methodMapping);
157 } 162 }
158 163
159 // check inner classes 164 // check inner classes
160 for (ClassMapping innerClassMapping : classMapping.innerClasses()) { 165 for (ClassMapping innerClassMapping : classMapping.innerClasses()) {
161 if (!checkClassMapping(innerClassMapping)) { 166 if (!checkClassMapping(relatedMethodChecker, innerClassMapping)) {
162 System.err.println("WARNING: unable to find inner class " + innerClassMapping + ". dropping mapping."); 167 System.err.println("WARNING: unable to find inner class " + innerClassMapping + ". dropping mapping.");
163 classMapping.removeInnerClassMapping(innerClassMapping); 168 classMapping.removeInnerClassMapping(innerClassMapping);
164 } 169 }
diff --git a/src/cuchaz/enigma/MainFormatConverter.java b/src/cuchaz/enigma/MainFormatConverter.java
index 1848144d..d4bb2db3 100644
--- a/src/cuchaz/enigma/MainFormatConverter.java
+++ b/src/cuchaz/enigma/MainFormatConverter.java
@@ -18,7 +18,7 @@ import cuchaz.enigma.mapping.ClassMapping;
18import cuchaz.enigma.mapping.ClassNameReplacer; 18import cuchaz.enigma.mapping.ClassNameReplacer;
19import cuchaz.enigma.mapping.FieldEntry; 19import cuchaz.enigma.mapping.FieldEntry;
20import cuchaz.enigma.mapping.FieldMapping; 20import cuchaz.enigma.mapping.FieldMapping;
21import cuchaz.enigma.mapping.JavassistUtil; 21import cuchaz.enigma.mapping.EntryFactory;
22import cuchaz.enigma.mapping.Mappings; 22import cuchaz.enigma.mapping.Mappings;
23import cuchaz.enigma.mapping.MappingsReader; 23import cuchaz.enigma.mapping.MappingsReader;
24import cuchaz.enigma.mapping.MappingsWriter; 24import cuchaz.enigma.mapping.MappingsWriter;
@@ -35,7 +35,7 @@ public class MainFormatConverter {
35 Map<String,Type> fieldTypes = Maps.newHashMap(); 35 Map<String,Type> fieldTypes = Maps.newHashMap();
36 for (CtClass c : JarClassIterator.classes(jar)) { 36 for (CtClass c : JarClassIterator.classes(jar)) {
37 for (CtField field : c.getDeclaredFields()) { 37 for (CtField field : c.getDeclaredFields()) {
38 FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); 38 FieldEntry fieldEntry = EntryFactory.getFieldEntry(field);
39 fieldTypes.put(getFieldKey(fieldEntry), moveClasssesOutOfDefaultPackage(fieldEntry.getType())); 39 fieldTypes.put(getFieldKey(fieldEntry), moveClasssesOutOfDefaultPackage(fieldEntry.getType()));
40 } 40 }
41 } 41 }
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index f54bedad..24d110ee 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -42,12 +42,11 @@ import cuchaz.enigma.Constants;
42import cuchaz.enigma.bytecode.ClassRenamer; 42import cuchaz.enigma.bytecode.ClassRenamer;
43import cuchaz.enigma.mapping.ArgumentEntry; 43import cuchaz.enigma.mapping.ArgumentEntry;
44import cuchaz.enigma.mapping.BehaviorEntry; 44import cuchaz.enigma.mapping.BehaviorEntry;
45import cuchaz.enigma.mapping.BehaviorEntryFactory;
46import cuchaz.enigma.mapping.ClassEntry; 45import cuchaz.enigma.mapping.ClassEntry;
47import cuchaz.enigma.mapping.ConstructorEntry; 46import cuchaz.enigma.mapping.ConstructorEntry;
48import cuchaz.enigma.mapping.Entry; 47import cuchaz.enigma.mapping.Entry;
48import cuchaz.enigma.mapping.EntryFactory;
49import cuchaz.enigma.mapping.FieldEntry; 49import cuchaz.enigma.mapping.FieldEntry;
50import cuchaz.enigma.mapping.JavassistUtil;
51import cuchaz.enigma.mapping.MethodEntry; 50import cuchaz.enigma.mapping.MethodEntry;
52import cuchaz.enigma.mapping.Translator; 51import cuchaz.enigma.mapping.Translator;
53 52
@@ -92,10 +91,10 @@ public class JarIndex {
92 for (CtClass c : JarClassIterator.classes(jar)) { 91 for (CtClass c : JarClassIterator.classes(jar)) {
93 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); 92 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
94 for (CtField field : c.getDeclaredFields()) { 93 for (CtField field : c.getDeclaredFields()) {
95 m_access.put(JavassistUtil.getFieldEntry(field), Access.get(field)); 94 m_access.put(EntryFactory.getFieldEntry(field), Access.get(field));
96 } 95 }
97 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 96 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
98 m_access.put(JavassistUtil.getBehaviorEntry(behavior), Access.get(behavior)); 97 m_access.put(EntryFactory.getBehaviorEntry(behavior), Access.get(behavior));
99 } 98 }
100 } 99 }
101 100
@@ -166,7 +165,7 @@ public class JarIndex {
166 165
167 private void indexBehavior(CtBehavior behavior) { 166 private void indexBehavior(CtBehavior behavior) {
168 // get the behavior entry 167 // get the behavior entry
169 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); 168 final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
170 if (behaviorEntry instanceof MethodEntry) { 169 if (behaviorEntry instanceof MethodEntry) {
171 MethodEntry methodEntry = (MethodEntry)behaviorEntry; 170 MethodEntry methodEntry = (MethodEntry)behaviorEntry;
172 171
@@ -178,12 +177,12 @@ public class JarIndex {
178 177
179 private void indexBehaviorReferences(CtBehavior behavior) { 178 private void indexBehaviorReferences(CtBehavior behavior) {
180 // index method calls 179 // index method calls
181 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); 180 final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
182 try { 181 try {
183 behavior.instrument(new ExprEditor() { 182 behavior.instrument(new ExprEditor() {
184 @Override 183 @Override
185 public void edit(MethodCall call) { 184 public void edit(MethodCall call) {
186 MethodEntry calledMethodEntry = JavassistUtil.getMethodEntry(call); 185 MethodEntry calledMethodEntry = EntryFactory.getMethodEntry(call);
187 ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); 186 ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry);
188 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { 187 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) {
189 calledMethodEntry = new MethodEntry( 188 calledMethodEntry = new MethodEntry(
@@ -202,7 +201,7 @@ public class JarIndex {
202 201
203 @Override 202 @Override
204 public void edit(FieldAccess call) { 203 public void edit(FieldAccess call) {
205 FieldEntry calledFieldEntry = JavassistUtil.getFieldEntry(call); 204 FieldEntry calledFieldEntry = EntryFactory.getFieldEntry(call);
206 ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); 205 ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry);
207 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { 206 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) {
208 calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); 207 calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry);
@@ -217,7 +216,7 @@ public class JarIndex {
217 216
218 @Override 217 @Override
219 public void edit(ConstructorCall call) { 218 public void edit(ConstructorCall call) {
220 ConstructorEntry calledConstructorEntry = JavassistUtil.getConstructorEntry(call); 219 ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call);
221 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 220 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
222 calledConstructorEntry, 221 calledConstructorEntry,
223 call.getMethodName(), 222 call.getMethodName(),
@@ -228,7 +227,7 @@ public class JarIndex {
228 227
229 @Override 228 @Override
230 public void edit(NewExpr call) { 229 public void edit(NewExpr call) {
231 ConstructorEntry calledConstructorEntry = JavassistUtil.getConstructorEntry(call); 230 ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call);
232 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 231 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
233 calledConstructorEntry, 232 calledConstructorEntry,
234 call.getClassName(), 233 call.getClassName(),
@@ -256,7 +255,7 @@ public class JarIndex {
256 } 255 }
257 256
258 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); 257 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
259 ConstructorEntry constructorEntry = JavassistUtil.getConstructorEntry(constructor); 258 ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor);
260 259
261 // gather the classes from the illegally-set synthetic fields 260 // gather the classes from the illegally-set synthetic fields
262 Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); 261 Set<ClassEntry> illegallySetClasses = Sets.newHashSet();
@@ -422,7 +421,7 @@ public class JarIndex {
422 CtConstructor constructor = c.getDeclaredConstructors()[0]; 421 CtConstructor constructor = c.getDeclaredConstructors()[0];
423 422
424 // is this constructor called exactly once? 423 // is this constructor called exactly once?
425 ConstructorEntry constructorEntry = JavassistUtil.getConstructorEntry(constructor); 424 ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor);
426 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences(constructorEntry); 425 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences(constructorEntry);
427 if (references.size() != 1) { 426 if (references.size() != 1) {
428 return null; 427 return null;
@@ -520,17 +519,17 @@ public class JarIndex {
520 return rootNode; 519 return rootNode;
521 } 520 }
522 521
523 public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { 522 public List<MethodImplementationsTreeNode> getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) {
524 523
525 MethodEntry interfaceMethodEntry; 524 List<MethodEntry> interfaceMethodEntries = Lists.newArrayList();
526 525
527 // is this method on an interface? 526 // is this method on an interface?
528 if (isInterface(obfMethodEntry.getClassName())) { 527 if (isInterface(obfMethodEntry.getClassName())) {
529 interfaceMethodEntry = obfMethodEntry; 528 interfaceMethodEntries.add(obfMethodEntry);
530 } else { 529 } else {
531 // get the interface class 530 // get the interface class
532 List<MethodEntry> methodInterfaces = Lists.newArrayList();
533 for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { 531 for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) {
532
534 // is this method defined in this interface? 533 // is this method defined in this interface?
535 MethodEntry methodInterface = new MethodEntry( 534 MethodEntry methodInterface = new MethodEntry(
536 new ClassEntry(interfaceName), 535 new ClassEntry(interfaceName),
@@ -538,21 +537,20 @@ public class JarIndex {
538 obfMethodEntry.getSignature() 537 obfMethodEntry.getSignature()
539 ); 538 );
540 if (containsObfBehavior(methodInterface)) { 539 if (containsObfBehavior(methodInterface)) {
541 methodInterfaces.add(methodInterface); 540 interfaceMethodEntries.add(methodInterface);
542 } 541 }
543 } 542 }
544 if (methodInterfaces.isEmpty()) {
545 return null;
546 }
547 if (methodInterfaces.size() > 1) {
548 throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!");
549 }
550 interfaceMethodEntry = methodInterfaces.get(0);
551 } 543 }
552 544
553 MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); 545 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList();
554 rootNode.load(this); 546 if (!interfaceMethodEntries.isEmpty()) {
555 return rootNode; 547 for (MethodEntry interfaceMethodEntry : interfaceMethodEntries) {
548 MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry);
549 node.load(this);
550 nodes.add(node);
551 }
552 }
553 return nodes;
556 } 554 }
557 555
558 public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) { 556 public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) {
@@ -569,9 +567,8 @@ public class JarIndex {
569 } 567 }
570 568
571 // look at interface methods too 569 // look at interface methods too
572 MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry); 570 for (MethodImplementationsTreeNode implementationsNode : getMethodImplementations(null, methodEntry)) {
573 if (implementations != null) { 571 getRelatedMethodImplementations(methodEntries, implementationsNode);
574 getRelatedMethodImplementations(methodEntries, implementations);
575 } 572 }
576 573
577 // recurse 574 // recurse
diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
index 10092268..6cafc55b 100644
--- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
+++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
@@ -63,6 +63,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
63 } 63 }
64 64
65 public void load(JarIndex index) { 65 public void load(JarIndex index) {
66
66 // get all method implementations 67 // get all method implementations
67 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); 68 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList();
68 for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { 69 for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) {
diff --git a/src/cuchaz/enigma/analysis/RelatedMethodChecker.java b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java
new file mode 100644
index 00000000..5bd67a0a
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java
@@ -0,0 +1,96 @@
1package cuchaz.enigma.analysis;
2
3import java.util.Map;
4import java.util.Set;
5
6import com.beust.jcommander.internal.Maps;
7import com.google.common.collect.Sets;
8
9import cuchaz.enigma.mapping.BehaviorEntry;
10import cuchaz.enigma.mapping.ClassEntry;
11import cuchaz.enigma.mapping.EntryFactory;
12import cuchaz.enigma.mapping.MethodEntry;
13import cuchaz.enigma.mapping.MethodMapping;
14
15public class RelatedMethodChecker {
16
17 private JarIndex m_jarIndex;
18 private Map<Set<MethodEntry>,String> m_deobfNamesByGroup;
19 private Map<MethodEntry,String> m_deobfNamesByObfMethod;
20 private Map<MethodEntry,Set<MethodEntry>> m_groupsByObfMethod;
21 private Set<Set<MethodEntry>> m_inconsistentGroups;
22
23 public RelatedMethodChecker(JarIndex jarIndex) {
24 m_jarIndex = jarIndex;
25 m_deobfNamesByGroup = Maps.newHashMap();
26 m_deobfNamesByObfMethod = Maps.newHashMap();
27 m_groupsByObfMethod = Maps.newHashMap();
28 m_inconsistentGroups = Sets.newHashSet();
29 }
30
31 public void checkMethod(ClassEntry classEntry, MethodMapping methodMapping) {
32
33 // TEMP: disable the expensive check for now, maybe we can optimize it later, or just use it for debugging
34 if (true) return;
35
36 BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping);
37 if (!(obfBehaviorEntry instanceof MethodEntry)) {
38 // only methods have related implementations
39 return;
40 }
41 MethodEntry obfMethodEntry = (MethodEntry)obfBehaviorEntry;
42 String deobfName = methodMapping.getDeobfName();
43 m_deobfNamesByObfMethod.put(obfMethodEntry, deobfName);
44
45 // have we seen this method's group before?
46 Set<MethodEntry> group = m_groupsByObfMethod.get(obfMethodEntry);
47 if (group == null) {
48
49 // no, compute the group and save the name
50 group = m_jarIndex.getRelatedMethodImplementations(obfMethodEntry);
51 m_deobfNamesByGroup.put(group, deobfName);
52
53 assert(group.contains(obfMethodEntry));
54 for (MethodEntry relatedMethodEntry : group) {
55 m_groupsByObfMethod.put(relatedMethodEntry, group);
56 }
57 }
58
59 // check the name
60 if (!sameName(m_deobfNamesByGroup.get(group), deobfName)) {
61 m_inconsistentGroups.add(group);
62 }
63 }
64
65 private boolean sameName(String a, String b) {
66 if (a == null && b == null) {
67 return true;
68 } else if (a != null && b != null) {
69 return a.equals(b);
70 }
71 return false;
72 }
73
74 public boolean hasProblems() {
75 return m_inconsistentGroups.size() > 0;
76 }
77
78 public String getReport() {
79 StringBuilder buf = new StringBuilder();
80 buf.append(m_inconsistentGroups.size());
81 buf.append(" groups of methods related by inheritance and/or interfaces have different deobf names!\n");
82 for (Set<MethodEntry> group : m_inconsistentGroups) {
83 buf.append("\tGroup with ");
84 buf.append(group.size());
85 buf.append(" methods:\n");
86 for (MethodEntry methodEntry : group) {
87 buf.append("\t\t");
88 buf.append(methodEntry.toString());
89 buf.append(" => ");
90 buf.append(m_deobfNamesByObfMethod.get(methodEntry));
91 buf.append("\n");
92 }
93 }
94 return buf.toString();
95 }
96}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
index e2ff3004..d6692f60 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
@@ -26,11 +26,10 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
26import com.strobel.decompiler.languages.java.ast.VariableInitializer; 26import com.strobel.decompiler.languages.java.ast.VariableInitializer;
27 27
28import cuchaz.enigma.mapping.BehaviorEntry; 28import cuchaz.enigma.mapping.BehaviorEntry;
29import cuchaz.enigma.mapping.BehaviorEntryFactory;
30import cuchaz.enigma.mapping.ClassEntry; 29import cuchaz.enigma.mapping.ClassEntry;
31import cuchaz.enigma.mapping.ConstructorEntry; 30import cuchaz.enigma.mapping.ConstructorEntry;
31import cuchaz.enigma.mapping.EntryFactory;
32import cuchaz.enigma.mapping.FieldEntry; 32import cuchaz.enigma.mapping.FieldEntry;
33import cuchaz.enigma.mapping.Signature;
34import cuchaz.enigma.mapping.Type; 33import cuchaz.enigma.mapping.Type;
35 34
36public class SourceIndexClassVisitor extends SourceIndexVisitor { 35public class SourceIndexClassVisitor extends SourceIndexVisitor {
@@ -69,12 +68,13 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor {
69 @Override 68 @Override
70 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { 69 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
71 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); 70 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
72 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); 71 BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(def);
73 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(classEntry, def.getName(), def.getSignature());
74 AstNode tokenNode = node.getNameToken(); 72 AstNode tokenNode = node.getNameToken();
73
75 if (behaviorEntry instanceof ConstructorEntry) { 74 if (behaviorEntry instanceof ConstructorEntry) {
76 ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; 75 ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry;
77 if (constructorEntry.isStatic()) { 76 if (constructorEntry.isStatic()) {
77 // for static initializers, check elsewhere for the token node
78 tokenNode = node.getModifiers().firstOrNullObject(); 78 tokenNode = node.getModifiers().firstOrNullObject();
79 } 79 }
80 } 80 }
@@ -85,8 +85,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor {
85 @Override 85 @Override
86 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { 86 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
87 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); 87 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
88 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); 88 ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(def);
89 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, new Signature(def.getSignature()));
90 index.addDeclaration(node.getNameToken(), constructorEntry); 89 index.addDeclaration(node.getNameToken(), constructorEntry);
91 return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); 90 return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index);
92 } 91 }
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java
index 7597c3ae..8651ebd6 100644
--- a/src/cuchaz/enigma/analysis/TranslationIndex.java
+++ b/src/cuchaz/enigma/analysis/TranslationIndex.java
@@ -37,7 +37,7 @@ import cuchaz.enigma.mapping.BehaviorEntry;
37import cuchaz.enigma.mapping.ClassEntry; 37import cuchaz.enigma.mapping.ClassEntry;
38import cuchaz.enigma.mapping.Entry; 38import cuchaz.enigma.mapping.Entry;
39import cuchaz.enigma.mapping.FieldEntry; 39import cuchaz.enigma.mapping.FieldEntry;
40import cuchaz.enigma.mapping.JavassistUtil; 40import cuchaz.enigma.mapping.EntryFactory;
41import cuchaz.enigma.mapping.Translator; 41import cuchaz.enigma.mapping.Translator;
42 42
43public class TranslationIndex implements Serializable { 43public class TranslationIndex implements Serializable {
@@ -85,23 +85,23 @@ public class TranslationIndex implements Serializable {
85 85
86 public void indexClass(CtClass c) { 86 public void indexClass(CtClass c) {
87 87
88 ClassEntry classEntry = JavassistUtil.getClassEntry(c); 88 ClassEntry classEntry = EntryFactory.getClassEntry(c);
89 89
90 // add the superclass 90 // add the superclass
91 ClassEntry superclassEntry = JavassistUtil.getSuperclassEntry(c); 91 ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c);
92 if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { 92 if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) {
93 m_superclasses.put(classEntry, superclassEntry); 93 m_superclasses.put(classEntry, superclassEntry);
94 } 94 }
95 95
96 // add fields 96 // add fields
97 for (CtField field : c.getDeclaredFields()) { 97 for (CtField field : c.getDeclaredFields()) {
98 FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); 98 FieldEntry fieldEntry = EntryFactory.getFieldEntry(field);
99 m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); 99 m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry);
100 } 100 }
101 101
102 // add behaviors 102 // add behaviors
103 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 103 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
104 BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); 104 BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
105 m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); 105 m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry);
106 } 106 }
107 } 107 }
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java
index 4dba0d87..4167731a 100644
--- a/src/cuchaz/enigma/bytecode/ClassTranslator.java
+++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java
@@ -23,10 +23,9 @@ import javassist.bytecode.SourceFileAttribute;
23import com.google.common.collect.Maps; 23import com.google.common.collect.Maps;
24 24
25import cuchaz.enigma.mapping.BehaviorEntry; 25import cuchaz.enigma.mapping.BehaviorEntry;
26import cuchaz.enigma.mapping.BehaviorEntryFactory;
27import cuchaz.enigma.mapping.ClassEntry; 26import cuchaz.enigma.mapping.ClassEntry;
27import cuchaz.enigma.mapping.EntryFactory;
28import cuchaz.enigma.mapping.FieldEntry; 28import cuchaz.enigma.mapping.FieldEntry;
29import cuchaz.enigma.mapping.JavassistUtil;
30import cuchaz.enigma.mapping.MethodEntry; 29import cuchaz.enigma.mapping.MethodEntry;
31import cuchaz.enigma.mapping.Signature; 30import cuchaz.enigma.mapping.Signature;
32import cuchaz.enigma.mapping.Translator; 31import cuchaz.enigma.mapping.Translator;
@@ -74,7 +73,7 @@ public class ClassTranslator {
74 case ConstPool.CONST_InterfaceMethodref: { 73 case ConstPool.CONST_InterfaceMethodref: {
75 74
76 // translate the name and type 75 // translate the name and type
77 BehaviorEntry entry = BehaviorEntryFactory.create( 76 BehaviorEntry entry = EntryFactory.getBehaviorEntry(
78 Descriptor.toJvmName(editor.getMemberrefClassname(i)), 77 Descriptor.toJvmName(editor.getMemberrefClassname(i)),
79 editor.getMemberrefName(i), 78 editor.getMemberrefName(i),
80 editor.getMemberrefType(i) 79 editor.getMemberrefType(i)
@@ -95,7 +94,7 @@ public class ClassTranslator {
95 for (CtField field : c.getDeclaredFields()) { 94 for (CtField field : c.getDeclaredFields()) {
96 95
97 // translate the name 96 // translate the name
98 FieldEntry entry = JavassistUtil.getFieldEntry(field); 97 FieldEntry entry = EntryFactory.getFieldEntry(field);
99 String translatedName = m_translator.translate(entry); 98 String translatedName = m_translator.translate(entry);
100 if (translatedName != null) { 99 if (translatedName != null) {
101 field.setName(translatedName); 100 field.setName(translatedName);
@@ -112,7 +111,7 @@ public class ClassTranslator {
112 CtMethod method = (CtMethod)behavior; 111 CtMethod method = (CtMethod)behavior;
113 112
114 // translate the name 113 // translate the name
115 MethodEntry entry = JavassistUtil.getMethodEntry(method); 114 MethodEntry entry = EntryFactory.getMethodEntry(method);
116 String translatedName = m_translator.translate(entry); 115 String translatedName = m_translator.translate(entry);
117 if (translatedName != null) { 116 if (translatedName != null) {
118 method.setName(translatedName); 117 method.setName(translatedName);
diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
index 853928c7..f64ca02a 100644
--- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
+++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
@@ -17,7 +17,7 @@ import javassist.CtBehavior;
17import javassist.CtClass; 17import javassist.CtClass;
18import cuchaz.enigma.mapping.ArgumentEntry; 18import cuchaz.enigma.mapping.ArgumentEntry;
19import cuchaz.enigma.mapping.BehaviorEntry; 19import cuchaz.enigma.mapping.BehaviorEntry;
20import cuchaz.enigma.mapping.BehaviorEntryFactory; 20import cuchaz.enigma.mapping.EntryFactory;
21import cuchaz.enigma.mapping.Signature; 21import cuchaz.enigma.mapping.Signature;
22import cuchaz.enigma.mapping.Translator; 22import cuchaz.enigma.mapping.Translator;
23 23
@@ -33,7 +33,7 @@ public class MethodParameterWriter {
33 33
34 // Procyon will read method arguments from the "MethodParameters" attribute, so write those 34 // Procyon will read method arguments from the "MethodParameters" attribute, so write those
35 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 35 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
36 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); 36 BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
37 37
38 // get the number of arguments 38 // get the number of arguments
39 Signature signature = behaviorEntry.getSignature(); 39 Signature signature = behaviorEntry.getSignature();
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index bb729a36..b5140124 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -53,7 +53,7 @@ import cuchaz.enigma.mapping.ClassEntry;
53import cuchaz.enigma.mapping.ClassNameReplacer; 53import cuchaz.enigma.mapping.ClassNameReplacer;
54import cuchaz.enigma.mapping.Entry; 54import cuchaz.enigma.mapping.Entry;
55import cuchaz.enigma.mapping.FieldEntry; 55import cuchaz.enigma.mapping.FieldEntry;
56import cuchaz.enigma.mapping.JavassistUtil; 56import cuchaz.enigma.mapping.EntryFactory;
57import cuchaz.enigma.mapping.Signature; 57import cuchaz.enigma.mapping.Signature;
58 58
59public class ClassIdentity { 59public class ClassIdentity {
@@ -116,13 +116,13 @@ public class ClassIdentity {
116 m_references = HashMultiset.create(); 116 m_references = HashMultiset.create();
117 if (useReferences) { 117 if (useReferences) {
118 for (CtField field : c.getDeclaredFields()) { 118 for (CtField field : c.getDeclaredFields()) {
119 FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); 119 FieldEntry fieldEntry = EntryFactory.getFieldEntry(field);
120 for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(fieldEntry)) { 120 for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(fieldEntry)) {
121 addReference(reference); 121 addReference(reference);
122 } 122 }
123 } 123 }
124 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 124 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
125 BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); 125 BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
126 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(behaviorEntry)) { 126 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(behaviorEntry)) {
127 addReference(reference); 127 addReference(reference);
128 } 128 }
diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java
index ccf6b787..d70b8ebb 100644
--- a/src/cuchaz/enigma/convert/ClassMatcher.java
+++ b/src/cuchaz/enigma/convert/ClassMatcher.java
@@ -42,7 +42,7 @@ import cuchaz.enigma.analysis.JarIndex;
42import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; 42import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
43import cuchaz.enigma.mapping.ClassEntry; 43import cuchaz.enigma.mapping.ClassEntry;
44import cuchaz.enigma.mapping.ClassMapping; 44import cuchaz.enigma.mapping.ClassMapping;
45import cuchaz.enigma.mapping.JavassistUtil; 45import cuchaz.enigma.mapping.EntryFactory;
46import cuchaz.enigma.mapping.MappingParseException; 46import cuchaz.enigma.mapping.MappingParseException;
47import cuchaz.enigma.mapping.Mappings; 47import cuchaz.enigma.mapping.Mappings;
48import cuchaz.enigma.mapping.MappingsReader; 48import cuchaz.enigma.mapping.MappingsReader;
@@ -242,13 +242,13 @@ public class ClassMatcher {
242 System.err.println("\tAvailable dest methods:"); 242 System.err.println("\tAvailable dest methods:");
243 CtClass c = destLoader.loadClass(classMapping.getObfName()); 243 CtClass c = destLoader.loadClass(classMapping.getObfName());
244 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 244 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
245 System.err.println("\t\t" + JavassistUtil.getBehaviorEntry(behavior)); 245 System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior));
246 } 246 }
247 247
248 System.err.println("\tAvailable source methods:"); 248 System.err.println("\tAvailable source methods:");
249 c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName())); 249 c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName()));
250 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 250 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
251 System.err.println("\t\t" + JavassistUtil.getBehaviorEntry(behavior)); 251 System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior));
252 } 252 }
253 } 253 }
254 } 254 }
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 61fea9c0..9fa633eb 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -186,14 +186,17 @@ public class GuiController {
186 186
187 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) { 187 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) {
188 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); 188 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry);
189 MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations( 189 List<MethodImplementationsTreeNode> rootNodes = m_deobfuscator.getJarIndex().getMethodImplementations(
190 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), 190 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
191 obfMethodEntry 191 obfMethodEntry
192 ); 192 );
193 if (rootNode == null) { 193 if (rootNodes.isEmpty()) {
194 return null; 194 return null;
195 } 195 }
196 return MethodImplementationsTreeNode.findNode(rootNode, obfMethodEntry); 196 if (rootNodes.size() > 1) {
197 System.err.println("WARNING: Method " + deobfMethodEntry + " implements multiple interfaces. Only showing first one.");
198 }
199 return MethodImplementationsTreeNode.findNode(rootNodes.get(0), obfMethodEntry);
197 } 200 }
198 201
199 public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) { 202 public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) {
diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
deleted file mode 100644
index 61e501b7..00000000
--- a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
+++ /dev/null
@@ -1,57 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import javassist.CtBehavior;
14import javassist.CtConstructor;
15import javassist.CtMethod;
16import javassist.bytecode.Descriptor;
17
18public class BehaviorEntryFactory {
19
20 public static BehaviorEntry create(String className, String name, String signature) {
21 return create(new ClassEntry(className), name, signature);
22 }
23
24 public static BehaviorEntry create(ClassEntry classEntry, String name, String signature) {
25 if (name.equals("<init>")) {
26 return new ConstructorEntry(classEntry, new Signature(signature));
27 } else if (name.equals("<clinit>")) {
28 return new ConstructorEntry(classEntry);
29 } else {
30 return new MethodEntry(classEntry, name, new Signature(signature));
31 }
32 }
33
34 public static BehaviorEntry create(CtBehavior behavior) {
35 String className = Descriptor.toJvmName(behavior.getDeclaringClass().getName());
36 if (behavior instanceof CtMethod) {
37 return create(className, behavior.getName(), behavior.getSignature());
38 } else if (behavior instanceof CtConstructor) {
39 CtConstructor constructor = (CtConstructor)behavior;
40 if (constructor.isClassInitializer()) {
41 return create(className, "<clinit>", null);
42 } else {
43 return create(className, "<init>", constructor.getSignature());
44 }
45 } else {
46 throw new IllegalArgumentException("Unable to create BehaviorEntry from " + behavior);
47 }
48 }
49
50 public static BehaviorEntry createObf(ClassEntry classEntry, MethodMapping methodMapping) {
51 return create(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature().toString());
52 }
53
54 public static BehaviorEntry createDeobf(ClassEntry classEntry, MethodMapping methodMapping) {
55 return create(classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature().toString());
56 }
57}
diff --git a/src/cuchaz/enigma/mapping/EntryFactory.java b/src/cuchaz/enigma/mapping/EntryFactory.java
new file mode 100644
index 00000000..dceea29d
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/EntryFactory.java
@@ -0,0 +1,184 @@
1package cuchaz.enigma.mapping;
2
3import java.util.List;
4
5import javassist.CtBehavior;
6import javassist.CtClass;
7import javassist.CtConstructor;
8import javassist.CtField;
9import javassist.CtMethod;
10import javassist.bytecode.Descriptor;
11import javassist.expr.ConstructorCall;
12import javassist.expr.FieldAccess;
13import javassist.expr.MethodCall;
14import javassist.expr.NewExpr;
15
16import com.beust.jcommander.internal.Lists;
17import com.strobel.assembler.metadata.MethodDefinition;
18
19import cuchaz.enigma.analysis.JarIndex;
20
21public class EntryFactory {
22
23 public static ClassEntry getClassEntry(CtClass c) {
24 return new ClassEntry(Descriptor.toJvmName(c.getName()));
25 }
26
27 public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) {
28 return new ClassEntry(getChainedOuterClassName(jarIndex, classMapping.getObfName()));
29 }
30
31 private static String getChainedOuterClassName(JarIndex jarIndex, String obfClassName) {
32
33 // lookup the chain of outer classes
34 List<String> obfOuterClassNames = Lists.newArrayList();
35 String checkName = obfClassName;
36 while (true) {
37
38 // if this class name has a package, then it can't be an inner class
39 if (!new ClassEntry(checkName).isInDefaultPackage()) {
40 break;
41 }
42
43 String obfOuterClassName = jarIndex.getOuterClass(checkName);
44 if (obfOuterClassName != null) {
45 obfOuterClassNames.add(obfOuterClassName);
46 checkName = obfOuterClassName;
47 } else {
48 break;
49 }
50 }
51
52 // build the chained class name
53 StringBuilder buf = new StringBuilder();
54 for (int i=obfOuterClassNames.size()-1; i>=0; i--) {
55 buf.append(obfOuterClassNames.get(i));
56 buf.append("$");
57 }
58 buf.append(obfClassName);
59 return buf.toString();
60 }
61
62 public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) {
63 return new ClassEntry(classMapping.getDeobfName());
64 }
65
66 public static ClassEntry getSuperclassEntry(CtClass c) {
67 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass()));
68 }
69
70 public static FieldEntry getFieldEntry(CtField field) {
71 return new FieldEntry(
72 getClassEntry(field.getDeclaringClass()),
73 field.getName(),
74 new Type(field.getFieldInfo().getDescriptor())
75 );
76 }
77
78 public static FieldEntry getFieldEntry(FieldAccess call) {
79 return new FieldEntry(
80 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
81 call.getFieldName(),
82 new Type(call.getSignature())
83 );
84 }
85
86 public static MethodEntry getMethodEntry(CtMethod method) {
87 return new MethodEntry(
88 getClassEntry(method.getDeclaringClass()),
89 method.getName(),
90 new Signature(method.getMethodInfo().getDescriptor())
91 );
92 }
93
94 public static MethodEntry getMethodEntry(MethodCall call) {
95 return new MethodEntry(
96 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
97 call.getMethodName(),
98 new Signature(call.getSignature())
99 );
100 }
101
102 public static MethodEntry getMethodEntry(MethodDefinition def) {
103 return new MethodEntry(
104 new ClassEntry(def.getDeclaringType().getInternalName()),
105 def.getName(),
106 new Signature(def.getSignature())
107 );
108 }
109
110 public static ConstructorEntry getConstructorEntry(CtConstructor constructor) {
111 if (constructor.isClassInitializer()) {
112 return new ConstructorEntry(
113 getClassEntry(constructor.getDeclaringClass())
114 );
115 } else {
116 return new ConstructorEntry(
117 getClassEntry(constructor.getDeclaringClass()),
118 new Signature(constructor.getMethodInfo().getDescriptor())
119 );
120 }
121 }
122
123 public static ConstructorEntry getConstructorEntry(ConstructorCall call) {
124 return new ConstructorEntry(
125 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
126 new Signature(call.getSignature())
127 );
128 }
129
130 public static ConstructorEntry getConstructorEntry(NewExpr call) {
131 return new ConstructorEntry(
132 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
133 new Signature(call.getSignature())
134 );
135 }
136
137 public static ConstructorEntry getConstructorEntry(MethodDefinition def) {
138 if (def.isTypeInitializer()) {
139 return new ConstructorEntry(
140 new ClassEntry(def.getDeclaringType().getInternalName())
141 );
142 } else {
143 return new ConstructorEntry(
144 new ClassEntry(def.getDeclaringType().getInternalName()),
145 new Signature(def.getSignature())
146 );
147 }
148 }
149
150 public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) {
151 if (behavior instanceof CtMethod) {
152 return getMethodEntry((CtMethod)behavior);
153 } else if (behavior instanceof CtConstructor) {
154 return getConstructorEntry((CtConstructor)behavior);
155 }
156 throw new Error("behavior is neither Method nor Constructor!");
157 }
158
159 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) {
160 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature));
161 }
162
163 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) {
164 if (behaviorName.equals("<init>")) {
165 return new ConstructorEntry(classEntry, behaviorSignature);
166 } else if(behaviorName.equals("<clinit>")) {
167 return new ConstructorEntry(classEntry);
168 } else {
169 return new MethodEntry(classEntry, behaviorName, behaviorSignature);
170 }
171 }
172
173 public static BehaviorEntry getBehaviorEntry(MethodDefinition def) {
174 if (def.isConstructor() || def.isTypeInitializer()) {
175 return getConstructorEntry(def);
176 } else {
177 return getMethodEntry(def);
178 }
179 }
180
181 public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) {
182 return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
183 }
184}
diff --git a/src/cuchaz/enigma/mapping/JavassistUtil.java b/src/cuchaz/enigma/mapping/JavassistUtil.java
deleted file mode 100644
index 0d6ce6a1..00000000
--- a/src/cuchaz/enigma/mapping/JavassistUtil.java
+++ /dev/null
@@ -1,85 +0,0 @@
1package cuchaz.enigma.mapping;
2
3import javassist.CtBehavior;
4import javassist.CtClass;
5import javassist.CtConstructor;
6import javassist.CtField;
7import javassist.CtMethod;
8import javassist.bytecode.Descriptor;
9import javassist.expr.ConstructorCall;
10import javassist.expr.FieldAccess;
11import javassist.expr.MethodCall;
12import javassist.expr.NewExpr;
13
14public class JavassistUtil {
15
16 public static ClassEntry getClassEntry(CtClass c) {
17 return new ClassEntry(Descriptor.toJvmName(c.getName()));
18 }
19
20 public static ClassEntry getSuperclassEntry(CtClass c) {
21 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass()));
22 }
23
24 public static MethodEntry getMethodEntry(CtMethod method) {
25 return new MethodEntry(
26 getClassEntry(method.getDeclaringClass()),
27 method.getName(),
28 new Signature(method.getMethodInfo().getDescriptor())
29 );
30 }
31
32 public static MethodEntry getMethodEntry(MethodCall call) {
33 return new MethodEntry(
34 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
35 call.getMethodName(),
36 new Signature(call.getSignature())
37 );
38 }
39
40 public static ConstructorEntry getConstructorEntry(CtConstructor constructor) {
41 return new ConstructorEntry(
42 getClassEntry(constructor.getDeclaringClass()),
43 new Signature(constructor.getMethodInfo().getDescriptor())
44 );
45 }
46
47 public static ConstructorEntry getConstructorEntry(ConstructorCall call) {
48 return new ConstructorEntry(
49 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
50 new Signature(call.getSignature())
51 );
52 }
53
54 public static ConstructorEntry getConstructorEntry(NewExpr call) {
55 return new ConstructorEntry(
56 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
57 new Signature(call.getSignature())
58 );
59 }
60
61 public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) {
62 if (behavior instanceof CtMethod) {
63 return getMethodEntry((CtMethod)behavior);
64 } else if (behavior instanceof CtConstructor) {
65 return getConstructorEntry((CtConstructor)behavior);
66 }
67 throw new Error("behavior is neither Method nor Constructor!");
68 }
69
70 public static FieldEntry getFieldEntry(CtField field) {
71 return new FieldEntry(
72 getClassEntry(field.getDeclaringClass()),
73 field.getName(),
74 new Type(field.getFieldInfo().getDescriptor())
75 );
76 }
77
78 public static FieldEntry getFieldEntry(FieldAccess call) {
79 return new FieldEntry(
80 new ClassEntry(Descriptor.toJvmName(call.getClassName())),
81 call.getFieldName(),
82 new Type(call.getSignature())
83 );
84 }
85}
diff --git a/test/cuchaz/enigma/EntryFactory.java b/test/cuchaz/enigma/TestEntryFactory.java
index 8c94bdf3..754f3081 100644
--- a/test/cuchaz/enigma/EntryFactory.java
+++ b/test/cuchaz/enigma/TestEntryFactory.java
@@ -20,7 +20,7 @@ import cuchaz.enigma.mapping.MethodEntry;
20import cuchaz.enigma.mapping.Signature; 20import cuchaz.enigma.mapping.Signature;
21import cuchaz.enigma.mapping.Type; 21import cuchaz.enigma.mapping.Type;
22 22
23public class EntryFactory { 23public class TestEntryFactory {
24 24
25 public static ClassEntry newClass(String name) { 25 public static ClassEntry newClass(String name) {
26 return new ClassEntry(name); 26 return new ClassEntry(name);
diff --git a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
index 22812fea..e1a30226 100644
--- a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
+++ b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
@@ -10,7 +10,7 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import static cuchaz.enigma.EntryFactory.*; 13import static cuchaz.enigma.TestEntryFactory.*;
14import static org.hamcrest.MatcherAssert.*; 14import static org.hamcrest.MatcherAssert.*;
15import static org.hamcrest.Matchers.*; 15import static org.hamcrest.Matchers.*;
16 16
diff --git a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
index 349d33b1..6e2c1ad3 100644
--- a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
+++ b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
@@ -10,7 +10,7 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import static cuchaz.enigma.EntryFactory.*; 13import static cuchaz.enigma.TestEntryFactory.*;
14import static org.hamcrest.MatcherAssert.*; 14import static org.hamcrest.MatcherAssert.*;
15import static org.hamcrest.Matchers.*; 15import static org.hamcrest.Matchers.*;
16 16
diff --git a/test/cuchaz/enigma/TestJarIndexLoneClass.java b/test/cuchaz/enigma/TestJarIndexLoneClass.java
index c0ac8d7d..768284f9 100644
--- a/test/cuchaz/enigma/TestJarIndexLoneClass.java
+++ b/test/cuchaz/enigma/TestJarIndexLoneClass.java
@@ -11,7 +11,7 @@
11 ******************************************************************************/ 11 ******************************************************************************/
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static cuchaz.enigma.EntryFactory.*; 14import static cuchaz.enigma.TestEntryFactory.*;
15import static org.hamcrest.MatcherAssert.*; 15import static org.hamcrest.MatcherAssert.*;
16import static org.hamcrest.Matchers.*; 16import static org.hamcrest.Matchers.*;
17 17
@@ -96,8 +96,7 @@ public class TestJarIndexLoneClass {
96 @Test 96 @Test
97 public void methodImplementations() { 97 public void methodImplementations() {
98 MethodEntry source = newMethod("none/a", "a", "()Ljava/lang/String;"); 98 MethodEntry source = newMethod("none/a", "a", "()Ljava/lang/String;");
99 MethodImplementationsTreeNode node = m_index.getMethodImplementations(new Translator(), source); 99 assertThat(m_index.getMethodImplementations(new Translator(), source), is(empty()));
100 assertThat(node, is(nullValue()));
101 } 100 }
102 101
103 @Test 102 @Test
diff --git a/test/cuchaz/enigma/TestTokensConstructors.java b/test/cuchaz/enigma/TestTokensConstructors.java
index 6758d2a7..a563f832 100644
--- a/test/cuchaz/enigma/TestTokensConstructors.java
+++ b/test/cuchaz/enigma/TestTokensConstructors.java
@@ -10,7 +10,7 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import static cuchaz.enigma.EntryFactory.*; 13import static cuchaz.enigma.TestEntryFactory.*;
14import static org.hamcrest.MatcherAssert.*; 14import static org.hamcrest.MatcherAssert.*;
15import static org.hamcrest.Matchers.*; 15import static org.hamcrest.Matchers.*;
16 16
diff --git a/test/cuchaz/enigma/TestTranslator.java b/test/cuchaz/enigma/TestTranslator.java
index f91c5852..3fe1680f 100644
--- a/test/cuchaz/enigma/TestTranslator.java
+++ b/test/cuchaz/enigma/TestTranslator.java
@@ -1,6 +1,6 @@
1package cuchaz.enigma; 1package cuchaz.enigma;
2 2
3import static cuchaz.enigma.EntryFactory.*; 3import static cuchaz.enigma.TestEntryFactory.*;
4import static org.hamcrest.MatcherAssert.*; 4import static org.hamcrest.MatcherAssert.*;
5import static org.hamcrest.Matchers.*; 5import static org.hamcrest.Matchers.*;
6 6
@@ -8,8 +8,10 @@ import java.io.InputStream;
8import java.io.InputStreamReader; 8import java.io.InputStreamReader;
9import java.util.jar.JarFile; 9import java.util.jar.JarFile;
10 10
11import org.junit.BeforeClass;
11import org.junit.Test; 12import org.junit.Test;
12 13
14import cuchaz.enigma.mapping.Entry;
13import cuchaz.enigma.mapping.Mappings; 15import cuchaz.enigma.mapping.Mappings;
14import cuchaz.enigma.mapping.MappingsReader; 16import cuchaz.enigma.mapping.MappingsReader;
15import cuchaz.enigma.mapping.TranslationDirection; 17import cuchaz.enigma.mapping.TranslationDirection;
@@ -18,25 +20,85 @@ import cuchaz.enigma.mapping.Translator;
18 20
19public class TestTranslator { 21public class TestTranslator {
20 22
21 private Deobfuscator m_deobfuscator; 23 private static Deobfuscator m_deobfuscator;
22 private Mappings m_mappings; 24 private static Mappings m_mappings;
25 private static Translator m_deobfTranslator;
26 private static Translator m_obfTranslator;
23 27
24 public TestTranslator() 28 @BeforeClass
29 public static void beforeClass()
25 throws Exception { 30 throws Exception {
26 m_deobfuscator = new Deobfuscator(new JarFile("build/testTranslation.obf.jar")); 31 m_deobfuscator = new Deobfuscator(new JarFile("build/testTranslation.obf.jar"));
27 try (InputStream in = getClass().getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) { 32 try (InputStream in = TestTranslator.class.getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) {
28 m_mappings = new MappingsReader().read(new InputStreamReader(in)); 33 m_mappings = new MappingsReader().read(new InputStreamReader(in));
29 m_deobfuscator.setMappings(m_mappings); 34 m_deobfuscator.setMappings(m_mappings);
35 m_deobfTranslator = m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating);
36 m_obfTranslator = m_deobfuscator.getTranslator(TranslationDirection.Obfuscating);
30 } 37 }
31 } 38 }
32 39
33 @Test 40 @Test
34 public void deobfuscatingTranslations() 41 public void basicClasses() {
35 throws Exception { 42 assertMapping(newClass("none/a"), newClass("deobf/A_Basic"));
36 Translator translator = m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating); 43 assertMapping(newClass("none/b"), newClass("deobf/B_BaseClass"));
37 assertThat(translator.translateEntry(newClass("none/a")), is(newClass("deobf/A"))); 44 assertMapping(newClass("none/c"), newClass("deobf/C_SubClass"));
38 assertThat(translator.translateEntry(newField("none/a", "a", "I")), is(newField("deobf/A", "one", "I"))); 45 }
39 assertThat(translator.translateEntry(newField("none/a", "a", "F")), is(newField("deobf/A", "two", "F"))); 46
40 assertThat(translator.translateEntry(newField("none/a", "a", "Ljava/lang/String;")), is(newField("deobf/A", "three", "Ljava/lang/String;"))); 47 @Test
48 public void basicFields() {
49 assertMapping(newField("none/a", "a", "I"), newField("deobf/A_Basic", "f1", "I"));
50 assertMapping(newField("none/a", "a", "F"), newField("deobf/A_Basic", "f2", "F"));
51 assertMapping(newField("none/a", "a", "Ljava/lang/String;"), newField("deobf/A_Basic", "f3", "Ljava/lang/String;"));
52 }
53
54 @Test
55 public void basicMethods() {
56 assertMapping(newMethod("none/a", "a", "()V"), newMethod("deobf/A_Basic", "m1", "()V"));
57 assertMapping(newMethod("none/a", "a", "()I"), newMethod("deobf/A_Basic", "m2", "()I"));
58 assertMapping(newMethod("none/a", "a", "(I)V"), newMethod("deobf/A_Basic", "m3", "(I)V"));
59 assertMapping(newMethod("none/a", "a", "(I)I"), newMethod("deobf/A_Basic", "m4", "(I)I"));
60 }
61
62 // TODO: basic constructors
63
64 @Test
65 public void inheritanceFields() {
66 assertMapping(newField("none/b", "a", "I"), newField("deobf/B_BaseClass", "f1", "I"));
67 assertMapping(newField("none/b", "a", "C"), newField("deobf/B_BaseClass", "f2", "C"));
68 assertMapping(newField("none/c", "b", "I"), newField("deobf/C_SubClass", "f3", "I"));
69 assertMapping(newField("none/c", "c", "I"), newField("deobf/C_SubClass", "f4", "I"));
70 }
71
72 @Test
73 public void inheritanceFieldsShadowing() {
74 assertMapping(newField("none/c", "b", "C"), newField("deobf/C_SubClass", "f2", "C"));
75 }
76
77 @Test
78 public void inheritanceFieldsBySubClass() {
79 assertMapping(newField("none/c", "a", "I"), newField("deobf/C_SubClass", "f1", "I"));
80 // NOTE: can't reference b.C by subclass since it's shadowed
81 }
82
83 @Test
84 public void inheritanceMethods() {
85 assertMapping(newMethod("none/b", "a", "()I"), newMethod("deobf/B_BaseClass", "m1", "()I"));
86 assertMapping(newMethod("none/b", "b", "()I"), newMethod("deobf/B_BaseClass", "m2", "()I"));
87 assertMapping(newMethod("none/c", "c", "()I"), newMethod("deobf/C_SubClass", "m3", "()I"));
88 }
89
90 @Test
91 public void inheritanceMethodsOverrides() {
92 assertMapping(newMethod("none/c", "a", "()I"), newMethod("deobf/C_SubClass", "m1", "()I"));
93 }
94
95 @Test
96 public void inheritanceMethodsBySubClass() {
97 assertMapping(newMethod("none/c", "b", "()I"), newMethod("deobf/C_SubClass", "m2", "()I"));
98 }
99
100 private void assertMapping(Entry obf, Entry deobf) {
101 assertThat(m_deobfTranslator.translateEntry(obf), is(deobf));
102 assertThat(m_obfTranslator.translateEntry(deobf), is(obf));
41 } 103 }
42} 104}
diff --git a/test/cuchaz/enigma/TestType.java b/test/cuchaz/enigma/TestType.java
index 7c3cebe2..93f864b0 100644
--- a/test/cuchaz/enigma/TestType.java
+++ b/test/cuchaz/enigma/TestType.java
@@ -7,7 +7,7 @@ import static org.hamcrest.Matchers.*;
7 7
8import cuchaz.enigma.mapping.Type; 8import cuchaz.enigma.mapping.Type;
9 9
10import static cuchaz.enigma.EntryFactory.*; 10import static cuchaz.enigma.TestEntryFactory.*;
11 11
12 12
13public class TestType { 13public class TestType {
diff --git a/test/cuchaz/enigma/inputs/translation/A.java b/test/cuchaz/enigma/inputs/translation/A.java
deleted file mode 100644
index b8aaf11e..00000000
--- a/test/cuchaz/enigma/inputs/translation/A.java
+++ /dev/null
@@ -1,8 +0,0 @@
1package cuchaz.enigma.inputs.translation;
2
3public class A {
4
5 public int one;
6 public float two;
7 public String three;
8}
diff --git a/test/cuchaz/enigma/inputs/translation/A_Basic.java b/test/cuchaz/enigma/inputs/translation/A_Basic.java
new file mode 100644
index 00000000..89307630
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/translation/A_Basic.java
@@ -0,0 +1,22 @@
1package cuchaz.enigma.inputs.translation;
2
3public class A_Basic {
4
5 public int one;
6 public float two;
7 public String three;
8
9 public void m1() {
10 }
11
12 public int m2() {
13 return 42;
14 }
15
16 public void m3(int a1) {
17 }
18
19 public int m4(int a1) {
20 return 5; // chosen by fair die roll, guaranteed to be random
21 }
22}
diff --git a/test/cuchaz/enigma/inputs/translation/B_BaseClass.java b/test/cuchaz/enigma/inputs/translation/B_BaseClass.java
new file mode 100644
index 00000000..44fbc8db
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/translation/B_BaseClass.java
@@ -0,0 +1,15 @@
1package cuchaz.enigma.inputs.translation;
2
3public class B_BaseClass {
4
5 public int f1;
6 public char f2;
7
8 public int m1() {
9 return 5;
10 }
11
12 public int m2() {
13 return 42;
14 }
15}
diff --git a/test/cuchaz/enigma/inputs/translation/C_SubClass.java b/test/cuchaz/enigma/inputs/translation/C_SubClass.java
new file mode 100644
index 00000000..8fe0b799
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/translation/C_SubClass.java
@@ -0,0 +1,17 @@
1package cuchaz.enigma.inputs.translation;
2
3public class C_SubClass extends B_BaseClass {
4
5 public char f2; // shadows B_BaseClass.f2
6 public int f3;
7 public int f4;
8
9 @Override
10 public int m1() {
11 return 32;
12 }
13
14 public int m3() {
15 return 7;
16 }
17}
diff --git a/test/cuchaz/enigma/resources/translation.mappings b/test/cuchaz/enigma/resources/translation.mappings
index c71493e9..d87d437c 100644
--- a/test/cuchaz/enigma/resources/translation.mappings
+++ b/test/cuchaz/enigma/resources/translation.mappings
@@ -1,4 +1,19 @@
1CLASS none/a deobf/A 1CLASS none/a deobf/A_Basic
2 FIELD a one I 2 FIELD a f1 I
3 FIELD a two F 3 FIELD a f2 F
4 FIELD a three Ljava/lang/String; \ No newline at end of file 4 FIELD a f3 Ljava/lang/String;
5 METHOD a m1 ()V
6 METHOD a m2 ()I
7 METHOD a m3 (I)V
8 METHOD a m4 (I)I
9CLASS none/b deobf/B_BaseClass
10 FIELD a f1 I
11 FIELD a f2 C
12 METHOD a m1 ()I
13 METHOD b m2 ()I
14CLASS none/c deobf/C_SubClass
15 FIELD b f2 C
16 FIELD b f3 I
17 FIELD c f4 I
18 METHOD a m1 ()I
19 METHOD c m3 ()I