diff options
| author | 2018-12-15 22:29:41 +0200 | |
|---|---|---|
| committer | 2018-12-15 21:29:41 +0100 | |
| commit | 4ff89cb1d48cb6916220ee308bf40810cfd868e2 (patch) | |
| tree | 1145080fde3ea6d727848d15994a3b71478ee22f | |
| parent | Fix #78 (#85) (diff) | |
| download | enigma-4ff89cb1d48cb6916220ee308bf40810cfd868e2.tar.gz enigma-4ff89cb1d48cb6916220ee308bf40810cfd868e2.tar.xz enigma-4ff89cb1d48cb6916220ee308bf40810cfd868e2.zip | |
Tweak variable name generation (#86)
* Don't apply offset to all methods in abstract class
* Tweak local variable naming
5 files changed, 78 insertions, 42 deletions
diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java index 52b40b05..6d0d550b 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java | |||
| @@ -1,14 +1,13 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.mapping.MethodDescriptor; | 3 | import cuchaz.enigma.mapping.*; |
| 4 | import cuchaz.enigma.mapping.Signature; | ||
| 5 | import cuchaz.enigma.mapping.Translator; | ||
| 6 | import cuchaz.enigma.mapping.TypeDescriptor; | ||
| 7 | import cuchaz.enigma.mapping.entry.*; | 4 | import cuchaz.enigma.mapping.entry.*; |
| 8 | import org.objectweb.asm.*; | 5 | import org.objectweb.asm.*; |
| 9 | 6 | ||
| 7 | import java.util.Collection; | ||
| 10 | import java.util.List; | 8 | import java.util.List; |
| 11 | import java.util.Locale; | 9 | import java.util.Locale; |
| 10 | import java.util.stream.Collectors; | ||
| 12 | 11 | ||
| 13 | public class TranslationMethodVisitor extends MethodVisitor { | 12 | public class TranslationMethodVisitor extends MethodVisitor { |
| 14 | private final ClassDefEntry ownerEntry; | 13 | private final ClassDefEntry ownerEntry; |
| @@ -85,17 +84,26 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 85 | hasParameterMeta = true; | 84 | hasParameterMeta = true; |
| 86 | 85 | ||
| 87 | String translatedSignature = translator.getTranslatedSignature(Signature.createTypedSignature(signature)).toString(); | 86 | String translatedSignature = translator.getTranslatedSignature(Signature.createTypedSignature(signature)).toString(); |
| 88 | int offsetIndex = index; | 87 | int argumentIndex = methodEntry.getArgumentIndex(ownerEntry, index); |
| 89 | 88 | ||
| 90 | if (offsetIndex >= 0) { | 89 | if (argumentIndex >= 0) { |
| 91 | LocalVariableDefEntry entry = new LocalVariableDefEntry(methodEntry, offsetIndex, name, new TypeDescriptor(desc)); | 90 | LocalVariableDefEntry entry = new LocalVariableDefEntry(methodEntry, index, name, new TypeDescriptor(desc)); |
| 92 | LocalVariableDefEntry translatedEntry = translator.getTranslatedVariableDef(entry); | 91 | LocalVariableDefEntry translatedEntry = translator.getTranslatedVariableDef(entry); |
| 93 | String translatedName = translatedEntry.getName(); | 92 | String translatedName = translatedEntry.getName(); |
| 94 | 93 | ||
| 95 | // TODO: Better name inference | 94 | // TODO: Better name inference |
| 96 | if (translatedName.equals(entry.getName())) { | 95 | if (translatedName.equals(entry.getName())) { |
| 97 | boolean argument = offsetIndex < methodEntry.getDesc().getArgumentDescs().size(); | 96 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); |
| 98 | translatedName = inferName(argument, offsetIndex, translatedEntry.getDesc()); | 97 | List<TypeDescriptor> translatedArguments = arguments.stream() |
| 98 | .map(translator::getTranslatedTypeDesc) | ||
| 99 | .collect(Collectors.toList()); | ||
| 100 | |||
| 101 | boolean argument = argumentIndex < arguments.size(); | ||
| 102 | if (argument) { | ||
| 103 | translatedName = inferArgumentName(argumentIndex, translatedEntry.getDesc(), translatedArguments); | ||
| 104 | } else { | ||
| 105 | translatedName = inferLocalVariableName(argumentIndex, translatedEntry.getDesc()); | ||
| 106 | } | ||
| 99 | } | 107 | } |
| 100 | 108 | ||
| 101 | super.visitLocalVariable(translatedName, translatedEntry.getDesc().toString(), translatedSignature, start, end, index); | 109 | super.visitLocalVariable(translatedName, translatedEntry.getDesc().toString(), translatedSignature, start, end, index); |
| @@ -147,48 +155,56 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 147 | // If we didn't receive any parameter metadata, generate it | 155 | // If we didn't receive any parameter metadata, generate it |
| 148 | if (!hasParameterMeta) { | 156 | if (!hasParameterMeta) { |
| 149 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | 157 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); |
| 150 | int flags = ownerEntry.getAccess().getFlags(); | 158 | int offset = ((methodEntry.getAccess().getFlags() & Opcodes.ACC_ABSTRACT) != 0) ? 1 : 0; |
| 151 | int offset = ((flags & Opcodes.ACC_INTERFACE) != 0 || (flags & Opcodes.ACC_ABSTRACT) != 0) ? 1 : 0; | ||
| 152 | 159 | ||
| 153 | for (int index = 0; index < arguments.size(); index++) { | 160 | for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { |
| 154 | LocalVariableEntry entry = new LocalVariableEntry(methodEntry, offset, "", true); | 161 | LocalVariableEntry entry = new LocalVariableEntry(methodEntry, offset, "", true); |
| 155 | LocalVariableEntry translatedEntry = translator.getTranslatedVariable(entry); | 162 | LocalVariableEntry translatedEntry = translator.getTranslatedVariable(entry); |
| 156 | String translatedName = translatedEntry.getName(); | 163 | String translatedName = translatedEntry.getName(); |
| 157 | if (translatedName.equals(entry.getName())) { | 164 | if (translatedName.equals(entry.getName())) { |
| 158 | super.visitParameter(inferName(true, index, arguments.get(index)), 0); | 165 | super.visitParameter(inferArgumentName(argumentIndex, arguments.get(argumentIndex), arguments), 0); |
| 159 | } else { | 166 | } else { |
| 160 | super.visitParameter(translatedName, 0); | 167 | super.visitParameter(translatedName, 0); |
| 161 | } | 168 | } |
| 162 | 169 | ||
| 163 | offset += arguments.get(index).getSize(); | 170 | offset += arguments.get(argumentIndex).getSize(); |
| 164 | } | 171 | } |
| 165 | } | 172 | } |
| 166 | super.visitEnd(); | 173 | super.visitEnd(); |
| 167 | } | 174 | } |
| 168 | 175 | ||
| 169 | private String inferName(boolean argument, int argumentIndex, TypeDescriptor desc) { | 176 | private String inferArgumentName(int index, TypeDescriptor desc, Collection<TypeDescriptor> arguments) { |
| 177 | boolean uniqueType = arguments.stream().filter(desc::equals).count() <= 1; | ||
| 170 | String translatedName; | 178 | String translatedName; |
| 171 | int nameIndex = argumentIndex + 1; | 179 | int nameIndex = index + 1; |
| 172 | StringBuilder nameBuilder = new StringBuilder(argument ? "a" : "v"); | 180 | StringBuilder nameBuilder = new StringBuilder(getTypeName(desc)); |
| 181 | if (!uniqueType || NameValidator.isReserved(nameBuilder.toString())) { | ||
| 182 | nameBuilder.append(nameIndex); | ||
| 183 | } | ||
| 184 | translatedName = nameBuilder.toString(); | ||
| 185 | return translatedName; | ||
| 186 | } | ||
| 187 | |||
| 188 | private String inferLocalVariableName(int index, TypeDescriptor desc) { | ||
| 189 | int nameIndex = index + 1; | ||
| 190 | return getTypeName(desc) + nameIndex; | ||
| 191 | } | ||
| 192 | |||
| 193 | private String getTypeName(TypeDescriptor desc) { | ||
| 173 | // Unfortunately each of these have different name getters, so they have different code paths | 194 | // Unfortunately each of these have different name getters, so they have different code paths |
| 174 | if (desc.isPrimitive()) { | 195 | if (desc.isPrimitive()) { |
| 175 | TypeDescriptor.Primitive argCls = desc.getPrimitive(); | 196 | TypeDescriptor.Primitive argCls = desc.getPrimitive(); |
| 176 | nameBuilder.append(argCls.name()); | 197 | return argCls.name().toLowerCase(Locale.ROOT); |
| 177 | } else if (desc.isArray()) { | 198 | } else if (desc.isArray()) { |
| 178 | // List types would require this whole block again, so just go with aListx | 199 | // List types would require this whole block again, so just go with aListx |
| 179 | nameBuilder.append("Arr"); | 200 | return "arr"; |
| 180 | } else if (desc.isType()) { | 201 | } else if (desc.isType()) { |
| 181 | String typeName = desc.getTypeEntry().getSimpleName().replace("$", ""); | 202 | String typeName = desc.getTypeEntry().getSimpleName().replace("$", ""); |
| 182 | typeName = typeName.substring(0, 1).toUpperCase(Locale.ROOT) + typeName.substring(1); | 203 | typeName = typeName.substring(0, 1).toLowerCase(Locale.ROOT) + typeName.substring(1); |
| 183 | nameBuilder.append(typeName); | 204 | return typeName; |
| 184 | } else { | 205 | } else { |
| 185 | System.err.println("Encountered invalid argument type descriptor " + desc.toString()); | 206 | System.err.println("Encountered invalid argument type descriptor " + desc.toString()); |
| 186 | nameBuilder.append("Unk"); | 207 | return "var"; |
| 187 | } | 208 | } |
| 188 | if (!argument || methodEntry.getDesc().getArgumentDescs().size() > 1) { | ||
| 189 | nameBuilder.append(nameIndex); | ||
| 190 | } | ||
| 191 | translatedName = nameBuilder.toString(); | ||
| 192 | return translatedName; | ||
| 193 | } | 209 | } |
| 194 | } | 210 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/NameValidator.java b/src/main/java/cuchaz/enigma/mapping/NameValidator.java index 9273c9bc..fca8cfcb 100644 --- a/src/main/java/cuchaz/enigma/mapping/NameValidator.java +++ b/src/main/java/cuchaz/enigma/mapping/NameValidator.java | |||
| @@ -66,4 +66,8 @@ public class NameValidator { | |||
| 66 | public static String validateArgumentName(String name) { | 66 | public static String validateArgumentName(String name) { |
| 67 | return validateFieldName(name); | 67 | return validateFieldName(name); |
| 68 | } | 68 | } |
| 69 | |||
| 70 | public static boolean isReserved(String name) { | ||
| 71 | return ReservedWords.contains(name); | ||
| 72 | } | ||
| 69 | } | 73 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java b/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java index 3c8cc746..6e58aa0f 100644 --- a/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java +++ b/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java | |||
| @@ -223,14 +223,14 @@ public class TypeDescriptor { | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | public enum Primitive { | 225 | public enum Primitive { |
| 226 | Byte('B'), | 226 | BYTE('B'), |
| 227 | Character('C'), | 227 | CHARACTER('C'), |
| 228 | Short('S'), | 228 | SHORT('S'), |
| 229 | Integer('I'), | 229 | INTEGER('I'), |
| 230 | Long('J'), | 230 | LONG('J'), |
| 231 | Float('F'), | 231 | FLOAT('F'), |
| 232 | Double('D'), | 232 | DOUBLE('D'), |
| 233 | Boolean('Z'); | 233 | BOOLEAN('Z'); |
| 234 | 234 | ||
| 235 | private static final Map<Character, Primitive> lookup; | 235 | private static final Map<Character, Primitive> lookup; |
| 236 | 236 | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/entry/MethodDefEntry.java b/src/main/java/cuchaz/enigma/mapping/entry/MethodDefEntry.java index 960b08d1..fa9e6685 100644 --- a/src/main/java/cuchaz/enigma/mapping/entry/MethodDefEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/entry/MethodDefEntry.java | |||
| @@ -42,4 +42,20 @@ public class MethodDefEntry extends MethodEntry implements DefEntry { | |||
| 42 | public MethodDefEntry updateOwnership(ClassEntry classEntry) { | 42 | public MethodDefEntry updateOwnership(ClassEntry classEntry) { |
| 43 | return new MethodDefEntry(new ClassEntry(classEntry.getName()), name, descriptor, signature, access); | 43 | return new MethodDefEntry(new ClassEntry(classEntry.getName()), name, descriptor, signature, access); |
| 44 | } | 44 | } |
| 45 | |||
| 46 | public int getArgumentIndex(ClassDefEntry ownerEntry, int localVariableIndex) { | ||
| 47 | int argumentIndex = localVariableIndex; | ||
| 48 | |||
| 49 | // Enum constructors have an implicit "name" and "ordinal" parameter as well as "this" | ||
| 50 | if (ownerEntry.getAccess().isEnum() && getName().startsWith("<")) { | ||
| 51 | argumentIndex -= 2; | ||
| 52 | } | ||
| 53 | |||
| 54 | // If we're not static, "this" is bound to index 0 | ||
| 55 | if (!getAccess().isStatic()) { | ||
| 56 | argumentIndex -= 1; | ||
| 57 | } | ||
| 58 | |||
| 59 | return argumentIndex; | ||
| 60 | } | ||
| 45 | } | 61 | } |
diff --git a/src/test/java/cuchaz/enigma/TestTypeDescriptor.java b/src/test/java/cuchaz/enigma/TestTypeDescriptor.java index 90fd6351..8172848c 100644 --- a/src/test/java/cuchaz/enigma/TestTypeDescriptor.java +++ b/src/test/java/cuchaz/enigma/TestTypeDescriptor.java | |||
| @@ -51,13 +51,13 @@ public class TestTypeDescriptor { | |||
| 51 | 51 | ||
| 52 | @Test | 52 | @Test |
| 53 | public void getPrimitive() { | 53 | public void getPrimitive() { |
| 54 | assertThat(new TypeDescriptor("Z").getPrimitive(), is(TypeDescriptor.Primitive.Boolean)); | 54 | assertThat(new TypeDescriptor("Z").getPrimitive(), is(TypeDescriptor.Primitive.BOOLEAN)); |
| 55 | assertThat(new TypeDescriptor("B").getPrimitive(), is(TypeDescriptor.Primitive.Byte)); | 55 | assertThat(new TypeDescriptor("B").getPrimitive(), is(TypeDescriptor.Primitive.BYTE)); |
| 56 | assertThat(new TypeDescriptor("C").getPrimitive(), is(TypeDescriptor.Primitive.Character)); | 56 | assertThat(new TypeDescriptor("C").getPrimitive(), is(TypeDescriptor.Primitive.CHARACTER)); |
| 57 | assertThat(new TypeDescriptor("I").getPrimitive(), is(TypeDescriptor.Primitive.Integer)); | 57 | assertThat(new TypeDescriptor("I").getPrimitive(), is(TypeDescriptor.Primitive.INTEGER)); |
| 58 | assertThat(new TypeDescriptor("J").getPrimitive(), is(TypeDescriptor.Primitive.Long)); | 58 | assertThat(new TypeDescriptor("J").getPrimitive(), is(TypeDescriptor.Primitive.LONG)); |
| 59 | assertThat(new TypeDescriptor("F").getPrimitive(), is(TypeDescriptor.Primitive.Float)); | 59 | assertThat(new TypeDescriptor("F").getPrimitive(), is(TypeDescriptor.Primitive.FLOAT)); |
| 60 | assertThat(new TypeDescriptor("D").getPrimitive(), is(TypeDescriptor.Primitive.Double)); | 60 | assertThat(new TypeDescriptor("D").getPrimitive(), is(TypeDescriptor.Primitive.DOUBLE)); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | @Test | 63 | @Test |