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 https://github.com/SonarSource/sonar-java.

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?