How to write a Java source checker

Each checker is associated with a XML description which contains the name, description, class name, etc. When Arana runs, it will read the XML description and dynamically load the checker. So let us start with the format of the XML description. We will use the checker that checks "empty catch block" as an example:

   <checker name="EmptyCatchBlock"
          message="Avoid empty catch blocks"
          class="edu.ksu.cis.projects.arana.checkers.basic.EmptyCatchBlock">
      <description>
  Empty Catch Block finds instances where an exception is caught,
  but nothing is done.  In most circumstances, this swallows an exception
  which should either be acted on or reported.
      </description>
        <priority>NORMAL_PRIORITY</priority>

      <example>
  ....
      </example>
    </checker> 
       
           
The name of the checker should be unique, in this example, it is EmptyCatchBlock. The message is the error message of the checker. The description and example nodes are only for documentation purpose. Priority should be LOW_PRIORITY, NORMAL_PRIORITY, or HIGH_PRIORITY.

After finishing the XML description, we proceed to write the checker. The checker should extend edu.ksu.cis.projects.arana.AbstractJavaSourceChecker and the checker class name (including package) should be the same as in the XML description. So for the "empty catch block" example, it starts with

      package edu.ksu.cis.projects.arana.checkers.basic;
      public class EmptyCatchBlock extends AbstractJavaSourceChecker 
    
The AbstractJavaSourceChecker is a JDT visitor class (extending from org.eclipse.jdt.core.dom.ASTVisitor). The visitor provides several visiting methods for each source AST node. The most important visiting method is "public boolean visit(Node)". The return value indicates whether to visit the subtrees of current node or not: returning true meaning the subtrees will be visited; returning false otherwise. You need to override appropriate visit methods to do the checking. For the "empty cath block" checker, it will only be interested in "TryStatement" AST node. So it only overwrites "visit(TryStatement)" method:
     public boolean visit(TryStatement node) {
        List<CatchClause> catches = (List<CatchClause>)node.catchClauses();
        for (CatchClause c : catches) {
            if (c.getBody().statements().isEmpty()) {
                ctx.getReport().addViolation(
                        createViolation(ctx, 
                                getLineno(c.getStartPosition()), getMessage()));
            }
        }
        return true;
    } 
    
When the checker needs to flag an error, it should call "ctx.getReport().addViolation" like the example above. The getLineno and getMessage methods are inherited from AbstractJavaSourceChecker.

References

  • The the JDT AST visitor: org.eclipse.jdt.core.dom.ASTVisitor in Eclipse JDT help
  • JDT AST nodes: org.eclipse.jdt.core.dom in Eclipse JDT help