Reputation: 25
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.
Upvotes: 1
Views: 623
Reputation: 15439
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]};
Upvotes: 3
Reputation: 6696
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.
Upvotes: 1