Reading trivias doesn't work as expected

Hi,

I want prevent empty lines at the beginning of methods, but methods where the first line is a comment are ok. I try to read all trivia during setContext of my rule. Following code works fine during JUnit debug in eclipse.

@Rule(key = "UnnecessaryEmptyLineRule", name = "At least one unnecessary empty line exists.",
      description = "A method shall not have an unnecessary empty line at the beginning or end.", priority = Priority.MAJOR, tags = {"brain-overload"})
public class UnnecessaryEmptyLineRule extends IssuableSubscriptionVisitor {

    private Map<Integer, SyntaxTrivia> trivias = new HashMap<>();

    @Override
    public List<Tree.Kind> nodesToVisit() {
        // Register to the kind of nodes you want to be called upon visit.
        return Arrays.asList(Tree.Kind.CONSTRUCTOR, Tree.Kind.METHOD);
    }

    @Override
    public void setContext(JavaFileScannerContext context) {
        findTrivia(context.getTree());
        super.setContext(context);
    }

    private void findTrivia(Tree tree) {
        JavaTree javaTree = (JavaTree) tree;

        if (javaTree.kind() == Tree.Kind.TOKEN) {
            trivias.putAll(((SyntaxToken) tree).trivias().stream().collect(Collectors.toMap(SyntaxTrivia::startLine, t -> t)));
        }

        if (!javaTree.isLeaf()) {
            javaTree.getChildren().forEach(this::findTrivia);
        }
    }

    @Override
    public void visitNode(Tree tree) {
        MethodTree methodTree = (MethodTree) tree;

        SyntaxToken firstLine = methodTree.closeParenToken();
        if (methodTree.throwsToken() != null) {
            firstLine = methodTree.throwsToken();
        }
        SyntaxToken lastLine = methodTree.lastToken();

        int lastCodeLine = 0;
        int firstCodeLine = 0;

        List<StatementTree> statements = methodTree.block().body();
        for (StatementTree statement : statements) {
            if (firstCodeLine > statement.firstToken().line() || firstCodeLine == 0) {
                firstCodeLine = statement.firstToken().line();
            }
            if (lastCodeLine < statement.lastToken().line()) {
                lastCodeLine = statement.lastToken().line();
            }
        }

        if (firstCodeLine - firstLine.line() > 1 && !trivias.containsKey(firstLine.line() + 1)) {
            reportIssue(firstLine, "unecessary empty line");
        }

        if (lastLine.line() - lastCodeLine > 1) {
            reportIssue(lastLine, "unecessary empty line");
        }
    }
}

When it’s executed via ‘mvn sonar:sonar’ on my project against a sonar server I get following error:

[INFO] Load project repositories (done) | time=44ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  12.046 s
[INFO] Finished at: 2020-12-18T14:10:57+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar (default-cli) on project custom-rules: Execution default-cli of goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar failed: A required class was missing while executing
org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar: org/sonar/java/model/JavaTree
[ERROR] -----------------------------------------------------
[ERROR] realm =    plugin>org.codehaus.mojo:sonar-maven-plugin:3.7.0.1746
[ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
[ERROR] urls[0] = file:/C:/Users/tre/.m2/repository/org/sonarsource/scanner/maven/sonar-maven-plugin/3.7.0.1746/sonar-maven-plugin-3.7.0.1746.jar
[ERROR] urls[1] = file:/C:/Users/tre/.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.4/plexus-sec-dispatcher-1.4.jar
[ERROR] urls[2] = file:/C:/Users/tre/.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar
[ERROR] urls[3] = file:/C:/Users/tre/.m2/repository/org/codehaus/plexus/plexus-utils/3.2.1/plexus-utils-3.2.1.jar
[ERROR] urls[4] = file:/C:/Users/tre/.m2/repository/org/sonarsource/scanner/api/sonar-scanner-api/2.14.0.2002/sonar-scanner-api-2.14.0.2002.jar
[ERROR] urls[5] = file:/C:/Users/tre/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
[ERROR] Number of foreign imports: 1
[ERROR] import: Entry[import  from realm ClassRealm[project>com.tre.plugins:custom-rules:1.0.3, parent: ClassRealm[maven.api, parent: null]]]
[ERROR]
[ERROR] -----------------------------------------------------
[ERROR] : org.sonar.java.model.JavaTree
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginContainerException

TestFile

class FooBar {

    int foo() { // Noncompliant

        return 1;

    } // Noncompliant

    void bar() {
        // some comment
        return 2;
    }
}

All other code is pretty much the same as from GitHub - SonarSource/sonar-java: SonarSource Static Analyzer for Java Code Quality and Security.

Any advice is appreciated.

Hi,

org.sonar.java.model.JavaTree is not part of the Java analyzer custom rule API. The classloader isolation between your plugin and sonar-java-plugin will not let you “see” the class.

Thanks for heaving a look into this.

Any other idea how I can identify comments during code analysis?