java-callgraph

Changes

pom.xml 6(+3 -3)

src/main/java/gr/gousiosg/callgraph/ClassPrinter.java 47(+0 -47)

Details

pom.xml 6(+3 -3)

diff --git a/pom.xml b/pom.xml
index 561b57e..03c8154 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,9 +23,9 @@
   		<scope>compile</scope>
   	</dependency>
   	<dependency>
-  		<groupId>asm</groupId>
-  		<artifactId>asm-all</artifactId>
-  		<version>3.3</version>
+  		<groupId>org.apache.bcel</groupId>
+  		<artifactId>bcel</artifactId>
+  		<version>5.2</version>
   		<type>jar</type>
   		<scope>compile</scope>
   	</dependency>
diff --git a/src/main/java/gr/gousiosg/callgraph/ClassVisitor.java b/src/main/java/gr/gousiosg/callgraph/ClassVisitor.java
new file mode 100644
index 0000000..347230a
--- /dev/null
+++ b/src/main/java/gr/gousiosg/callgraph/ClassVisitor.java
@@ -0,0 +1,34 @@
+package gr.gousiosg.callgraph;
+
+import org.apache.bcel.classfile.EmptyVisitor;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.MethodGen;
+
+public class ClassVisitor extends EmptyVisitor {
+
+    JavaClass visitedClass;
+    private ConstantPoolGen cp;
+
+    public ClassVisitor(JavaClass jc) {
+        visitedClass = jc;
+        cp = new ConstantPoolGen(visitedClass.getConstantPool());
+    }
+
+    public void visitJavaClass(JavaClass jc) {
+        Method[] methods = jc.getMethods();
+        for (int i = 0; i < methods.length; i++)
+            methods[i].accept(this);
+    }
+
+    public void visitMethod(Method method) {
+        MethodGen mg = new MethodGen(method, visitedClass.getClassName(), cp);
+        MethodVisitor visitor = new MethodVisitor(mg, visitedClass);
+        visitor.start(); 
+    }
+    
+    public void start() {
+        visitJavaClass(visitedClass);
+    }
+}
diff --git a/src/main/java/gr/gousiosg/callgraph/JCallGraph.java b/src/main/java/gr/gousiosg/callgraph/JCallGraph.java
index 1e22617..6ef87f5 100644
--- a/src/main/java/gr/gousiosg/callgraph/JCallGraph.java
+++ b/src/main/java/gr/gousiosg/callgraph/JCallGraph.java
@@ -3,7 +3,8 @@ package gr.gousiosg.callgraph;
 
 import java.io.IOException;
 
