Search code examples
javarascal

Extracting class dependencies from Eclipse project using Rascal


I am using Rascal to analyze an Eclipse Java project and identify the class dependencies in this project. To be more precise: class A depends on class B if and only if class A has a method which (1) uses a parameter of type B or (2) uses a local variable of type B. Here, I am only interested in dependency relations A -> B, where A and B are both classes within my project and are both different classes. I already created an M3 model from my Eclipse project and was able to identify the required parameters (of type B), using the following:

{ <e.name, f> | e <- model@declarations, e.name.scheme == "java+parameter", f <- model@typeDependency[e.name], !(/java/ := f.path), f.scheme != "java+primitiveType" }

Here, I obtain all declarations of my M3 model, filter on parameters and using the @typeDependency annotation I retrieve the corresponding type (I didn't know how to manipulate the information I obtained when using @types instead). Finally, I use the last two statements to filter out all parameters of which the type is not related to a class in my project, like String and Integer parameters. As I am quite new to Rascal, I could not think of another way to achieve this.

My question now is: how can I retrieve the local variables of type B for my project? Using the scheme "java+variable" is not sufficient in combination with @typeDependency, as this also includes variables of type Iterator or String that have a dependency with other classes within my project and I am not interested in these types of variables. Moreover, the resulting set contains variables like

B b = field.method(); 

where field is a global variable within that class. Because of this, a type dependency is present from b to the class itself and I would like to exclude these from my result as well. So, I believe that @typeDependency does not give me the information that I need.

I found this related post that seems to deal with local variables with Rascal, but it uses AST instead of M3. I am not sure how to use AST in this setting (like I said, I'm just a beginner in Rascal) and was wondering if it could be done with M3. How should I proceed?

Edit: in order to clearify what I want to achieve exactly, I will give a small example. Say that my project has two classes, A and B, and B contains some methods (methodB1, methodB2, ...). Moreover, class A has the following structure:

class A {

   void methodA1(){
        B importantVar;
        importantVar.methodB1();
        ...
        String someVar1 = importantVar.methodB2();
        int someVar2 = importantVar.methodB3();
   }

   void methodA2(){
        A someVar3;
        ...
   }

}

The variable that I would like to be able to retrieve is importantVar, because it is a local variable and it is of a type B (a class within my project). I am not interested in someVar1 and in someVar2, because they are local variables that have a type that is not related to my project. In the code example that I gave earlier for the parameters, I filtered these types out with the last two statements. Moreover, I am also not interested in someVar3, because it has type A and occurs within this same class.

I think that I should be able to retrieve the local variables that I want using @types, but I am not sure how. When using @types, I get a TypeSymbol and I already looked into the definition of this data type to see how I could manipulate it. Most of the data types within TypeSymbol have a location named decl, of which I know how to manipulate it. The problem is however, that I also receive some types that do not have this location, like \int() and \array(..) for instance. In these cases, the location decl is undefined.


Solution

  • If you only want to analyse a specific TypeSymbol, use pattern matching. Here is an example.

    TypeSymbol t;
    if (class(l,_) := t) {
      println(l);
    }
    

    or in a comprehension

    { l | <_,class(l,_)> <- m3@types};
    

    or as part of a lookup in a comprehension:

    { <v, l> | <_,v> <- m3@containment, isVariable(v), class(l,_) <- m3@types[v]};