Question

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.

Was it helpful?

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]}; 

OTHER TIPS

You could use the containment relation from the M3 model. All local variables are declared in the declarations relation, but they also appear in containment. If you want to get all the variables in a method m, you can have a look at containment[m] and filter on the java+variable scheme.

Interesting corner cases are when a method contains an anonymous class. You have to look at bit further in containment (like a transitive closure) if you need to filter nested variables used in anonymous nested classes as well.

By the way, the M3 model has utility predicates isVariable, isClass, etc. and also classes(M3), etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top