-import org.objectweb.asm.ClassReader;
+import org.apache.bcel.classfile.ClassParser;
+
 
 /**
  * Constructs a callgraph out of a JAR archive. Can combine multiple archives
@@ -15,12 +16,14 @@ import org.objectweb.asm.ClassReader;
 public class JCallGraph {
 
     public static void main(String[] args) {
+        ClassParser cp;
         try {
-            ClassPrinter cp = new ClassPrinter(); 
-            ClassReader cr = new ClassReader("java.lang.Thread"); 
-            cr.accept(cp, 0);
+            cp = new ClassParser("/Volumes/Files/Developer/java-callgraph/target/classes/gr/gousiosg/callgraph/ClassVisitor.class");
+            ClassVisitor visitor = new ClassVisitor(cp.parse());
+            visitor.start();
         } catch (IOException e) {
-            
+            // TODO Auto-generated catch block
+            e.printStackTrace();
         }
-    }
+    }   
 }
diff --git a/src/main/java/gr/gousiosg/callgraph/MethodVisitor.java b/src/main/java/gr/gousiosg/callgraph/MethodVisitor.java
new file mode 100644
index 0000000..1d55bf2
--- /dev/null
+++ b/src/main/java/gr/gousiosg/callgraph/MethodVisitor.java
@@ -0,0 +1,107 @@
+package gr.gousiosg.callgraph;
+
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.generic.ArrayInstruction;
+import org.apache.bcel.generic.CHECKCAST;
+import org.apache.bcel.generic.CodeExceptionGen;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.ConstantPushInstruction;
+import org.apache.bcel.generic.EmptyVisitor;
+import org.apache.bcel.generic.FieldInstruction;
+import org.apache.bcel.generic.INSTANCEOF;
+import org.apache.bcel.generic.Instruction;
+import org.apache.bcel.generic.InstructionConstants;
+import org.apache.bcel.generic.InstructionHandle;
+import org.apache.bcel.generic.InvokeInstruction;
+import org.apache.bcel.generic.LocalVariableInstruction;
+import org.apache.bcel.generic.MethodGen;
+import org.apache.bcel.generic.ReturnInstruction;
+import org.apache.bcel.generic.Type;
+
+public class MethodVisitor extends EmptyVisitor {
+
+    JavaClass visitedClass;
+    private MethodGen mg;
+    private ConstantPoolGen cp;
+
+    public MethodVisitor(MethodGen m, JavaClass jc) {
+        visitedClass = jc;
+        mg = m;
+        cp = mg.getConstantPool();
+    }
+
+    public void start() {
+        if (!mg.isAbstract() && !mg.isNative()) {
+            for (InstructionHandle ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) {
+                Instruction i = ih.getInstruction();
+
+                if (!visitInstruction(i))
+                    i.accept(this);
+            }
+            updateExceptionHandlers();
+        }
+    }
+
+    /** Visit a single instruction. */
+    private boolean visitInstruction(Instruction i) {
+        short opcode = i.getOpcode();
+
+        return ((InstructionConstants.INSTRUCTIONS[opcode] != null)
+                && !(i instanceof ConstantPushInstruction) && !(i instanceof ReturnInstruction));
+    }
+
+    /** Local variable use. */
+    public void visitLocalVariableInstruction(LocalVariableInstruction i) {
+        //if (i.getOpcode() != Constants.IINC)
+            //cv.registerCoupling(i.getType(cp));
+    }
+
+    /** Array use. */
+    public void visitArrayInstruction(ArrayInstruction i) {
+        //cv.registerCoupling(i.getType(cp));
+    }
+
+    /** Field access. */
+    public void visitFieldInstruction(FieldInstruction i) {
+        //cv.registerFieldAccess(i.getClassName(cp), i.getFieldName(cp));
+        //cv.registerCoupling(i.getFieldType(cp));
+    }
+
+    /** Method invocation. */
+    public void visitInvokeInstruction(InvokeInstruction i) {
+        System.out.println(visitedClass.getClassName() + ":" + mg.getName() + "->" +  i.getReferenceType(cp) + ":"+ i.getMethodName(cp));
+        //Type[] argTypes = i.getArgumentTypes(cp);
+        //for (int j = 0; j < argTypes.length; j++)
+        //    cv.registerCoupling(argTypes[j]);
+        //cv.registerCoupling(i.getReturnType(cp));
+        /* Measuring decision: measure overloaded methods separately */
+        //cv.registerMethodInvocation(i.getClassName(cp), i.getMethodName(cp),
+        //        argTypes);
+    }
+
+    /** Visit an instanceof instruction. */
+    public void visitINSTANCEOF(INSTANCEOF i) {
+        
+    }
+
+    /** Visit checklast instruction. */
+    public void visitCHECKCAST(CHECKCAST i) {
+       
+    }
+
+    /** Visit return instruction. */
+    public void visitReturnInstruction(ReturnInstruction i) {
+    }
+
+    /** Visit the method's exception handlers. */
+    private void updateExceptionHandlers() {
+        CodeExceptionGen[] handlers = mg.getExceptionHandlers();
+
+        /* Measuring decision: couple exceptions */
+        for (int i = 0; i < handlers.length; i++) {
+            Type t = handlers[i].getCatchType();
+            //if (t != null)
+                //cv.registerCoupling(t);
+        }
+    }
+}