Hammurapi Group
Java tools and libraries
Products
Hammurapi
Hammurapi rules
jIncarnate

Supporting libraries
Common library
Enterprise extensions
Mesopotamia

Contact us
Discussion board
Newsletter

Inspector developer guide

DescriptionThis document describes how to develop Hammurapi inspectors.
Id173
Last modifiedTue Jan 01 21:11:43 EST 2008
GUID8f220c47ff09b6fcfd8245b833d5a8b9a08c77c1
Glossary Hammurapi glossary

Prerequisites

 A code review solution, either the bundle or a custom assembly shall be installed in your environment. See Hammurapi 5 Quick Start Guide for installation instructions.

Set up

  • Create a project in your favorite Java IDE and add Mesopotamia, Hammurapi rules and Hammurapi jar files to the project build path.
  • Start code review solution's database and web application.

Identify the problem

Write down in a plain human language what is the problem. In our sample project we’ll implement an inspector “If you have to compare with a string do not use degree.equals("1")), but rather "1".equals(degree)”

Identify a language construct to be inspected

From the inspector description above we see that we need to inspect equals() method call.

Create code snippets for testing

  • Code snippet which violates the coding rule to be checked by the new inspector.
  • Code snippet compliant with the rule.

Multiple levels of parsing

There are multiple levels of parsing of sources. E.g. there are three levels in the Java language module. First of all, character stream from source file is converted into token stream by a lexer. Then tokens are composed into an Abstract Syntax Tree (AST) by a parser. The AST is homogeneous, i.e. all nodes are instances of the same class. As the last parsing step, AST is transformed into a heterogeneous graph of objects where each language construct is represented by a separate Java class. These classes form a hierarchy which follows target language’s grammar production rules.

It is possible to write inspectors working with tokens, AST or language elements. While inspectors can work on tokens, AST, or language elements, most inspectors work with language elements because heterogeneity of the language elements graph allows to use method parameter type matching to indicate which language construct a particular inspector is “interested in”.

Syntax tree and token stream can be obtained from SourceUnit class. Consult Mesopotamia and Mesopotamia Java language module JavaDoc or source code for more information.

Visualize the violation to identify language element class/interface to be inspected

A picture is worth a thousand words. SourceUnit and LanguageElement classes have show() method. This method displays object and its children as a tree. To take a look at parsed source code structure create inspect() method as shown below.

package mypackage;

import org.mesopotamia.MesopotamiaException;
import org.mesopotamia.SourceUnit;
import org.mesopotamia.lang.java.MethodCall;
import org.mesopotamia.lang.java.StringConstant;

import biz.hammurapi.review.Inspector;
import biz.hammurapi.review.Violation;

public class StringEqualsInspector extends Inspector {
   
    public void inspect(SourceUnit su) {
        su.show();
    }

}

 Then create a file called my-inspectors.xml with the following content.

<ruleset type="biz.hammurapi.config.ElementNameDomConfigurableContainer">
   
    <name>My inspectors</name>
    <description>Inspectors under development</description>
   
    <handle-manager type="biz.hammurapi.rules.KnowledgeMaximizingHandleManager"/>
   
    <collection-manager type="biz.hammurapi.rules.PojoCollectionManager">
        <collectionType>biz.hammurapi.rules.KnowledgeMaximizingSet</collectionType>
    </collection-manager>
   
    <rules type="biz.hammurapi.review.ReviewRulesContainer">
        <rule type="mypackage.StringEqualsInspector">
            <name>My new inspector</name>
            <description>Inspector under development</description>
            <severity>3</severity>
        </rule>       
    </rules>
</ruleset>

Configure the code review solution in your environment to include the new inspector class into classpath and to use my-inspectors.xml inspector set. When you run a review, a Swind window will open showing structure of the source unit. show() method blocks the invoking thread while browser window is open. Close the browser to resume program execution.

In our example, after studying source unit structure and JavaDoc we come to conclusion that we need to write inspect method for MethodCall class. Modified inspector code will look like

package mypackage;

import org.mesopotamia.MesopotamiaException;
import org.mesopotamia.SourceUnit;
import org.mesopotamia.lang.java.MethodCall;
import org.mesopotamia.lang.java.StringConstant;

import biz.hammurapi.review.Inspector;
import biz.hammurapi.review.Violation;

public class StringEqualsInspector extends Inspector {
   
    public void inspect(MethodCall methodCall) {
        methodCall.show();
    }

}

This version of our inspector will show the browser window for each MethodCall instance encountered in the code being reviewed.

Implement inspector logic

Now we'll implement inspector logic.

package mypackage;

import org.mesopotamia.MesopotamiaException;
import org.mesopotamia.SourceUnit;
import org.mesopotamia.lang.java.MethodCall;
import org.mesopotamia.lang.java.StringConstant;

import biz.hammurapi.review.Inspector;
import biz.hammurapi.review.Violation;

public class StringEqualsInspector extends Inspector {
   
    public void inspect(MethodCall methodCall) throws MesopotamiaException {
        if ("equals".equals(methodCall.getName())
                && methodCall.getArguments().size()==1
                && methodCall.getArguments().get(0) instanceof StringConstant) {
           
            post(new Violation(methodCall));
        }       
    }   
   
}

 

A single method inspect() takes MethodCall instance. Code review runtime parses source files, creates language element instances and then passes those instances to compatible inspect() methods. I.e. if we had inspect(LanguageElement le) method we’d get all language elements for inspection; inspect(Object obj) would get all language elements and source units for inspection. Here we are getting only instances of MethodCall.

inspect() methods can throw any exceptions. Exceptions thrown by inspector are intercepted by the code review runtime and output to the report as warnings.

This inspector assumes that developers don’t write code like “A”.equals(“B”) and as such there is no need to check if the method provider is a String constant. A check like this, comparison operator on two constants, would be a task for another inspector.

In our case the inspector is not parameterizable. Parameterization can be easily added by providing appropriate setter methods. See DomConfigFactory and Hammurapi Rules documentation for more details.

You can now add more test cases, implement nuances. E.g. in our case we should, ideally, check if method argument is a reference to static final field, or enumeration member, which are as constant as literals.

Package

The final step is packaging for distribution. The package shall include:

  • Compiled inspectors
  • Third-party libraries used by inspectors
  • Inspector set
  • Documentation

Notes

Intermediate results and inspectors collaboration

Inspectors can work as a team using forward chaining. E.g. one inspector can infer intermediate conclusions, which then can be posted to other inspectors to draw final conclusions in the form of violations.

Language elements and source units are Attributable and inspectors can communicate by setting attributes of objects being inspected.

Finally, all inspectors can be looked up through the naming bus. As such one inspector can look up another inspector if needed.

Inspector vs. Loader

It is important to differentiate where to put some particular logic. Logic which is specific to the model, e.g. class hierarchy, resolving of variable references shall be in loaders. Inspectors shall contain only inspection logic, though it might be some times necessary to build sub-models. E.g. inspectors which check correct implementation of a pattern with multiple participants shall build a pattern model by resolving participating classes. Then each of participants can be checked for compliance with the pattern contract.

 

 

 

Hammurapi Group