ControlFlow in Intellij

Answered

I am trying to get all the Psi Elements in the order of execution till a specific element. I am using CodeFlowAnalyser#getInstructions() method. But Iam getting an empty list.


List<Instruction> obj = ControlFlowFactory.getInstance(getPsiElement().getProject()).getControlFlow(getPsiElement(),
AllVariablesControlFlowPolicy.getInstance()).getInstructions();


Am I right in implementing? Is there any other better way?
Thanks in Advance.

9 comments
Comment actions Permalink
Official comment

the ControlFlowFactory builds a graph of java statements which are directly beneath the psi element it was given. Mostly it is used for statements inside java code block. So the typical usage is:

 

ControlFlowFactory.getInstance(project).getControlFlow(psiMethod.getBody(),
AllVariablesControlFlowPolicy.getInstance())

 

(note the psiMethod.getBody() - it's the PsiCodeBlock with the PsiStatements directly beneath)

Also please note that it's an internal API which can change.

Comment actions Permalink

The actual case in the test program is :

class A{

m(){

Object o = new Object("something");

xyz();

method(o);   // I need to extract the attribute value of str here assuming setValue sets some attr. str of Object class.

//If xyz() is called after method() then i must get "something". and if it is called b4  i must get "otherthing"

}

 xyz(){

o = new Object("otherthing"); (or) o.setValue("otherthing");

}

}

 

And pls note that the object o need not belong to a single method and it's value can be changed by some other method also.

Thanks.

0
Comment actions Permalink

So you need to know all possible values of the variable at some point of execution. This is called data-flow analysis and we don't do this at that level, especially interprocedurally, sorry.

0
Comment actions Permalink

I donot need all possible values but the exact value of a variable or an attribute of a variable.

I kept on trying it using DfaVariableValue and other classes in intellij.psi.controlflow package, Any ideas?

It is ok even if it is able to determine if variable value is changed to new value from actual value before a statement. Here before means not in terms of code but in terms of control. And variable is not a primitive but an Object.

Hope I guess there is definitely some way to do it.

Thanks.

0
Comment actions Permalink

We have limited data-flow analysis for variables inside code block only. Variables assigned outside the current method cannot be analyzed currently, sorry. 

In case of variables inside code block, e.g 

Object foo(int param) {

  Object o;

  if (param == 0) {

    o = null;

  else {

    o = param;

  }

  return o;

}

 

we can analyze and determine that the "o" variable can contain values "null" or "param".

See com.intellij.codeInspection.dataFlow.DfaUtil#getCachedVariableValues()

(This API is extremely internal)

1
Comment actions Permalink

Thanks for your answer.

Can we have an alternate solution like this:

Can we able to determine all the instructions in the order of execution from beginning to the instruction where I need to determine the value of variable.

For example:(test application)

class A{

method1(){

Object o;

o=new Object("something");

xyz(o);

method2(o); // Assume I need to know the value of o here.

}

xyz(o){

o.setValue("otherthing"); (or) o = new Object("otherthing");

}

}

Now can we determine set of instructions like this:

1)Object o;

2)o=new Object("something");

3)xyz(o);

4)o.setValue("otherthing"); (or) o = new Object("otherthing");

5)method2(o);

 

Now If we can get the above List then I can determine by comparison or any other method whether o's value is changed after initialization. Important thing here is that the instructions must be in same order of execution. (which we have to determine using the plugin without running the test app).  There are various API's and Classes in (com.intellij.psi.controlflow) package but I need your help in determining the exact API which can perform the required task.

 

Thanks.

0
Comment actions Permalink

Again, there are no corresponding ready-to-use classes for that purpose in IDEA.

If you want to do that in your plugin yourself, you'll need to:

- build control flow for the corresponding method body (e.g. method1 in your example) (using e.g. ControlFlowFactory above)

- traverse the this control flow in reverse execution order to determine the most recent calls to o.setValue() or calls to methods with "o" as arguments (in your examples these are "method2(o)", "xyz(o)" and "o = new Object()") (like in com.intellij.psi.controlFlow.ControlFlowUtil#depthFirstSearch(com.intellij.psi.controlFlow.ControlFlow, com.intellij.psi.controlFlow.InstructionClientVisitor, int, int))

- repeat two steps above for each method (to get "o.setValue("otherthing")" from method xyz in your example)

- now you have a collection of sequences of "o.setValue(v1); o.setValue(v2);... " calls in reverse-execution order ("o.setValue("otherthing")" and "Object("something") " in your example)

- extract arguments from the latest setValue() call in each sentence and these could be your values you were looking for ("otherthing" in your example)

1
Comment actions Permalink

Is there any other class equivalent to InstructionClientVisitor because it is not public class and I cannot use it out of the package. There is a class called CompositeInstructionClientVisitor but it is not public either.

Thanks.

0
Comment actions Permalink

mmm, sorry, no. You  are asking about classes so internal they are inaccessible even to other IDEA parts ;), to protect them the imminent breakage.

0

Please sign in to leave a comment.