I am trying to create a custom java rule. In my project, I need every java file to start with a header. I choose to create a rule that signal the error if the file does not start with a comment. (the next step would be to check inside the comment to see if there are the required informations)
Helped by the internet, I wrote this code.
import java.util.List;
import java.util.Collections;
import org.sonar.check.Rule;
import org.sonar.check.Priority;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.tree.Tree;
@Rule(key = "IncludeHeader", description = "The file need a header",
priority = Priority.MINOR)
public class IncludeHeaderRule extends IssuableSubscriptionVisitor{
@Override
public List<Tree.Kind> nodesToVisit(){
return Collections.singletonList(Tree.Kind.ANNOTATION_TYPE);
}
@Override
public void visitNode(Tree tree) {
List<String> lines = context.getFileLines();
if (!(lines.get(0).contains("/*"))||(lines.get(0).contains("//"))) {
reportIssue(tree, "The file should start with a header.");
}
}
The code looks pretty easy. I create a list of strings where I include the lines. I check if there is a comment that starts with “//” or “/*” for the first item of the list that represent line 1(lines.get(0) and if there is no comment I report the issue.
However, when I try to check if the rule works I see that nothing happen. In one case it is normal but in the other one, somthing should happen.
I am using - sonarqube-10.0.0.68432
- java 17
- Apache Maven 3.9.1
Of course, I did insert the jar file in sonar/extensions/plugin then restarted SonarQube. I also created a quality profile and activated that rule.
If someone knows what is wrong with my code, knows what did I missed or has tips to give me, I will be more than thankfull
Thank you very much
Gab
Indeed it works if I write Kind.COMPILATION_UNIT instead of `Kind.ANNOTATION_TYPE’ but I am not sure to understand why. Can you explain in few words what is the difference between these two lines ?
Thanks you very much for your answer
Best regards
Gab
Adressing your question: with nodesToVisit() you state which parts of a files syntax tree you want to analyse. You could initially request the full tree, but usually a rule is interested only in specific patterns. For example, to check that a method matches a naming convention a rule does not inspect, say, package names.
With your Collections.singletonList(Tree.Kind.ANNOTATION_TYPE) you specify, that your rule is interested in definitions of new annotations, like
public @interface MyAnnotation {
// here come the params
}
If your file does not contain a annotation definition, as in the case of both of your files, your visitNode() isn’t called.
Using Kind.COMPILATION_UNIT you state that you are interested in basically in the full syntax tree of the file. This has the advantage that you report issues only once per file. If you would use anything else that is usually contained in a file, like Kind.CLASS, you might report missing comments multiple times if there are multiple classes defined in the file.