package ch.usi.inf.sp.callgraph.renderer; import org.objectweb.asm.Opcodes; import java.util.Map; public class InvokeEdge implements DotEdge { private final DotMethodNode from; private final DotMethodNode to; private final int invokeOpCode; private final boolean isDeclared; public InvokeEdge(DotMethodNode from, DotMethodNode to, int invokeOpCode, boolean isDeclared) { if (invokeOpCode != Opcodes.INVOKESTATIC && invokeOpCode != Opcodes.INVOKESPECIAL && invokeOpCode != Opcodes.INVOKEVIRTUAL && invokeOpCode != Opcodes.INVOKEINTERFACE) { throw new IllegalArgumentException("invokeOpCode must be a invoke instruction opcode"); } this.from = from; this.to = to; this.invokeOpCode = invokeOpCode; this.isDeclared = isDeclared; } private String getStyle() { switch (invokeOpCode) { case Opcodes.INVOKESTATIC: case Opcodes.INVOKESPECIAL: return "solid"; case Opcodes.INVOKEVIRTUAL: return "dashed"; case Opcodes.INVOKEINTERFACE: return "dotted"; default: throw new IllegalStateException("unreachable"); } } @Override public Map getProperties() { return Map.of( "style", getStyle(), "color", isDeclared ? "blue" : "red" ); } public DotMethodNode getFrom() { return from; } public DotMethodNode getTo() { return to; } @Override public String toString() { return "InvokeEdge{" + "from=" + from.getMethodLike().prettyName() + ", to=" + to.getMethodLike().prettyName() + ", invokeOpCode=" + invokeOpCode + ", isDeclared=" + isDeclared + '}'; } }