From 227ccb35a48529724ecf28c94a9156af2f699481 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Sat, 19 May 2018 20:00:12 +0200 Subject: More bytecode translation --- src/main/java/cuchaz/enigma/Deobfuscator.java | 6 +- .../translators/TranslationAnnotationVisitor.java | 13 +-- .../translators/TranslationClassVisitor.java | 26 ++--- .../translators/TranslationMethodVisitor.java | 81 ++++++++++++-- .../translators/TranslationSignatureVisitor.java | 122 +++++++++++++++++++++ .../enigma/mapping/DirectionalTranslator.java | 58 +++++++++- .../java/cuchaz/enigma/mapping/Translator.java | 48 ++++++-- 7 files changed, 304 insertions(+), 50 deletions(-) create mode 100644 src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java (limited to 'src') diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 3433ca9..cb03d45 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -532,15 +532,15 @@ public class Deobfuscator { ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); return classMapping != null && classMapping.getDeobfName() != null; } else if (obfEntry instanceof FieldEntry) { - return translator.getTranslatedField((FieldEntry) obfEntry) != null; + return translator.hasFieldMapping((FieldEntry) obfEntry); } else if (obfEntry instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry) obfEntry; if (methodEntry.isConstructor()) { return false; } - return translator.getTranslatedMethod(methodEntry) != null; + return translator.hasMethodMapping(methodEntry); } else if (obfEntry instanceof LocalVariableEntry) { - return translator.getTranslatedVariable((LocalVariableEntry) obfEntry) != null; + return translator.hasLocalVariableMapping((LocalVariableEntry) obfEntry); } else { throw new Error("Unknown entry desc: " + obfEntry.getClass().getName()); } diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java index 177691b..7cc3771 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java @@ -6,7 +6,6 @@ import cuchaz.enigma.mapping.TypeDescriptor; import cuchaz.enigma.mapping.entry.ClassEntry; import cuchaz.enigma.mapping.entry.FieldDefEntry; import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Type; public class TranslationAnnotationVisitor extends AnnotationVisitor { private final Translator translator; @@ -20,12 +19,12 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor { @Override public void visit(String name, Object value) { - if (value instanceof Type) { - Type type = (Type) value; - super.visit(name, translator.getTranslatedType(type)); - } else { - super.visit(name, value); - } + super.visit(name, translator.getTranslatedValue(value)); + } + + @Override + public AnnotationVisitor visitArray(String name) { + return this; } @Override diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java index dcc221e..89772db 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java @@ -19,11 +19,7 @@ import cuchaz.enigma.mapping.TypeDescriptor; import cuchaz.enigma.mapping.entry.*; import org.objectweb.asm.*; -import java.util.regex.Pattern; - public class TranslationClassVisitor extends ClassVisitor { - private static final Pattern OBJECT_PATTERN = Pattern.compile(".*:Ljava/lang/Object;:.*"); - private final Translator translator; private final JarIndex jarIndex; private final ReferencedEntryPool entryPool; @@ -39,9 +35,6 @@ public class TranslationClassVisitor extends ClassVisitor { @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - if (signature != null && OBJECT_PATTERN.matcher(signature).matches()) { - signature = signature.replaceAll(":Ljava/lang/Object;:", "::"); - } obfClassEntry = new ClassDefEntry(name, new AccessFlags(access)); ClassDefEntry entry = translator.getTranslatedClassDef(obfClassEntry); ClassEntry superEntry = translator.getTranslatedClass(entryPool.getClass(superName)); @@ -49,14 +42,16 @@ public class TranslationClassVisitor extends ClassVisitor { for (int i = 0; i < interfaces.length; i++) { translatedInterfaces[i] = translator.getTranslatedClass(entryPool.getClass(interfaces[i])).getName(); } - super.visit(version, entry.getAccess().getFlags(), entry.getName(), signature, superEntry.getName(), translatedInterfaces); + String translatedSignature = translator.getTranslatedSignature(signature, false, api); + super.visit(version, entry.getAccess().getFlags(), entry.getName(), translatedSignature, superEntry.getName(), translatedInterfaces); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { FieldDefEntry entry = new FieldDefEntry(obfClassEntry, name, new TypeDescriptor(desc), new AccessFlags(access)); FieldDefEntry translatedEntry = translator.getTranslatedFieldDef(entry); - FieldVisitor fv = super.visitField(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), signature, value); + String translatedSignature = translator.getTranslatedSignature(signature, true, api); + FieldVisitor fv = super.visitField(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedSignature, value); return new TranslationFieldVisitor(translator, translatedEntry, api, fv); } @@ -71,19 +66,18 @@ public class TranslationClassVisitor extends ClassVisitor { for (int i = 0; i < exceptions.length; i++) { translatedExceptions[i] = translator.getTranslatedClass(entryPool.getClass(exceptions[i])).getName(); } - MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), signature, translatedExceptions); + String translatedSignature = translator.getTranslatedSignature(signature, false, api); + MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedSignature, translatedExceptions); return new TranslationMethodVisitor(translator, translatedEntry, api, mv); } @Override public void visitOuterClass(String owner, String name, String desc) { - ClassEntry ownerEntry = translator.getTranslatedClass(entryPool.getClass(owner)); - String translatedDesc = desc != null ? translator.getTranslatedTypeDesc(new TypeDescriptor(desc)).toString() : desc; - if (name != null) { - ClassEntry entry = translator.getTranslatedClass(entryPool.getClass(name)); - super.visitOuterClass(ownerEntry.getName(), entry.getName(), translatedDesc); + if (desc != null) { + MethodEntry translatedEntry = translator.getTranslatedMethod(new MethodEntry(new ClassEntry(owner), name, new MethodDescriptor(desc))); + super.visitOuterClass(translatedEntry.getClassName(), translatedEntry.getName(), translatedEntry.getDesc().toString()); } else { - super.visitOuterClass(ownerEntry.getName(), name, translatedDesc); + super.visitOuterClass(owner, name, desc); } } diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java index c729962..cce91db 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java @@ -1,6 +1,8 @@ package cuchaz.enigma.bytecode.translators; -import cuchaz.enigma.mapping.*; +import cuchaz.enigma.mapping.MethodDescriptor; +import cuchaz.enigma.mapping.Translator; +import cuchaz.enigma.mapping.TypeDescriptor; import cuchaz.enigma.mapping.entry.*; import org.objectweb.asm.*; @@ -20,22 +22,35 @@ public class TranslationMethodVisitor extends MethodVisitor { public void visitFieldInsn(int opcode, String owner, String name, String desc) { FieldEntry entry = new FieldEntry(new ClassEntry(owner), name, new TypeDescriptor(desc)); FieldEntry translatedEntry = translator.getTranslatedField(entry); - if (translatedEntry != null) { - super.visitFieldInsn(opcode, translatedEntry.getClassName(), translatedEntry.getName(), translatedEntry.getDesc().toString()); - } else { - super.visitFieldInsn(opcode, owner, name, desc); - } + super.visitFieldInsn(opcode, translatedEntry.getClassName(), translatedEntry.getName(), translatedEntry.getDesc().toString()); } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { MethodEntry entry = new MethodEntry(new ClassEntry(owner), name, new MethodDescriptor(desc)); MethodEntry translatedEntry = translator.getTranslatedMethod(entry); - if (translatedEntry != null) { - super.visitMethodInsn(opcode, translatedEntry.getClassName(), translatedEntry.getName(), translatedEntry.getDesc().toString(), itf); - } else { - super.visitMethodInsn(opcode, owner, name, desc, itf); + super.visitMethodInsn(opcode, translatedEntry.getClassName(), translatedEntry.getName(), translatedEntry.getDesc().toString(), itf); + } + + @Override + public void visitFrame(int type, int localCount, Object[] locals, int stackCount, Object[] stack) { + Object[] translatedLocals = this.getTranslatedFrame(locals, localCount); + Object[] translatedStack = this.getTranslatedFrame(stack, stackCount); + super.visitFrame(type, localCount, translatedLocals, stackCount, translatedStack); + } + + private Object[] getTranslatedFrame(Object[] array, int count) { + if (array == null) { + return null; } + for (int i = 0; i < count; i++) { + Object object = array[i]; + if (object instanceof String) { + ClassEntry entry = new ClassEntry((String) object); + array[i] = translator.getTranslatedClass(entry).getName(); + } + } + return array; } @Override @@ -45,6 +60,13 @@ public class TranslationMethodVisitor extends MethodVisitor { return new TranslationAnnotationVisitor(translator, typeDesc.getTypeEntry(), api, av); } + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { + TypeDescriptor typeDesc = translator.getTranslatedTypeDesc(new TypeDescriptor(desc)); + AnnotationVisitor av = super.visitAnnotation(typeDesc.toString(), visible); + return new TranslationAnnotationVisitor(translator, typeDesc.getTypeEntry(), api, av); + } + @Override public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { TypeDescriptor typeDesc = translator.getTranslatedTypeDesc(new TypeDescriptor(desc)); @@ -80,6 +102,43 @@ public class TranslationMethodVisitor extends MethodVisitor { } translatedName = nameBuilder.toString(); } - super.visitLocalVariable(translatedName, translatedEntry.getDesc().toString(), signature, start, end, index); + String translatedSignature = translator.getTranslatedSignature(signature, true, api); + super.visitLocalVariable(translatedName, translatedEntry.getDesc().toString(), translatedSignature, start, end, index); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + ClassEntry translatedEntry = translator.getTranslatedClass(new ClassEntry(type)); + super.visitTypeInsn(opcode, translatedEntry.getName()); + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { + MethodDescriptor translatedMethodDesc = translator.getTranslatedMethodDesc(new MethodDescriptor(desc)); + Object[] translatedBsmArgs = new Object[bsmArgs.length]; + for (int i = 0; i < bsmArgs.length; i++) { + translatedBsmArgs[i] = translator.getTranslatedValue(bsmArgs[i]); + } + super.visitInvokeDynamicInsn(name, translatedMethodDesc.toString(), translator.getTranslatedHandle(bsm), translatedBsmArgs); + } + + @Override + public void visitLdcInsn(Object cst) { + super.visitLdcInsn(translator.getTranslatedValue(cst)); + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + super.visitMultiANewArrayInsn(translator.getTranslatedTypeDesc(new TypeDescriptor(desc)).toString(), dims); + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + if (type != null) { + ClassEntry translatedEntry = translator.getTranslatedClass(new ClassEntry(type)); + super.visitTryCatchBlock(start, end, handler, translatedEntry.getName()); + } else { + super.visitTryCatchBlock(start, end, handler, type); + } } } diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java new file mode 100644 index 0000000..e1dcea5 --- /dev/null +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java @@ -0,0 +1,122 @@ +package cuchaz.enigma.bytecode.translators; + +import cuchaz.enigma.mapping.Translator; +import cuchaz.enigma.mapping.entry.ClassEntry; +import org.objectweb.asm.signature.SignatureVisitor; + +import java.util.Stack; + +public class TranslationSignatureVisitor extends SignatureVisitor { + private final Translator translator; + + private final SignatureVisitor sv; + private final Stack classes = new Stack<>(); + + public TranslationSignatureVisitor(Translator translator, int api, SignatureVisitor sv) { + super(api); + this.translator = translator; + this.sv = sv; + } + + @Override + public void visitClassType(String name) { + ClassEntry entry = new ClassEntry(name); + ClassEntry translatedEntry = this.translator.getTranslatedClass(entry); + this.classes.push(entry); + this.sv.visitClassType(translatedEntry.getName()); + } + + @Override + public void visitInnerClassType(String name) { + ClassEntry outerEntry = this.classes.pop(); + ClassEntry entry = new ClassEntry(outerEntry + "$" + name); + this.classes.push(entry); + String translatedEntry = this.translator.getTranslatedClass(entry).getName(); + this.sv.visitInnerClassType(translatedEntry.substring(translatedEntry.lastIndexOf('$') + 1)); + } + + @Override + public void visitFormalTypeParameter(String name) { + this.sv.visitFormalTypeParameter(name); + } + + @Override + public void visitTypeVariable(String name) { + this.sv.visitTypeVariable(name); + } + + @Override + public SignatureVisitor visitArrayType() { + this.sv.visitArrayType(); + return this; + } + + @Override + public void visitBaseType(char descriptor) { + this.sv.visitBaseType(descriptor); + } + + @Override + public SignatureVisitor visitClassBound() { + this.sv.visitClassBound(); + return this; + } + + @Override + public SignatureVisitor visitExceptionType() { + this.sv.visitExceptionType(); + return this; + } + + @Override + public SignatureVisitor visitInterface() { + this.sv.visitInterface(); + return this; + } + + @Override + public SignatureVisitor visitInterfaceBound() { + this.sv.visitInterfaceBound(); + return this; + } + + @Override + public SignatureVisitor visitParameterType() { + this.sv.visitParameterType(); + return this; + } + + @Override + public SignatureVisitor visitReturnType() { + this.sv.visitReturnType(); + return this; + } + + @Override + public SignatureVisitor visitSuperclass() { + this.sv.visitSuperclass(); + return this; + } + + @Override + public void visitTypeArgument() { + this.sv.visitTypeArgument(); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + this.sv.visitTypeArgument(wildcard); + return this; + } + + @Override + public void visitEnd() { + this.sv.visitEnd(); + this.classes.pop(); + } + + @Override + public String toString() { + return this.sv.toString(); + } +} diff --git a/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java index 7af1a52..dec5acf 100644 --- a/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java +++ b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java @@ -15,13 +15,19 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.bytecode.AccessFlags; +import cuchaz.enigma.bytecode.translators.TranslationSignatureVisitor; import cuchaz.enigma.mapping.entry.*; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.signature.SignatureWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; public class DirectionalTranslator implements Translator { + private static final Pattern OBJECT_PATTERN = Pattern.compile(".*:Ljava/lang/Object;:.*"); private final TranslationDirection direction; private final Map classes; @@ -98,7 +104,7 @@ public class DirectionalTranslator implements Translator { public FieldDefEntry getTranslatedFieldDef(FieldDefEntry entry) { String translatedName = translateFieldName(entry); if (translatedName == null) { - return entry; + translatedName = entry.getName(); } ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry()); TypeDescriptor translatedDesc = getTranslatedTypeDesc(entry.getDesc()); @@ -110,7 +116,7 @@ public class DirectionalTranslator implements Translator { public FieldEntry getTranslatedField(FieldEntry entry) { String translatedName = translateFieldName(entry); if (translatedName == null) { - return null; + translatedName = entry.getName(); } ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry()); TypeDescriptor translatedDesc = getTranslatedTypeDesc(entry.getDesc()); @@ -138,7 +144,7 @@ public class DirectionalTranslator implements Translator { public MethodDefEntry getTranslatedMethodDef(MethodDefEntry entry) { String translatedName = translateMethodName(entry); if (translatedName == null) { - return entry; + translatedName = entry.getName(); } ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry()); MethodDescriptor translatedDesc = getTranslatedMethodDesc(entry.getDesc()); @@ -150,7 +156,7 @@ public class DirectionalTranslator implements Translator { public MethodEntry getTranslatedMethod(MethodEntry entry) { String translatedName = translateMethodName(entry); if (translatedName == null) { - return null; + translatedName = entry.getName(); } ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry()); MethodDescriptor translatedDesc = getTranslatedMethodDesc(entry.getDesc()); @@ -181,11 +187,11 @@ public class DirectionalTranslator implements Translator { translatedArgumentName = inheritLocalVariableName(entry); } if (translatedArgumentName == null) { - return null; + translatedArgumentName = entry.getName(); } // TODO: Translating arguments calls method translation.. Can we refactor the code in such a way that we don't need this? MethodEntry translatedOwner = getTranslatedMethod(entry.getOwnerEntry()); - return new LocalVariableEntry(translatedOwner != null ? translatedOwner : entry.getOwnerEntry(), entry.getIndex(), translatedArgumentName); + return new LocalVariableEntry(translatedOwner, entry.getIndex(), translatedArgumentName); } @Override @@ -200,6 +206,26 @@ public class DirectionalTranslator implements Translator { return new LocalVariableDefEntry(translatedOwner, entry.getIndex(), translatedArgumentName != null ? translatedArgumentName : entry.getName(), translatedTypeDesc); } + @Override + public boolean hasClassMapping(ClassEntry entry) { + return classes.containsKey(entry.getName()); + } + + @Override + public boolean hasFieldMapping(FieldEntry entry) { + return translateFieldName(entry) != null; + } + + @Override + public boolean hasMethodMapping(MethodEntry entry) { + return translateMethodName(entry) != null; + } + + @Override + public boolean hasLocalVariableMapping(LocalVariableEntry entry) { + return translateLocalVariableName(entry) != null || inheritLocalVariableName(entry) != null; + } + // TODO: support not identical behavior (specific to constructor) private String translateLocalVariableName(LocalVariableEntry entry) { // look for identical behavior in superclasses @@ -252,6 +278,26 @@ public class DirectionalTranslator implements Translator { return new MethodDescriptor(translatedArguments, getTranslatedTypeDesc(descriptor.getReturnDesc())); } + @Override + public String getTranslatedSignature(String signature, boolean isType, int api) { + if (signature == null) { + return null; + } + SignatureReader reader = new SignatureReader(signature); + SignatureWriter writer = new SignatureWriter(); + SignatureVisitor visitor = new TranslationSignatureVisitor(this, api, writer); + if (isType) { + reader.acceptType(visitor); + } else { + reader.accept(visitor); + } + String translatedSignature = writer.toString(); + if (OBJECT_PATTERN.matcher(signature).matches()) { + translatedSignature = signature.replaceAll(":Ljava/lang/Object;:", "::"); + } + return translatedSignature; + } + private ClassMapping findClassMapping(ClassEntry entry) { List mappingChain = getClassMappingChain(entry); return mappingChain.get(mappingChain.size() - 1); diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java index 6373da7..1bc2f37 100644 --- a/src/main/java/cuchaz/enigma/mapping/Translator.java +++ b/src/main/java/cuchaz/enigma/mapping/Translator.java @@ -12,6 +12,7 @@ package cuchaz.enigma.mapping; import cuchaz.enigma.mapping.entry.*; +import org.objectweb.asm.Handle; import org.objectweb.asm.Type; public interface Translator { @@ -31,20 +32,53 @@ public interface Translator { LocalVariableDefEntry getTranslatedVariableDef(LocalVariableDefEntry entry); + boolean hasClassMapping(ClassEntry entry); + + boolean hasFieldMapping(FieldEntry entry); + + boolean hasMethodMapping(MethodEntry entry); + + boolean hasLocalVariableMapping(LocalVariableEntry entry); + TypeDescriptor getTranslatedTypeDesc(TypeDescriptor desc); MethodDescriptor getTranslatedMethodDesc(MethodDescriptor descriptor); + String getTranslatedSignature(String signature, boolean isType, int api); + default Type getTranslatedType(Type type) { String descString = type.getDescriptor(); - // If this is a method - if (descString.contains("(")) { - MethodDescriptor descriptor = new MethodDescriptor(descString); - return Type.getMethodType(getTranslatedMethodDesc(descriptor).toString()); - } else { - TypeDescriptor descriptor = new TypeDescriptor(descString); - return Type.getType(getTranslatedTypeDesc(descriptor).toString()); + switch (type.getSort()) { + case Type.OBJECT: { + ClassEntry classEntry = new ClassEntry(type.getInternalName()); + return Type.getObjectType(getTranslatedClass(classEntry).getName()); + } + case Type.ARRAY: { + TypeDescriptor descriptor = new TypeDescriptor(descString); + return Type.getType(getTranslatedTypeDesc(descriptor).toString()); + } + case Type.METHOD: { + MethodDescriptor descriptor = new MethodDescriptor(descString); + return Type.getMethodType(getTranslatedMethodDesc(descriptor).toString()); + } + } + return type; + } + + default Handle getTranslatedHandle(Handle handle) { + MethodEntry entry = new MethodEntry(new ClassEntry(handle.getOwner()), handle.getName(), new MethodDescriptor(handle.getDesc())); + MethodEntry translatedMethod = getTranslatedMethod(entry); + ClassEntry ownerClass = translatedMethod.getOwnerClassEntry(); + return new Handle(handle.getTag(), ownerClass.getName(), translatedMethod.getName(), translatedMethod.getDesc().toString(), handle.isInterface()); + } + + default Object getTranslatedValue(Object value) { + if (value instanceof Type) { + return this.getTranslatedType((Type) value); + } else if (value instanceof Handle) { + return getTranslatedHandle((Handle) value); } + return value; } @SuppressWarnings("unchecked") -- cgit v1.2.3