Can't reach informations needed in a for statement

Hi all,

I resume a project for develop some new rules, and one of them is to know if there is an invocation method in a for statement.

So i get the ForStatementTree objet and check the object in the condition(), update() and initializer() functions.
.
Condition() and update() functions return a ListTree, so for my needs, i check if possible the children of each StatementTree (maybe a mistake, but i’m starting this project).

My problem is that all subclass of interface StatementTree are not in the package org.sonar.plugins.java.api but org.sonar.java.model.statement, so when i execute my rules i have the same problem as this topic : Custom Rule Plugin - CompilationUnitTreeImpl ClassCastException - #3 by jmcnally2020

So do you know how can i get and navigate in the tree which is in a condition or update of a For statement ?

Thanks fo any help,

Nicolas

Hello @nicodavdavidson

First, a small reminder for Java custom rules:

  • CUSTOM RULES 101 is the go-to guide when starting to implement custom rules for Java, it is regularly updated.
  • Example project.
  • For rules implementation examples, you can directly look into the rules of the Java analyzer itself, it contains hundreds of examples (just make sure to use only what is provided in the public API).
    For example, NestedSwitchCheck could give you hints to implement your idea.

Then, to answer your question:
You should not use the implementation (ending with Impl) of the trees, but the interfaces available in the public API. (Ex: use MethodInvocationTree instead of MethodInvocationTreeImpl in your rule).

Hope it helps,
Quentin

1 Like

Thanks for your answer and documentation @Quentin,

I tried to use the interfaces, but the définition of the children() function is from the Abstract class JavaTree.

And i can’t use this class because like the other, it’s not a part of org.sonar.plugins.java.api package and the children() function is protected.

I thought for an another solution : get all invocationMethod instead of ForStatement, and check if the .parent() is a ForStatement (and check his parent if it’s not a ForStatement, etc…), but to me it’s seems significately less effective than get the children of a ForStatement.

Nicolas

and… it doesn’t work properly, because i can’t check if the invocationMethod is in the ForStatement or in the body of the ForStatement.

Ex : the following example is ok ( getMyValue() is in the condition of a ForStatement)

  public void test3() {
         for (int i = 0; i < getMyValue(); i++) {  // Noncompliant
             System.out.println(i);
             boolean b = getMyValue() > 6;
         }
     }

But the next case is detected as non compilant (cause a “parent” of println() is a ForStatement)

 public void test1() {
         for (int i = 0; i < 20; i++) {
             System.out.println(i);
             boolean b = getMyValue() > 6;
         }
     }

And the plugin must detect some tricky case like this one :

     public void test7() {
        for (int i = 0; i < 20 ; if (i < 5) {getMyValue()} else {incrementeMyValue(i)} ) { // Noncompliant
            System.out.println(i);
            boolean b = getMyValue() > 6;
        }
    }

So i can’t stop the search if the plugin reach a block/if statement.

To my knowledge, we never use children() in the rules. parent() is sometimes used, but you should try to avoid it when possible.

What about using the same idea as in NestedSwitchCheck?

  @Override
  public List<Tree.Kind> nodesToVisit() {
    return Collections.singletonList(Tree.Kind.FOR_STATEMENT);
  }

  @Override
  public void visitNode(Tree tree) {
    ForStatementTree forStatementTree = (ForStatementTree) tree;
    NestedSwitchVisitor visitor = new NestedSwitchVisitor();

    ExpressionTree condition = forStatementTree.condition();
    if (condition != null) {
      condition.accept(visitor);
    }
    forStatementTree.initializer().accept(visitor);
    forStatementTree.update().accept(visitor);
  }

  private class NestedSwitchVisitor extends BaseTreeVisitor {
    @Override
    public void visitMethodInvocation(MethodInvocationTree tree) {
      reportIssue(tree, "...");
    }
  }

Hello @Quentin,

It works, after a little understanding of this api.

Thanks for your help, and sorry for this newbie question.

Nicolas

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.