Custom Java rule

Dear all

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.

image
image

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

Shouldn’t you be visiting something like Kind.COMPILATION_UNIT or at least Kind.CLASS? Kind.ANNOTATION_TYPE is likely an annotation definition:

public @Interface MyAnnotation {

}

Since your second test class is not an annotation it would not get visited.

Additionally, you can write unit tests for your rules, no need to deploy to a SonarQube instance.

Regards,
Oliver

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

@Gabzouzer Please have a look at the basic info on writing custom rules. You can find it here: sonar-java/docs/CUSTOM_RULES_101.md at master · SonarSource/sonar-java · GitHub

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.

Regards,
Oliver

Thank you very much. It helps me a lot.
Have a nice day
Best regards
Gab

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