diff --git a/src/main/java/reincarnation/JavaMethodDecompiler.java b/src/main/java/reincarnation/JavaMethodDecompiler.java index 83d10831..da9840a5 100644 --- a/src/main/java/reincarnation/JavaMethodDecompiler.java +++ b/src/main/java/reincarnation/JavaMethodDecompiler.java @@ -10,9 +10,9 @@ package reincarnation; import static org.objectweb.asm.Opcodes.*; -import static reincarnation.Node.Termination; +import static reincarnation.Node.*; import static reincarnation.OperandCondition.*; -import static reincarnation.OperandUtil.load; +import static reincarnation.OperandUtil.*; import java.lang.reflect.Executable; import java.lang.reflect.Method; diff --git a/src/main/java/reincarnation/OperandCast.java b/src/main/java/reincarnation/OperandCast.java index fa64b92c..2769e1af 100644 --- a/src/main/java/reincarnation/OperandCast.java +++ b/src/main/java/reincarnation/OperandCast.java @@ -21,6 +21,8 @@ class OperandCast extends Operand { /** The type to cast. */ private final Class type; + private final boolean needCast; + /** * Create cast code. * @@ -31,8 +33,11 @@ class OperandCast extends Operand { this.value = value; this.type = type; fix(type); + this.needCast = !Inference.instanceOf(value.type.v, type); - encolose(); + if (needCast) { + encolose(); + } } /** @@ -40,10 +45,10 @@ class OperandCast extends Operand { */ @Override protected void writeCode(Coder coder) { - if (Inference.instanceOf(value.type.v, type)) { - value.writeCode(coder); - } else { + if (needCast) { coder.writeCast(type, value); + } else { + value.writeCode(coder); } } diff --git a/src/main/java/reincarnation/OperandMethodReference.java b/src/main/java/reincarnation/OperandMethodReference.java index 0a890eb8..396deffd 100644 --- a/src/main/java/reincarnation/OperandMethodReference.java +++ b/src/main/java/reincarnation/OperandMethodReference.java @@ -10,8 +10,6 @@ package reincarnation; import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Arrays; import reincarnation.coder.Coder; @@ -23,14 +21,12 @@ class OperandMethodReference extends Operand { /** The context. */ private final Operand context; - OperandMethodReference(Class interfaceClass, Method reference, Operand context, Type type) { - this.reference = reference; - this.context = context; - - System.out.println(Arrays.toString(reference.getGenericParameterTypes())); - fix(type); - } - + /** + * Create the operand for method reference. + * + * @param reference + * @param context + */ OperandMethodReference(Method reference, Operand context) { this.reference = reference; this.context = context; diff --git a/src/main/java/reincarnation/SpecializedType.java b/src/main/java/reincarnation/SpecializedType.java index 7bf4d563..4fcb226f 100644 --- a/src/main/java/reincarnation/SpecializedType.java +++ b/src/main/java/reincarnation/SpecializedType.java @@ -11,6 +11,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; @@ -18,22 +19,31 @@ import java.util.Objects; import kiss.I; +import reincarnation.coder.Join; -public final class SpecializedType implements Type { +public final class SpecializedType implements ParameterizedType { /** The reusable type for . */ private static final WildcardType WILD = new WildcardType() { - private static final Type[] O = {Object.class}; + private static final Type[] Φ = {}; @Override public Type[] getUpperBounds() { - return O; + return Φ; } @Override public Type[] getLowerBounds() { - return O; + return Φ; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "?"; } }; @@ -282,22 +292,40 @@ SpecializedType fillBy(Type type) { } /** - * Returns an array of Type objects representing the actual type arguments to this type. Note - * that in some cases, the returned array be empty. This can occur if this type represents a - * non-parameterized type nested within a parameterized type. - * - * @return An array of Type objects representing the actual type arguments to this type. + * {@inheritDoc} + */ + @Override + public Type getOwnerType() { + return null; + } + + /** + * {@inheritDoc} */ + @Override public Type[] getActualTypeArguments() { return specialized; } /** - * Returns the Type object representing the class or interface that declared this type. - * - * @return Type object representing the class or interface that declared this type + * {@inheritDoc} */ + @Override public Type getRawType() { return raw; } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return raw.getSimpleName() + Join.of(specialized) + .ignoreEmpty() + .prefix("<") + .separator(", ") + .suffix(">") + .converter(Type::getTypeName) + .write(); + } } \ No newline at end of file diff --git a/src/main/java/reincarnation/coder/Join.java b/src/main/java/reincarnation/coder/Join.java index cd0850d7..6e79281a 100644 --- a/src/main/java/reincarnation/coder/Join.java +++ b/src/main/java/reincarnation/coder/Join.java @@ -199,6 +199,17 @@ public Join remove(Collection values) { return this; } + /** + * Write out as {@link String}. + * + * @return + */ + public String write() { + StringBuilder builder = new StringBuilder(); + write(builder); + return builder.toString(); + } + /** * {@inheritDoc} */ @@ -207,6 +218,12 @@ public void write(Coder coder) { write(coder, I.NoOP); } + /** + * Write out or process if no item. + * + * @param coder + * @param empty + */ public void write(Coder coder, Runnable empty) { List values = take == null ? this.values : I.signal(this.values).index(0).take(x -> take.test(x.ⅱ, x.ⅰ)).map(Ⅱ::ⅰ).toList(); int size = values.size(); diff --git a/src/main/java/reincarnation/coder/java/JavaCoder.java b/src/main/java/reincarnation/coder/java/JavaCoder.java index 3656db23..efbef791 100644 --- a/src/main/java/reincarnation/coder/java/JavaCoder.java +++ b/src/main/java/reincarnation/coder/java/JavaCoder.java @@ -549,7 +549,7 @@ public void writeLocalVariable(Type type, String name) { if (vars.isDeclared(name)) { prefix = ""; } else { - boolean needInfer = (type instanceof Class clazz && clazz.getTypeParameters().length != 0) || type instanceof ParameterizedType; + boolean needInfer = (type instanceof Class clazz && clazz.getTypeParameters().length != 0); prefix = (needInfer ? "var" : name(type)).concat(space); vars.declare(name); } @@ -976,6 +976,16 @@ private void qualify(Type type, StringBuilder builder) { .take(x -> x != Object.class) .ignoreEmpty() .write(builder); + } else if (type instanceof SpecializedType specialized) { + qualify(specialized.getRawType(), builder); + + Join.of(specialized.getActualTypeArguments()) + .ignoreEmpty() + .prefix("<") + .separator("," + space) + .suffix(">") + .converter(this::name) + .write(builder); } else if (type instanceof ParameterizedType parameterized) { qualify(parameterized.getRawType(), builder); @@ -1010,16 +1020,6 @@ private void qualify(Type type, StringBuilder builder) { }); } else if (type instanceof GenericArrayType array) { throw new Error("Generic array"); - } else if (type instanceof SpecializedType specialized) { - qualify(specialized.getRawType(), builder); - - Join.of(specialized.getActualTypeArguments()) - .ignoreEmpty() - .prefix("<") - .separator("," + space) - .suffix(">") - .converter(this::name) - .write(builder); } else { throw new Error(String.valueOf(type)); } diff --git a/src/test/java/reincarnation/decompiler/lambda/MethodReferenceTest.java b/src/test/java/reincarnation/decompiler/lambda/MethodReferenceTest.java index eb61f4a4..79a103dc 100644 --- a/src/test/java/reincarnation/decompiler/lambda/MethodReferenceTest.java +++ b/src/test/java/reincarnation/decompiler/lambda/MethodReferenceTest.java @@ -23,8 +23,10 @@ import org.junit.jupiter.api.Test; import reincarnation.CodeVerifier; +import reincarnation.Debuggable; import reincarnation.TestCode; +@Debuggable() class MethodReferenceTest extends CodeVerifier { @Test