summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/translation/representation
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/translation/representation
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/translation/representation')
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java112
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java132
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/ProcyonEntryFactory.java45
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/ReferencedEntryPool.java60
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/Signature.java93
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java268
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java92
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java180
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/DefEntry.java7
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java99
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java61
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java86
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java45
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java92
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java77
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java95
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java71
17 files changed, 1615 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java b/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java
new file mode 100644
index 0000000..0534edd
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java
@@ -0,0 +1,112 @@
1package cuchaz.enigma.translation.representation;
2
3import cuchaz.enigma.analysis.Access;
4import org.objectweb.asm.Opcodes;
5
6import java.lang.reflect.Modifier;
7
8public class AccessFlags {
9 public static final AccessFlags PRIVATE = new AccessFlags(Opcodes.ACC_PRIVATE);
10 public static final AccessFlags PUBLIC = new AccessFlags(Opcodes.ACC_PUBLIC);
11
12 private int flags;
13
14 public AccessFlags(int flags) {
15 this.flags = flags;
16 }
17
18 public boolean isPrivate() {
19 return Modifier.isPrivate(this.flags);
20 }
21
22 public boolean isProtected() {
23 return Modifier.isProtected(this.flags);
24 }
25
26 public boolean isPublic() {
27 return Modifier.isPublic(this.flags);
28 }
29
30 public boolean isSynthetic() {
31 return (this.flags & Opcodes.ACC_SYNTHETIC) != 0;
32 }
33
34 public boolean isStatic() {
35 return Modifier.isStatic(this.flags);
36 }
37
38 public boolean isEnum() {
39 return (flags & Opcodes.ACC_ENUM) != 0;
40 }
41
42 public boolean isBridge() {
43 return (flags & Opcodes.ACC_BRIDGE) != 0;
44 }
45
46 public boolean isFinal() {
47 return (flags & Opcodes.ACC_FINAL) != 0;
48 }
49
50 public AccessFlags setPrivate() {
51 this.setVisibility(Opcodes.ACC_PRIVATE);
52 return this;
53 }
54
55 public AccessFlags setProtected() {
56 this.setVisibility(Opcodes.ACC_PROTECTED);
57 return this;
58 }
59
60 public AccessFlags setPublic() {
61 this.setVisibility(Opcodes.ACC_PUBLIC);
62 return this;
63 }
64
65 public AccessFlags setBridge() {
66 flags |= Opcodes.ACC_BRIDGE;
67 return this;
68 }
69
70 @Deprecated
71 public AccessFlags setBridged() {
72 return setBridge();
73 }
74
75 public void setVisibility(int visibility) {
76 this.resetVisibility();
77 this.flags |= visibility;
78 }
79
80 private void resetVisibility() {
81 this.flags &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC);
82 }
83
84 public int getFlags() {
85 return this.flags;
86 }
87
88 @Override
89 public boolean equals(Object obj) {
90 return obj instanceof AccessFlags && ((AccessFlags) obj).flags == flags;
91 }
92
93 @Override
94 public int hashCode() {
95 return flags;
96 }
97
98 @Override
99 public String toString() {
100 StringBuilder builder = new StringBuilder(Access.get(this).toString().toLowerCase());
101 if (isStatic()) {
102 builder.append(" static");
103 }
104 if (isSynthetic()) {
105 builder.append(" synthetic");
106 }
107 if (isBridge()) {
108 builder.append(" bridge");
109 }
110 return builder.toString();
111 }
112}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java b/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java
new file mode 100644
index 0000000..c59751f
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java
@@ -0,0 +1,132 @@
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.translation.representation;
13
14import com.google.common.collect.Lists;
15import cuchaz.enigma.translation.Translatable;
16import cuchaz.enigma.translation.Translator;
17import cuchaz.enigma.translation.mapping.EntryMapping;
18import cuchaz.enigma.translation.mapping.EntryResolver;
19import cuchaz.enigma.translation.mapping.EntryMap;
20import cuchaz.enigma.translation.representation.entry.ClassEntry;
21import cuchaz.enigma.utils.Utils;
22
23import java.util.ArrayList;
24import java.util.List;
25import java.util.function.Function;
26
27public class MethodDescriptor implements Translatable {
28
29 private List<TypeDescriptor> argumentDescs;
30 private TypeDescriptor returnDesc;
31
32 public MethodDescriptor(String desc) {
33 try {
34 this.argumentDescs = Lists.newArrayList();
35 int i = 0;
36 while (i < desc.length()) {
37 char c = desc.charAt(i);
38 if (c == '(') {
39 assert (this.argumentDescs.isEmpty());
40 assert (this.returnDesc == null);
41 i++;
42 } else if (c == ')') {
43 i++;
44 break;
45 } else {
46 String type = TypeDescriptor.parseFirst(desc.substring(i));
47 this.argumentDescs.add(new TypeDescriptor(type));
48 i += type.length();
49 }
50 }
51 this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i)));
52 } catch (Exception ex) {
53 throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex);
54 }
55 }
56
57 public MethodDescriptor(List<TypeDescriptor> argumentDescs, TypeDescriptor returnDesc) {
58 this.argumentDescs = argumentDescs;
59 this.returnDesc = returnDesc;
60 }
61
62 public List<TypeDescriptor> getArgumentDescs() {
63 return this.argumentDescs;
64 }
65
66 public TypeDescriptor getReturnDesc() {
67 return this.returnDesc;
68 }
69
70 @Override
71 public String toString() {
72 StringBuilder buf = new StringBuilder();
73 buf.append("(");
74 for (TypeDescriptor desc : this.argumentDescs) {
75 buf.append(desc);
76 }
77 buf.append(")");
78 buf.append(this.returnDesc);
79 return buf.toString();
80 }
81
82 public Iterable<TypeDescriptor> types() {
83 List<TypeDescriptor> descs = Lists.newArrayList();
84 descs.addAll(this.argumentDescs);
85 descs.add(this.returnDesc);
86 return descs;
87 }
88
89 @Override
90 public boolean equals(Object other) {
91 return other instanceof MethodDescriptor && equals((MethodDescriptor) other);
92 }
93
94 public boolean equals(MethodDescriptor other) {
95 return this.argumentDescs.equals(other.argumentDescs) && this.returnDesc.equals(other.returnDesc);
96 }
97
98 @Override
99 public int hashCode() {
100 return Utils.combineHashesOrdered(this.argumentDescs.hashCode(), this.returnDesc.hashCode());
101 }
102
103 public boolean hasClass(ClassEntry classEntry) {
104 for (TypeDescriptor desc : types()) {
105 if (desc.containsType() && desc.getTypeEntry().equals(classEntry)) {
106 return true;
107 }
108 }
109 return false;
110 }
111
112 public MethodDescriptor remap(Function<String, String> remapper) {
113 List<TypeDescriptor> argumentDescs = new ArrayList<>(this.argumentDescs.size());
114 for (TypeDescriptor desc : this.argumentDescs) {
115 argumentDescs.add(desc.remap(remapper));
116 }
117 return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper));
118 }
119
120 @Override
121 public Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
122 List<TypeDescriptor> translatedArguments = new ArrayList<>(argumentDescs.size());
123 for (TypeDescriptor argument : argumentDescs) {
124 translatedArguments.add(translator.translate(argument));
125 }
126 return new MethodDescriptor(translatedArguments, translator.translate(returnDesc));
127 }
128
129 public boolean canConflictWith(MethodDescriptor descriptor) {
130 return descriptor.argumentDescs.equals(argumentDescs);
131 }
132}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/ProcyonEntryFactory.java b/src/main/java/cuchaz/enigma/translation/representation/ProcyonEntryFactory.java
new file mode 100644
index 0000000..9c9fa3d
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/ProcyonEntryFactory.java
@@ -0,0 +1,45 @@
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.translation.representation;
13
14import com.strobel.assembler.metadata.FieldDefinition;
15import com.strobel.assembler.metadata.MemberReference;
16import com.strobel.assembler.metadata.MethodDefinition;
17import cuchaz.enigma.translation.representation.entry.*;
18
19public class ProcyonEntryFactory {
20 private final ReferencedEntryPool entryPool;
21
22 public ProcyonEntryFactory(ReferencedEntryPool entryPool) {
23 this.entryPool = entryPool;
24 }
25
26 public FieldEntry getFieldEntry(MemberReference def) {
27 ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
28 return entryPool.getField(classEntry, def.getName(), def.getErasedSignature());
29 }
30
31 public FieldDefEntry getFieldDefEntry(FieldDefinition def) {
32 ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
33 return new FieldDefEntry(classEntry, def.getName(), new TypeDescriptor(def.getErasedSignature()), Signature.createTypedSignature(def.getSignature()), new AccessFlags(def.getModifiers()));
34 }
35
36 public MethodEntry getMethodEntry(MemberReference def) {
37 ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
38 return entryPool.getMethod(classEntry, def.getName(), def.getErasedSignature());
39 }
40
41 public MethodDefEntry getMethodDefEntry(MethodDefinition def) {
42 ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
43 return new MethodDefEntry(classEntry, def.getName(), new MethodDescriptor(def.getErasedSignature()), Signature.createSignature(def.getSignature()), new AccessFlags(def.getModifiers()));
44 }
45}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/ReferencedEntryPool.java b/src/main/java/cuchaz/enigma/translation/representation/ReferencedEntryPool.java
new file mode 100644
index 0000000..631b375
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/ReferencedEntryPool.java
@@ -0,0 +1,60 @@
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.translation.representation;
13
14import cuchaz.enigma.translation.representation.entry.ClassEntry;
15import cuchaz.enigma.translation.representation.entry.FieldEntry;
16import cuchaz.enigma.translation.representation.entry.MethodEntry;
17
18import java.util.HashMap;
19import java.util.Map;
20
21public class ReferencedEntryPool {
22 private final Map<String, ClassEntry> classEntries = new HashMap<>();
23 private final Map<String, Map<String, MethodEntry>> methodEntries = new HashMap<>();
24 private final Map<String, Map<String, FieldEntry>> fieldEntries = new HashMap<>();
25
26 public ClassEntry getClass(String name) {
27 // TODO: FIXME - I'm a hack!
28 if ("[T".equals(name) || "[[T".equals(name) || "[[[T".equals(name)) {
29 name = name.replaceAll("T", "Ljava/lang/Object;");
30 }
31
32 final String computeName = name;
33 return this.classEntries.computeIfAbsent(name, s -> new ClassEntry(computeName));
34 }
35
36 public MethodEntry getMethod(ClassEntry ownerEntry, String name, String desc) {
37 return getMethod(ownerEntry, name, new MethodDescriptor(desc));
38 }
39
40 public MethodEntry getMethod(ClassEntry ownerEntry, String name, MethodDescriptor desc) {
41 String key = name + desc.toString();
42 return getClassMethods(ownerEntry.getFullName()).computeIfAbsent(key, s -> new MethodEntry(ownerEntry, name, desc));
43 }
44
45 public FieldEntry getField(ClassEntry ownerEntry, String name, String desc) {
46 return getField(ownerEntry, name, new TypeDescriptor(desc));
47 }
48
49 public FieldEntry getField(ClassEntry ownerEntry, String name, TypeDescriptor desc) {
50 return getClassFields(ownerEntry.getFullName()).computeIfAbsent(name, s -> new FieldEntry(ownerEntry, name, desc));
51 }
52
53 private Map<String, MethodEntry> getClassMethods(String name) {
54 return methodEntries.computeIfAbsent(name, s -> new HashMap<>());
55 }
56
57 private Map<String, FieldEntry> getClassFields(String name) {
58 return fieldEntries.computeIfAbsent(name, s -> new HashMap<>());
59 }
60}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/Signature.java b/src/main/java/cuchaz/enigma/translation/representation/Signature.java
new file mode 100644
index 0000000..dc241b7
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/Signature.java
@@ -0,0 +1,93 @@
1package cuchaz.enigma.translation.representation;
2
3import cuchaz.enigma.bytecode.translators.TranslationSignatureVisitor;
4import cuchaz.enigma.translation.Translatable;
5import cuchaz.enigma.translation.Translator;
6import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.EntryResolver;
8import cuchaz.enigma.translation.mapping.EntryMap;
9import cuchaz.enigma.translation.representation.entry.ClassEntry;
10import org.objectweb.asm.signature.SignatureReader;
11import org.objectweb.asm.signature.SignatureVisitor;
12import org.objectweb.asm.signature.SignatureWriter;
13
14import java.util.function.Function;
15import java.util.regex.Pattern;
16
17public class Signature implements Translatable {
18 private static final Pattern OBJECT_PATTERN = Pattern.compile(".*:Ljava/lang/Object;:.*");
19
20 private final String signature;
21 private final boolean isType;
22
23 private Signature(String signature, boolean isType) {
24 if (signature != null && OBJECT_PATTERN.matcher(signature).matches()) {
25 signature = signature.replaceAll(":Ljava/lang/Object;:", "::");
26 }
27
28 this.signature = signature;
29 this.isType = isType;
30 }
31
32 public static Signature createTypedSignature(String signature) {
33 if (signature != null && !signature.isEmpty()) {
34 return new Signature(signature, true);
35 }
36 return new Signature(null, true);
37 }
38
39 public static Signature createSignature(String signature) {
40 if (signature != null && !signature.isEmpty()) {
41 return new Signature(signature, false);
42 }
43 return new Signature(null, false);
44 }
45
46 public String getSignature() {
47 return signature;
48 }
49
50 public boolean isType() {
51 return isType;
52 }
53
54 public Signature remap(Function<String, String> remapper) {
55 if (signature == null) {
56 return this;
57 }
58 SignatureWriter writer = new SignatureWriter();
59 SignatureVisitor visitor = new TranslationSignatureVisitor(remapper, writer);
60 if (isType) {
61 new SignatureReader(signature).acceptType(visitor);
62 } else {
63 new SignatureReader(signature).accept(visitor);
64 }
65 return new Signature(writer.toString(), isType);
66 }
67
68 @Override
69 public boolean equals(Object obj) {
70 if (obj instanceof Signature) {
71 Signature other = (Signature) obj;
72 return (other.signature == null && signature == null || other.signature != null
73 && signature != null && other.signature.equals(signature))
74 && other.isType == this.isType;
75 }
76 return false;
77 }
78
79 @Override
80 public int hashCode() {
81 return signature.hashCode() | (isType ? 1 : 0) << 16;
82 }
83
84 @Override
85 public String toString() {
86 return signature;
87 }
88
89 @Override
90 public Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
91 return remap(name -> translator.translate(new ClassEntry(name)).getFullName());
92 }
93}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java b/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
new file mode 100644
index 0000000..f7ba849
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
@@ -0,0 +1,268 @@
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.translation.representation;
13
14import com.google.common.base.Preconditions;
15import com.google.common.collect.Maps;
16import cuchaz.enigma.translation.Translatable;
17import cuchaz.enigma.translation.Translator;
18import cuchaz.enigma.translation.mapping.EntryMapping;
19import cuchaz.enigma.translation.mapping.EntryResolver;
20import cuchaz.enigma.translation.mapping.EntryMap;
21import cuchaz.enigma.translation.representation.entry.ClassEntry;
22
23import java.util.Map;
24import java.util.function.Function;
25
26public class TypeDescriptor implements Translatable {
27
28 protected final String desc;
29
30 public TypeDescriptor(String desc) {
31 Preconditions.checkNotNull(desc, "Desc cannot be null");
32
33 // don't deal with generics
34 // this is just for raw jvm types
35 if (desc.charAt(0) == 'T' || desc.indexOf('<') >= 0 || desc.indexOf('>') >= 0) {
36 throw new IllegalArgumentException("don't use with generic types or templates: " + desc);
37 }
38
39 this.desc = desc;
40 }
41
42 public static String parseFirst(String in) {
43
44 if (in == null || in.length() <= 0) {
45 throw new IllegalArgumentException("No desc to parse, input is empty!");
46 }
47
48 // read one desc from the input
49
50 char c = in.charAt(0);
51
52 // first check for void
53 if (c == 'V') {
54 return "V";
55 }
56
57 // then check for primitives
58 Primitive primitive = Primitive.get(c);
59 if (primitive != null) {
60 return in.substring(0, 1);
61 }
62
63 // then check for classes
64 if (c == 'L') {
65 return readClass(in);
66 }
67
68 // then check for templates
69 if (c == 'T') {
70 return readClass(in);
71 }
72
73 // then check for arrays
74 int dim = countArrayDimension(in);
75 if (dim > 0) {
76 String arrayType = TypeDescriptor.parseFirst(in.substring(dim));
77 return in.substring(0, dim + arrayType.length());
78 }
79
80 throw new IllegalArgumentException("don't know how to parse: " + in);
81 }
82
83 private static int countArrayDimension(String in) {
84 int i = 0;
85 while (i < in.length() && in.charAt(i) == '[')
86 i++;
87 return i;
88 }
89
90 private static String readClass(String in) {
91 // read all the characters in the buffer until we hit a ';'
92 // include the parameters too
93 StringBuilder buf = new StringBuilder();
94 int depth = 0;
95 for (int i = 0; i < in.length(); i++) {
96 char c = in.charAt(i);
97 buf.append(c);
98
99 if (c == '<') {
100 depth++;
101 } else if (c == '>') {
102 depth--;
103 } else if (depth == 0 && c == ';') {
104 return buf.toString();
105 }
106 }
107 return null;
108 }
109
110 public static TypeDescriptor of(String name) {
111 return new TypeDescriptor("L" + name + ";");
112 }
113
114 @Override
115 public String toString() {
116 return this.desc;
117 }
118
119 public boolean isVoid() {
120 return this.desc.length() == 1 && this.desc.charAt(0) == 'V';
121 }
122
123 public boolean isPrimitive() {
124 return this.desc.length() == 1 && Primitive.get(this.desc.charAt(0)) != null;
125 }
126
127 public Primitive getPrimitive() {
128 if (!isPrimitive()) {
129 throw new IllegalStateException("not a primitive");
130 }
131 return Primitive.get(this.desc.charAt(0));
132 }
133
134 public boolean isType() {
135 return this.desc.charAt(0) == 'L' && this.desc.charAt(this.desc.length() - 1) == ';';
136 }
137
138 public ClassEntry getTypeEntry() {
139 if (isType()) {
140 String name = this.desc.substring(1, this.desc.length() - 1);
141
142 int pos = name.indexOf('<');
143 if (pos >= 0) {
144 // remove the parameters from the class name
145 name = name.substring(0, pos);
146 }
147
148 return new ClassEntry(name);
149
150 } else if (isArray() && getArrayType().isType()) {
151 return getArrayType().getTypeEntry();
152 } else {
153 throw new IllegalStateException("desc doesn't have a class");
154 }
155 }
156
157 public boolean isArray() {
158 return this.desc.charAt(0) == '[';
159 }
160
161 public int getArrayDimension() {
162 if (!isArray()) {
163 throw new IllegalStateException("not an array");
164 }
165 return countArrayDimension(this.desc);
166 }
167
168 public TypeDescriptor getArrayType() {
169 if (!isArray()) {
170 throw new IllegalStateException("not an array");
171 }
172 return new TypeDescriptor(this.desc.substring(getArrayDimension()));
173 }
174
175 public boolean containsType() {
176 return isType() || (isArray() && getArrayType().containsType());
177 }
178
179 @Override
180 public boolean equals(Object other) {
181 return other instanceof TypeDescriptor && equals((TypeDescriptor) other);
182 }
183
184 public boolean equals(TypeDescriptor other) {
185 return this.desc.equals(other.desc);
186 }
187
188 @Override
189 public int hashCode() {
190 return this.desc.hashCode();
191 }
192
193 public TypeDescriptor remap(Function<String, String> remapper) {
194 String desc = this.desc;
195 if (isType() || (isArray() && containsType())) {
196 String replacedName = remapper.apply(this.getTypeEntry().getFullName());
197 if (replacedName != null) {
198 if (this.isType()) {
199 desc = "L" + replacedName + ";";
200 } else {
201 desc = getArrayPrefix(this.getArrayDimension()) + "L" + replacedName + ";";
202 }
203 }
204 }
205 return new TypeDescriptor(desc);
206 }
207
208 private static String getArrayPrefix(int dimension) {
209 StringBuilder buf = new StringBuilder();
210 for (int i = 0; i < dimension; i++) {
211 buf.append("[");
212 }
213 return buf.toString();
214 }
215
216 public int getSize() {
217 switch (desc.charAt(0)) {
218 case 'J':
219 case 'D':
220 if (desc.length() == 1) {
221 return 2;
222 } else {
223 return 1;
224 }
225 default:
226 return 1;
227 }
228 }
229
230 @Override
231 public Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
232 return remap(name -> translator.translate(new ClassEntry(name)).getFullName());
233 }
234
235 public enum Primitive {
236 BYTE('B'),
237 CHARACTER('C'),
238 SHORT('S'),
239 INTEGER('I'),
240 LONG('J'),
241 FLOAT('F'),
242 DOUBLE('D'),
243 BOOLEAN('Z');
244
245 private static final Map<Character, Primitive> lookup;
246
247 static {
248 lookup = Maps.newTreeMap();
249 for (Primitive val : values()) {
250 lookup.put(val.getCode(), val);
251 }
252 }
253
254 private char code;
255
256 Primitive(char code) {
257 this.code = code;
258 }
259
260 public static Primitive get(char code) {
261 return lookup.get(code);
262 }
263
264 public char getCode() {
265 return this.code;
266 }
267 }
268}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
new file mode 100644
index 0000000..b9391b0
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
@@ -0,0 +1,92 @@
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.translation.representation.entry;
13
14import com.google.common.base.Preconditions;
15import com.strobel.assembler.metadata.TypeDefinition;
16import cuchaz.enigma.translation.Translator;
17import cuchaz.enigma.translation.mapping.EntryMapping;
18import cuchaz.enigma.translation.representation.AccessFlags;
19import cuchaz.enigma.translation.representation.Signature;
20
21import javax.annotation.Nullable;
22import java.util.Arrays;
23
24public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> {
25 private final AccessFlags access;
26 private final Signature signature;
27 private final ClassEntry superClass;
28 private final ClassEntry[] interfaces;
29
30 public ClassDefEntry(String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, ClassEntry[] interfaces) {
31 this(getOuterClass(className), getInnerName(className), signature, access, superClass, interfaces);
32 }
33
34 public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, ClassEntry[] interfaces) {
35 super(parent, className);
36 Preconditions.checkNotNull(signature, "Class signature cannot be null");
37 Preconditions.checkNotNull(access, "Class access cannot be null");
38
39 this.signature = signature;
40 this.access = access;
41 this.superClass = superClass;
42 this.interfaces = interfaces != null ? interfaces : new ClassEntry[0];
43 }
44
45 public static ClassDefEntry parse(int access, String name, String signature, String superName, String[] interfaces) {
46 ClassEntry superClass = superName != null ? new ClassEntry(superName) : null;
47 ClassEntry[] interfaceClasses = Arrays.stream(interfaces).map(ClassEntry::new).toArray(ClassEntry[]::new);
48 return new ClassDefEntry(name, Signature.createSignature(signature), new AccessFlags(access), superClass, interfaceClasses);
49 }
50
51 public static ClassDefEntry parse(TypeDefinition def) {
52 String name = def.getInternalName();
53 Signature signature = Signature.createSignature(def.getSignature());
54 AccessFlags access = new AccessFlags(def.getModifiers());
55 ClassEntry superClass = def.getBaseType() != null ? ClassEntry.parse(def.getBaseType()) : null;
56 ClassEntry[] interfaces = def.getExplicitInterfaces().stream().map(ClassEntry::parse).toArray(ClassEntry[]::new);
57 return new ClassDefEntry(name, signature, access, superClass, interfaces);
58 }
59
60 public Signature getSignature() {
61 return signature;
62 }
63
64 @Override
65 public AccessFlags getAccess() {
66 return access;
67 }
68
69 @Nullable
70 public ClassEntry getSuperClass() {
71 return superClass;
72 }
73
74 public ClassEntry[] getInterfaces() {
75 return interfaces;
76 }
77
78 @Override
79 public ClassDefEntry translate(Translator translator, @Nullable EntryMapping mapping) {
80 Signature translatedSignature = translator.translate(signature);
81 String translatedName = mapping != null ? mapping.getTargetName() : name;
82 AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access;
83 ClassEntry translatedSuper = translator.translate(superClass);
84 ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new);
85 return new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces);
86 }
87
88 @Override
89 public ClassDefEntry withParent(ClassEntry parent) {
90 return new ClassDefEntry(parent, name, signature, access, superClass, interfaces);
91 }
92}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
new file mode 100644
index 0000000..dcbb8d9
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
@@ -0,0 +1,180 @@
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.translation.representation.entry;
13
14import com.strobel.assembler.metadata.TypeReference;
15import cuchaz.enigma.throwables.IllegalNameException;
16import cuchaz.enigma.translation.Translator;
17import cuchaz.enigma.translation.mapping.EntryMapping;
18import cuchaz.enigma.translation.mapping.NameValidator;
19
20import javax.annotation.Nullable;
21import java.util.List;
22import java.util.Objects;
23
24public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<ClassEntry> {
25 private final String fullName;
26
27 public ClassEntry(String className) {
28 this(getOuterClass(className), getInnerName(className));
29 }
30
31 public ClassEntry(@Nullable ClassEntry parent, String className) {
32 super(parent, className);
33 if (parent != null) {
34 fullName = parent.getFullName() + "$" + name;
35 } else {
36 fullName = name;
37 }
38
39 if (parent == null && className.indexOf('.') >= 0) {
40 throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className);
41 }
42 }
43
44 public static ClassEntry parse(TypeReference typeReference) {
45 return new ClassEntry(typeReference.getInternalName());
46 }
47
48 @Override
49 public Class<ClassEntry> getParentType() {
50 return ClassEntry.class;
51 }
52
53 @Override
54 public String getName() {
55 return this.name;
56 }
57
58 public String getFullName() {
59 return fullName;
60 }
61
62 @Override
63 public ClassEntry translate(Translator translator, @Nullable EntryMapping mapping) {
64 String translatedName = mapping != null ? mapping.getTargetName() : name;
65 return new ClassEntry(parent, translatedName);
66 }
67
68 @Override
69 public ClassEntry getContainingClass() {
70 return this;
71 }
72
73 @Override
74 public int hashCode() {
75 return fullName.hashCode();
76 }
77
78 @Override
79 public boolean equals(Object other) {
80 return other instanceof ClassEntry && equals((ClassEntry) other);
81 }
82
83 public boolean equals(ClassEntry other) {
84 return other != null && Objects.equals(parent, other.parent) && this.name.equals(other.name);
85 }
86
87 @Override
88 public boolean canConflictWith(Entry<?> entry) {
89 return true;
90 }
91
92 @Override
93 public void validateName(String name) throws IllegalNameException {
94 NameValidator.validateClassName(name, !isInnerClass());
95 }
96
97 @Override
98 public ClassEntry withParent(ClassEntry parent) {
99 return new ClassEntry(parent, name);
100 }
101
102 @Override
103 public String toString() {
104 return getFullName();
105 }
106
107 public String getPackageName() {
108 return getPackageName(this.name);
109 }
110
111 public String getSimpleName() {
112 int packagePos = name.lastIndexOf('/');
113 if (packagePos > 0) {
114 return name.substring(packagePos + 1);
115 }
116 return name;
117 }
118
119 public boolean isInnerClass() {
120 return parent != null;
121 }
122
123 @Nullable
124 public ClassEntry getOuterClass() {
125 return parent;
126 }
127
128 public ClassEntry buildClassEntry(List<ClassEntry> classChain) {
129 assert (classChain.contains(this));
130 StringBuilder buf = new StringBuilder();
131 for (ClassEntry chainEntry : classChain) {
132 if (buf.length() == 0) {
133 buf.append(chainEntry.getFullName());
134 } else {
135 buf.append("$");
136 buf.append(chainEntry.getSimpleName());
137 }
138
139 if (chainEntry == this) {
140 break;
141 }
142 }
143 return new ClassEntry(buf.toString());
144 }
145
146 public boolean isJre() {
147 String packageName = getPackageName();
148 return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax"));
149 }
150
151 public static String getPackageName(String name) {
152 int pos = name.lastIndexOf('/');
153 if (pos > 0) {
154 return name.substring(0, pos);
155 }
156 return null;
157 }
158
159 @Nullable
160 public static ClassEntry getOuterClass(String name) {
161 int index = name.lastIndexOf('$');
162 if (index >= 0) {
163 return new ClassEntry(name.substring(0, index));
164 }
165 return null;
166 }
167
168 public static String getInnerName(String name) {
169 int innerClassPos = name.lastIndexOf('$');
170 if (innerClassPos > 0) {
171 return name.substring(innerClassPos + 1);
172 }
173 return name;
174 }
175
176 @Override
177 public int compareTo(ClassEntry entry) {
178 return name.compareTo(entry.name);
179 }
180}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/DefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/DefEntry.java
new file mode 100644
index 0000000..82536c7
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/DefEntry.java
@@ -0,0 +1,7 @@
1package cuchaz.enigma.translation.representation.entry;
2
3import cuchaz.enigma.translation.representation.AccessFlags;
4
5public interface DefEntry<P extends Entry<?>> extends Entry<P> {
6 AccessFlags getAccess();
7}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
new file mode 100644
index 0000000..1a2ca78
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
@@ -0,0 +1,99 @@
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.translation.representation.entry;
13
14import cuchaz.enigma.throwables.IllegalNameException;
15import cuchaz.enigma.translation.Translatable;
16import cuchaz.enigma.translation.mapping.NameValidator;
17
18import javax.annotation.Nullable;
19import java.util.ArrayList;
20import java.util.List;
21
22public interface Entry<P extends Entry<?>> extends Translatable {
23 String getName();
24
25 @Nullable
26 P getParent();
27
28 Class<P> getParentType();
29
30 Entry<P> withParent(P parent);
31
32 boolean canConflictWith(Entry<?> entry);
33
34 @Nullable
35 default ClassEntry getContainingClass() {
36 P parent = getParent();
37 if (parent == null) {
38 return null;
39 }
40 if (parent instanceof ClassEntry) {
41 return (ClassEntry) parent;
42 }
43 return parent.getContainingClass();
44 }
45
46 default List<Entry<?>> getAncestry() {
47 P parent = getParent();
48 List<Entry<?>> entries = new ArrayList<>();
49 if (parent != null) {
50 entries.addAll(parent.getAncestry());
51 }
52 entries.add(this);
53 return entries;
54 }
55
56 @Nullable
57 @SuppressWarnings("unchecked")
58 default <E extends Entry<?>> E findAncestor(Class<E> type) {
59 List<Entry<?>> ancestry = getAncestry();
60 for (int i = ancestry.size() - 1; i >= 0; i--) {
61 Entry<?> ancestor = ancestry.get(i);
62 if (type.isAssignableFrom(ancestor.getClass())) {
63 return (E) ancestor;
64 }
65 }
66 return null;
67 }
68
69 @SuppressWarnings("unchecked")
70 default <E extends Entry<?>> Entry<P> replaceAncestor(E target, E replacement) {
71 if (replacement.equals(target)) {
72 return this;
73 }
74
75 if (equals(target)) {
76 return (Entry<P>) replacement;
77 }
78
79 P parent = getParent();
80 if (parent == null) {
81 return this;
82 }
83
84 return withParent((P) parent.replaceAncestor(target, replacement));
85 }
86
87 default void validateName(String name) throws IllegalNameException {
88 NameValidator.validateIdentifier(name);
89 }
90
91 @SuppressWarnings("unchecked")
92 @Nullable
93 default <C extends Entry<?>> Entry<C> castParent(Class<C> parentType) {
94 if (parentType.equals(getParentType())) {
95 return (Entry<C>) this;
96 }
97 return null;
98 }
99}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
new file mode 100644
index 0000000..d487f71
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
@@ -0,0 +1,61 @@
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.translation.representation.entry;
13
14import com.google.common.base.Preconditions;
15import cuchaz.enigma.translation.Translator;
16import cuchaz.enigma.translation.mapping.EntryMapping;
17import cuchaz.enigma.translation.representation.AccessFlags;
18import cuchaz.enigma.translation.representation.Signature;
19import cuchaz.enigma.translation.representation.TypeDescriptor;
20
21import javax.annotation.Nullable;
22
23public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> {
24 private final AccessFlags access;
25 private final Signature signature;
26
27 public FieldDefEntry(ClassEntry owner, String name, TypeDescriptor desc, Signature signature, AccessFlags access) {
28 super(owner, name, desc);
29 Preconditions.checkNotNull(access, "Field access cannot be null");
30 Preconditions.checkNotNull(signature, "Field signature cannot be null");
31 this.access = access;
32 this.signature = signature;
33 }
34
35 public static FieldDefEntry parse(ClassEntry owner, int access, String name, String desc, String signature) {
36 return new FieldDefEntry(owner, name, new TypeDescriptor(desc), Signature.createTypedSignature(signature), new AccessFlags(access));
37 }
38
39 @Override
40 public AccessFlags getAccess() {
41 return access;
42 }
43
44 public Signature getSignature() {
45 return signature;
46 }
47
48 @Override
49 public FieldDefEntry translate(Translator translator, @Nullable EntryMapping mapping) {
50 TypeDescriptor translatedDesc = translator.translate(desc);
51 Signature translatedSignature = translator.translate(signature);
52 String translatedName = mapping != null ? mapping.getTargetName() : name;
53 AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access;
54 return new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess);
55 }
56
57 @Override
58 public FieldDefEntry withParent(ClassEntry owner) {
59 return new FieldDefEntry(owner, this.name, this.desc, signature, access);
60 }
61}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
new file mode 100644
index 0000000..2ec2471
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
@@ -0,0 +1,86 @@
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.translation.representation.entry;
13
14import com.google.common.base.Preconditions;
15import cuchaz.enigma.translation.Translator;
16import cuchaz.enigma.translation.mapping.EntryMapping;
17import cuchaz.enigma.translation.representation.TypeDescriptor;
18import cuchaz.enigma.utils.Utils;
19
20import javax.annotation.Nullable;
21
22public class FieldEntry extends ParentedEntry<ClassEntry> implements Comparable<FieldEntry> {
23 protected final TypeDescriptor desc;
24
25 public FieldEntry(ClassEntry parent, String name, TypeDescriptor desc) {
26 super(parent, name);
27
28 Preconditions.checkNotNull(parent, "Owner cannot be null");
29 Preconditions.checkNotNull(desc, "Field descriptor cannot be null");
30
31 this.desc = desc;
32 }
33
34 public static FieldEntry parse(String owner, String name, String desc) {
35 return new FieldEntry(new ClassEntry(owner), name, new TypeDescriptor(desc));
36 }
37
38 @Override
39 public Class<ClassEntry> getParentType() {
40 return ClassEntry.class;
41 }
42
43 public TypeDescriptor getDesc() {
44 return this.desc;
45 }
46
47 @Override
48 public FieldEntry withParent(ClassEntry parent) {
49 return new FieldEntry(parent, this.name, this.desc);
50 }
51
52 @Override
53 protected FieldEntry translate(Translator translator, @Nullable EntryMapping mapping) {
54 String translatedName = mapping != null ? mapping.getTargetName() : name;
55 return new FieldEntry(parent, translatedName, translator.translate(desc));
56 }
57
58 @Override
59 public int hashCode() {
60 return Utils.combineHashesOrdered(this.parent, this.name, this.desc);
61 }
62
63 @Override
64 public boolean equals(Object other) {
65 return other instanceof FieldEntry && equals((FieldEntry) other);
66 }
67
68 public boolean equals(FieldEntry other) {
69 return this.parent.equals(other.parent) && name.equals(other.name) && desc.equals(other.desc);
70 }
71
72 @Override
73 public boolean canConflictWith(Entry<?> entry) {
74 return entry instanceof FieldEntry && ((FieldEntry) entry).parent.equals(parent);
75 }
76
77 @Override
78 public String toString() {
79 return this.parent.getFullName() + "." + this.name + ":" + this.desc;
80 }
81
82 @Override
83 public int compareTo(FieldEntry entry) {
84 return (name + desc.toString()).compareTo(entry.name + entry.desc.toString());
85 }
86}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
new file mode 100644
index 0000000..86bdf61
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
@@ -0,0 +1,45 @@
1package cuchaz.enigma.translation.representation.entry;
2
3import com.google.common.base.Preconditions;
4import cuchaz.enigma.translation.Translator;
5import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.translation.representation.TypeDescriptor;
7
8import javax.annotation.Nullable;
9
10/**
11 * TypeDescriptor...
12 * Created by Thog
13 * 19/10/2016
14 */
15public class LocalVariableDefEntry extends LocalVariableEntry {
16 protected final TypeDescriptor desc;
17
18 public LocalVariableDefEntry(MethodEntry ownerEntry, int index, String name, boolean parameter, TypeDescriptor desc) {
19 super(ownerEntry, index, name, parameter);
20 Preconditions.checkNotNull(desc, "Variable desc cannot be null");
21
22 this.desc = desc;
23 }
24
25 public TypeDescriptor getDesc() {
26 return desc;
27 }
28
29 @Override
30 public LocalVariableDefEntry translate(Translator translator, @Nullable EntryMapping mapping) {
31 TypeDescriptor translatedDesc = translator.translate(desc);
32 String translatedName = mapping != null ? mapping.getTargetName() : name;
33 return new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc);
34 }
35
36 @Override
37 public LocalVariableDefEntry withParent(MethodEntry entry) {
38 return new LocalVariableDefEntry(entry, index, name, parameter, desc);
39 }
40
41 @Override
42 public String toString() {
43 return this.parent + "(" + this.index + ":" + this.name + ":" + this.desc + ")";
44 }
45}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
new file mode 100644
index 0000000..df96b59
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
@@ -0,0 +1,92 @@
1package cuchaz.enigma.translation.representation.entry;
2
3import com.google.common.base.Preconditions;
4import cuchaz.enigma.translation.Translator;
5import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.utils.Utils;
7
8import javax.annotation.Nullable;
9
10/**
11 * TypeDescriptor...
12 * Created by Thog
13 * 19/10/2016
14 */
15public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Comparable<LocalVariableEntry> {
16
17 protected final int index;
18 protected final boolean parameter;
19
20 @Deprecated
21 public LocalVariableEntry(MethodEntry parent, int index, String name) {
22 this(parent, index, name, true);
23 }
24
25 public LocalVariableEntry(MethodEntry parent, int index, String name, boolean parameter) {
26 super(parent, name);
27
28 Preconditions.checkNotNull(parent, "Variable owner cannot be null");
29 Preconditions.checkArgument(index >= 0, "Index must be positive");
30
31 this.index = index;
32 this.parameter = parameter;
33 }
34
35 @Override
36 public Class<MethodEntry> getParentType() {
37 return MethodEntry.class;
38 }
39
40 public boolean isParameter() {
41 return this.parameter;
42 }
43
44 public int getIndex() {
45 return index;
46 }
47
48 @Override
49 public String getName() {
50 return this.name;
51 }
52
53 @Override
54 public LocalVariableEntry translate(Translator translator, @Nullable EntryMapping mapping) {
55 String translatedName = mapping != null ? mapping.getTargetName() : name;
56 return new LocalVariableEntry(parent, index, translatedName, parameter);
57 }
58
59 @Override
60 public LocalVariableEntry withParent(MethodEntry parent) {
61 return new LocalVariableEntry(parent, index, name, parameter);
62 }
63
64 @Override
65 public int hashCode() {
66 return Utils.combineHashesOrdered(this.parent, this.index);
67 }
68
69 @Override
70 public boolean equals(Object other) {
71 return other instanceof LocalVariableEntry && equals((LocalVariableEntry) other);
72 }
73
74 public boolean equals(LocalVariableEntry other) {
75 return this.parent.equals(other.parent) && this.index == other.index;
76 }
77
78 @Override
79 public boolean canConflictWith(Entry<?> entry) {
80 return entry instanceof LocalVariableEntry && ((LocalVariableEntry) entry).parent.equals(parent);
81 }
82
83 @Override
84 public String toString() {
85 return this.parent + "(" + this.index + ":" + this.name + ")";
86 }
87
88 @Override
89 public int compareTo(LocalVariableEntry entry) {
90 return Integer.compare(index, entry.index);
91 }
92}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
new file mode 100644
index 0000000..3ecd470
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
@@ -0,0 +1,77 @@
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.translation.representation.entry;
13
14import com.google.common.base.Preconditions;
15import cuchaz.enigma.translation.Translator;
16import cuchaz.enigma.translation.mapping.EntryMapping;
17import cuchaz.enigma.translation.representation.AccessFlags;
18import cuchaz.enigma.translation.representation.MethodDescriptor;
19import cuchaz.enigma.translation.representation.Signature;
20
21import javax.annotation.Nullable;
22
23public class MethodDefEntry extends MethodEntry implements DefEntry<ClassEntry> {
24 private final AccessFlags access;
25 private final Signature signature;
26
27 public MethodDefEntry(ClassEntry owner, String name, MethodDescriptor descriptor, Signature signature, AccessFlags access) {
28 super(owner, name, descriptor);
29 Preconditions.checkNotNull(access, "Method access cannot be null");
30 Preconditions.checkNotNull(signature, "Method signature cannot be null");
31 this.access = access;
32 this.signature = signature;
33 }
34
35 public static MethodDefEntry parse(ClassEntry owner, int access, String name, String desc, String signature) {
36 return new MethodDefEntry(owner, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access));
37 }
38
39 @Override
40 public AccessFlags getAccess() {
41 return access;
42 }
43
44 public Signature getSignature() {
45 return signature;
46 }
47
48 @Override
49 public MethodDefEntry translate(Translator translator, @Nullable EntryMapping mapping) {
50 MethodDescriptor translatedDesc = translator.translate(descriptor);
51 Signature translatedSignature = translator.translate(signature);
52 String translatedName = mapping != null ? mapping.getTargetName() : name;
53 AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access;
54 return new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess);
55 }
56
57 @Override
58 public MethodDefEntry withParent(ClassEntry parent) {
59 return new MethodDefEntry(new ClassEntry(parent.getFullName()), name, descriptor, signature, access);
60 }
61
62 public int getArgumentIndex(ClassDefEntry ownerEntry, int localVariableIndex) {
63 int argumentIndex = localVariableIndex;
64
65 // Enum constructors have an implicit "name" and "ordinal" parameter as well as "this"
66 if (ownerEntry.getAccess().isEnum() && getName().startsWith("<")) {
67 argumentIndex -= 2;
68 }
69
70 // If we're not static, "this" is bound to index 0
71 if (!getAccess().isStatic()) {
72 argumentIndex -= 1;
73 }
74
75 return argumentIndex;
76 }
77}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
new file mode 100644
index 0000000..3a1dbb3
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
@@ -0,0 +1,95 @@
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.translation.representation.entry;
13
14import com.google.common.base.Preconditions;
15import cuchaz.enigma.translation.Translator;
16import cuchaz.enigma.translation.mapping.EntryMapping;
17import cuchaz.enigma.translation.representation.MethodDescriptor;
18import cuchaz.enigma.utils.Utils;
19
20import javax.annotation.Nullable;
21
22public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable<MethodEntry> {
23
24 protected final MethodDescriptor descriptor;
25
26 public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor) {
27 super(parent, name);
28
29 Preconditions.checkNotNull(parent, "Parent cannot be null");
30 Preconditions.checkNotNull(descriptor, "Method descriptor cannot be null");
31
32 this.descriptor = descriptor;
33 }
34
35 public static MethodEntry parse(String owner, String name, String desc) {
36 return new MethodEntry(new ClassEntry(owner), name, new MethodDescriptor(desc));
37 }
38
39 @Override
40 public Class<ClassEntry> getParentType() {
41 return ClassEntry.class;
42 }
43
44 public MethodDescriptor getDesc() {
45 return this.descriptor;
46 }
47
48 public boolean isConstructor() {
49 return name.equals("<init>") || name.equals("<clinit>");
50 }
51
52 @Override
53 public MethodEntry translate(Translator translator, @Nullable EntryMapping mapping) {
54 String translatedName = mapping != null ? mapping.getTargetName() : name;
55 return new MethodEntry(parent, translatedName, translator.translate(descriptor));
56 }
57
58 @Override
59 public MethodEntry withParent(ClassEntry parent) {
60 return new MethodEntry(new ClassEntry(parent.getFullName()), name, descriptor);
61 }
62
63 @Override
64 public int hashCode() {
65 return Utils.combineHashesOrdered(this.parent, this.name, this.descriptor);
66 }
67
68 @Override
69 public boolean equals(Object other) {
70 return other instanceof MethodEntry && equals((MethodEntry) other);
71 }
72
73 public boolean equals(MethodEntry other) {
74 return this.parent.equals(other.getParent()) && this.name.equals(other.getName()) && this.descriptor.equals(other.getDesc());
75 }
76
77 @Override
78 public boolean canConflictWith(Entry<?> entry) {
79 if (entry instanceof MethodEntry) {
80 MethodEntry methodEntry = (MethodEntry) entry;
81 return methodEntry.parent.equals(parent) && methodEntry.descriptor.canConflictWith(descriptor);
82 }
83 return false;
84 }
85
86 @Override
87 public String toString() {
88 return this.parent.getFullName() + "." + this.name + this.descriptor;
89 }
90
91 @Override
92 public int compareTo(MethodEntry entry) {
93 return (name + descriptor.toString()).compareTo(entry.name + entry.descriptor.toString());
94 }
95}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
new file mode 100644
index 0000000..7ba7c19
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
@@ -0,0 +1,71 @@
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.translation.representation.entry;
13
14import com.google.common.base.Preconditions;
15import cuchaz.enigma.translation.Translatable;
16import cuchaz.enigma.translation.Translator;
17import cuchaz.enigma.translation.mapping.EntryMap;
18import cuchaz.enigma.translation.mapping.EntryMapping;
19import cuchaz.enigma.translation.mapping.EntryResolver;
20import cuchaz.enigma.translation.mapping.ResolutionStrategy;
21
22import javax.annotation.Nullable;
23
24public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> {
25 protected final P parent;
26 protected final String name;
27
28 protected ParentedEntry(P parent, String name) {
29 this.parent = parent;
30 this.name = name;
31
32 Preconditions.checkNotNull(name, "Name cannot be null");
33 }
34
35 @Override
36 public abstract ParentedEntry<P> withParent(P parent);
37
38 protected abstract ParentedEntry<P> translate(Translator translator, @Nullable EntryMapping mapping);
39
40 @Override
41 public String getName() {
42 return name;
43 }
44
45 @Override
46 @Nullable
47 public P getParent() {
48 return parent;
49 }
50
51 @Override
52 public Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
53 P parent = getParent();
54 EntryMapping mapping = resolveMapping(resolver, mappings);
55 if (parent == null) {
56 return translate(translator, mapping);
57 }
58 P translatedParent = translator.translate(parent);
59 return withParent(translatedParent).translate(translator, mapping);
60 }
61
62 private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings) {
63 for (ParentedEntry<P> entry : resolver.resolveEntry(this, ResolutionStrategy.RESOLVE_ROOT)) {
64 EntryMapping mapping = mappings.get(entry);
65 if (mapping != null) {
66 return mapping;
67 }
68 }
69 return null;
70 }
71}