Hammurapi Group |
Java tools and libraries |
|
Inspector developer guide
PrerequisitesA 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
Identify the problemWrite 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 inspectedFrom the inspector description above we see that we need to inspect equals() method call. Create code snippets for testing
Multiple levels of parsingThere 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 inspectedA 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 <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 In our example, after studying source unit structure and JavaDoc we come to conclusion that we need to write inspect method for 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 logicNow 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
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 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. PackageThe final step is packaging for distribution. The package shall include:
NotesIntermediate results and inspectors collaborationInspectors 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 Finally, all inspectors can be looked up through the naming bus. As such one inspector can look up another inspector if needed. Inspector vs. LoaderIt 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.
|