package com.googlecode.totallylazy.reflection;
import com.googlecode.totallylazy.functions.Lazy;
import com.googlecode.totallylazy.predicates.Predicate;
import com.googlecode.totallylazy.Sequence;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
import jdk.internal.org.objectweb.asm.tree.ClassNode;
import jdk.internal.org.objectweb.asm.tree.LineNumberNode;
import jdk.internal.org.objectweb.asm.tree.MethodNode;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import static com.googlecode.totallylazy.functions.Lazy.lazy;
import static com.googlecode.totallylazy.predicates.Predicates.instanceOf;
import static com.googlecode.totallylazy.predicates.Predicates.not;
import static com.googlecode.totallylazy.Sequences.sequence;
public class StackFrame {
private final StackTraceElement trace;
private final Lazy<Class<?>> aClass;
private final Lazy<ClassNode> classNode;
private final Lazy<MethodNode> methodNode;
private final Lazy<Sequence<AbstractInsnNode>> instructions;
private final Lazy<Method> method;
private final Lazy<Constructor<?>> constructor;
public StackFrame(StackTraceElement trace) {
this.trace = trace;
Predicate<AbstractInsnNode> lineNumber = instanceOf(LineNumberNode.class, line -> line.line == trace.getLineNumber());
aClass = lazy(() -> Class.forName(trace.getClassName()));
classNode = lazy(() -> Asm.classNode(aClass.value()));
methodNode = lazy(() -> Asm.methods(classNode.value()).
filter(m -> m.name.equals(trace.getMethodName())).
filter(m -> Asm.instructions(m).exists(lineNumber)).
head());
instructions = lazy(() -> Asm.instructions(methodNode.value()).
dropWhile(not(lineNumber)).tail().
takeWhile(not(instanceOf(LineNumberNode.class))).
memoize());
method = lazy(() -> sequence(aClass.value().getDeclaredMethods()).
filter(m -> m.getName().equals(trace.getMethodName())).
filter(m -> sequence(Type.getArgumentTypes(m)).
equals(sequence(Type.getArgumentTypes(methodNode.value().desc)))).
head());
constructor = lazy(() -> sequence(aClass.value().getDeclaredConstructors()).
filter(c -> sequence(Asm.getArgumentTypes(c)).
equals(sequence(Type.getArgumentTypes(methodNode.value().desc)))).
head());
}
public StackTraceElement trace() {
return trace;
}
public Class<?> aClass() {
return aClass.value();
}
public ClassNode classNode() {
return classNode.value();
}
public MethodNode methodNode() {
return methodNode.value();
}
public Method method() {
return method.value();
}
public Constructor<?> constructor() {
return constructor.value();
}
public Sequence<AbstractInsnNode> instructions() {
return instructions.value();
}
@Override
public String toString() {
return trace().toString();
}
}