wojtus wojtus -4 years ago 52
Java Question

Proper way for getting annotations of Java-Methods in custom Sonar rules

I try to write a custom Sonar-rule (Java) and struggle with the proper way for getting annotation of invoked Java methods.
This rule should detect illegal access to methods and fields marked as

@VisibleForTesting
. Accesing such elements from production code is illegal, but access from the same class is legal.
My first approach is to implement
BaseTreeVisitor.visitMethodInvocation(MethodInvocationTree)
and use the metadata of the belonging symbol:


  • get annotations:
    methodInvocationSymbol.metadata().annotations()

  • analyse the names of the symbols of each
    AnnotationInstance
    (annotations class) and its owner (annotations package)



This works great as long other classes invoke the method. When the call is made inside the same class - the annotations name and package are set to
!unknownSymbol!
.

I also tried an alternative approach: to analyse the
IdentifierTree
of the
AnnotationTree
(inside of
BaseTreeVisitor.visitMethodInvocation(MethodInvocationTree))
, but I could not find the way how to get the package name of the annotation.

I use sonar-java-plugin 3.7.1 and sonar-plugin-api 5.1.

The code is commited in this mvn / Eclipse project.
The
UnexpectedAccessCheckTest
contains 2 use-cases. The "InvokedFromOtherClass" works well. The
InvokedFromSameClass
passes the test, but it happens only by accident - the annotation is not correctly detected.
It produces this output:

[main] DEBUG d.t.s.p.vft.checks.IsAnAnnotation - Checking Annotation.
Expected [com.google.common.annotations.VisibleForTesting]
got [.!unknownSymbol!]


The correct running use-case produces this:

[main] DEBUG d.t.s.p.vft.checks.IsAnAnnotation - Checking Annotation.
Expected [com.google.common.annotations.VisibleForTesting]
got [com.google.common.annotations.VisibleForTesting]


Do you have any hint for me?

Answer Source

The first way is prefered and should work for every method call, even within the same class.

If it does not work it probably means that the method invoked is not resolved from semantic (which is why the symbol is set to unknown, the analyzer has some bugs regarding method calls when generics are involved). In order to point you out to the correct ticket, an example would be required.

Regarding your comment about the syntax tree : the identifier in the syntax tree won't contain information about the package (as its name gives it away, it concerns only syntax ;) ). However, you can use the following to find the type of the annotation from the source :

annotationTree.annotationType().symbolType().is("com.mypackage.MyAnnotation")

Make sure that the expected binary is in the Classpath while runnnig the scan (see sonar.java.binaries property, or usage of maven-dependency-plugin if you use Maven).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download