Hi,
I am writing a custom sonar rule to check if all non-primitive members are initialized. The implementation extends AbstractTreeVisitor, it fetches all non-primitive and non-constant member variables from a class, then check if they are initialized in constructors.
I found that in some cases when the constructors are nested, sonar fails to get the correct declaration of constructor which leads to false issue report or infinite loop of calling visitMethod, visitBlock, visitExpressionStatement and visitMethodInvocation.
I use the following to get the declared constructor MethodTree:
@Override
public void visitMethodInvocation(MethodInvocationTree tree) {
if (tree.methodSymbol().declaration() != null) {
scan(tree.methodSymbol().declaration()); // declaration() will be a MethodTree representing the invoked constructor/method
}
}
For the following example test class, when visiting MethodInvocationTree this(toMap(a));
, tree.symbol().declaration()
returns constructor Test28(String ss)
instead of Test28(Map<Integer, String> m)
.
public class Test28 {
private String s;
public Test28() {
this(1);
}
public Test28(String ss) { // Noncompliant
//Does not init s
}
public Test28(int a) {
this(toMap(a));
}
private Test28(Map<Integer, String> m) {
this.s = "does not matter";
}
private Map<Integer, String> toMap(int a) {
Map<Integer, String> map = null;
return map;
}
}
Currently I find a way to work around, but I think it would be nice to directly use tree.methodSymbol().declaration()
to find the correct declaration. Could you help check if it is a bug of sonar api or if there is any other ways for me to get the correct corresponding constructor in nested calls?
BR,
Qi