1

I am trying to extract method calls for a project that I am parsing using the tool spoon developed by INRIA, I already have a methods mysql table where I stored all the methods (methodid, methodname, classid, classname ). I am using the following code to extract the methodcalls within my project:

    SpoonAPI spoon = new Launcher();
    spoon.addInputResource("C:\\Users\\mouna\\Downloads\\chess and gantt code\\workspace_codeBase\\Chess\\src");
    spoon.getEnvironment().setAutoImports(true);
    spoon.getEnvironment().setNoClasspath(true);
    CtModel model = spoon.buildModel();
    //List<String> classnames= new ArrayList<String>(); 

    // Interact with model
    Factory factory = spoon.getFactory();
    ClassFactory classFactory = factory.Class();
    MethodFactory methodFactory = factory.Method(); 
List<methodcalls> methodcallsList = new ArrayList<methodcalls>(); 
    for(CtType<?> clazz : classFactory.getAll()) {

    for(CtMethod<?> method :clazz.getMethods()) {

        String methname=method.getSimpleName(); 
        System.out.println("CALLER METHOD=====>"+methname);
         List<CtInvocation> methodcalls = method.getElements(new TypeFilter<>(CtInvocation.class)); 
        for( CtInvocation calledmethod: methodcalls) {

            //CALLEE EXECUTABLE 
            String CALLEENAME= calledmethod.getExecutable().getSignature().toString(); 
            String methodCallee=calledmethod.getExecutable().toString();
            if(calledmethod.getTarget()!=null) {
        //CALLEE TARGET  
                String CALLEENAMETARGET= calledmethod.getTarget().toString(); 
                System.out.println("TARGET: "+ CALLEENAMETARGET);
            }
        //CALLEE METHOD INFORMATION  
            ResultSet callingmethodsrefined2 = st.executeQuery("SELECT methods.* from methods where methods.methodname='"+CALLEENAME+"' "); 
            while(callingmethodsrefined2.next()) {
                String CALLEECLASSNAME = callingmethodsrefined2.getString("classname"); 
                String CALLEECLASSID = callingmethodsrefined2.getString("classid"); 
                String CALLEEID = callingmethodsrefined2.getString("id"); 
                System.out.println("CALLEE CLASS NAME: "+ CALLEECLASSNAME);
            }



            //CALLER METHOD INFORMATION     
            String CALLERCLASSNAME=clazz.getQualifiedName() ; 
            String CallerMethod= method.getSignature(); 
            ResultSet callingmethodsrefined = st.executeQuery("SELECT methods.* from methods where methods.methodname='"+CallerMethod+"'and methods.classname='"+CALLERCLASSNAME+"'"); 
            if(callingmethodsrefined.next()) {
                String CallerMethodID = callingmethodsrefined.getString("id"); 
                String CALLERCLASSNAME = callingmethodsrefined.getString("classname"); 
                String CALLERCLASSID = callingmethodsrefined.getString("classid"); 
                System.out.println("CALLEE METHOD ID: "+ CALLEEID);
            }




            String fullcaller= CALLERCLASSNAME+"."+CallerMethod; 
            String fullcallee= CALLEECLASSNAME+"."+CALLEENAME; 
            methodcalls methodcall= new methodcalls(CALLEEID, fullcaller, CALLEECLASSNAME, CallerMethodID, fullcallee, CALLERCLASSNAME); 

            if( methodcall.contains(methodcallsList, methodcall)==false && CallerMethodID!=null && CALLEEID!=null) {
                String statement = "INSERT INTO `methodcalls`(`callermethodid`,  `callername`,  `callerclass`, `callerclassid`,`fullcaller`,`calleemethodid`,  `calleename`, `calleeclass`,  `calleeclassid`,  `fullcallee`) VALUES ('"+CallerMethodID +"','" +CallerMethod+"','" +CALLERCLASSNAME+"','" +CALLERCLASSID+"','" +fullcaller+"','" +CALLEEID+"','" +CALLEENAME+"','" +CALLEECLASSNAME+"','" +CALLEECLASSID+"','" +fullcallee+"')";

                st.executeUpdate(statement);
                methodcallsList.add(methodcall); 
            }


        }
    }
}

The problem is that I am not able to retrieve the class to which the callee belongs, I am only able to retrieve the method signature, this is a problem since the same method like for example isWhite() can be found in multiple classes so I will end up with multiple results when I query my database "methods" table only based on the method name. I have tried using this to retrieve the class to which the callee belongs to String methodCallee=calledmethod.getExecutable().getClass().getSimpleName(); but that returned: "CtExecutableReferenceImpl".

Another problem that I have is that I am relying on calledmethod.getExecutable() to extract the method callees. However, calledmethod.getTarget() can contain in itself some callees, I printed the content of calledmethod.getTarget() and I got TARGET: getLastPly().getDestination() for one of the callers. In case the target is made of a succession of callees, is there a way to separate all of them? Also, I need to know the list of classes that each of these "target callees" belongs to, I am pretty new to Spoon so I don't really know which APIs to use

larasmith
  • 7
  • 5

1 Answers1

0

I have tried using this to retrieve the class to which the callee belongs to String methodCallee=calledmethod.getExecutable().getClass().getSimpleName(); but that returned: "CtExecutableReferenceImpl".

I think the method you are looking for is actually getDeclaringType(). This method is not available from the CtExecutable interface so you have to check that your executable is indeed an instance of CtMethod and after casting it you can use getDeclaringType. See: http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/declaration/CtTypeMember.html#getDeclaringType--

I'm not sure to understand your second problem: could you provide an example it would be helpful there.

Simon Urli
  • 449
  • 1
  • 5
  • 12