In the first article of this four-part series, we examined static analysis from a high level and introduced the common user interface for analysis available in IBM® Rational® Software Analyzer (also in IBM Rational Software Architect and IBM Rational Application Developer) and the process of creating an analysis configuration by selecting providers, categories and rules. We also discussed the results view that shows the outcome of the static analysis, as well as some of the basic reporting capabilities built into the software.
In this part and Part 3, you will learn how to write rules to extend the
current Java code review rule set. The Rational Software Analyzer analysis
framework (referred to in code as rsar) includes
several extension points and a complete API for adding new forms of analysis and
new rules. But more importantly for this purpose, it also supplies a fully
functional analysis provider to perform automated code reviews for Java™
source code. Together, this and the next article describe enough of the framework
to understand and write any rule that you need.
This article starts with a description of the components that make up a rule. Then we cover the category and rule extension points plus a very quick overview of the Java IDE. Finally, we walk through the complete process that you follow to create your own rules by implementing simple rules from the group.
As you may already know, the Eclipse platform supplies a complete parser for Java source code that is used internally for common functions, such as displaying the Java source outline view, finding dependencies, and syntax highlighting. Fortunately, Eclipse has also exposed this IDE for platform developers to use. JDT parses a Java source file and produces an in-memory tree structure representation that can be queried by other areas of the API (application programming interface). The topmost portion of the Abstract Syntax Tree (AST) tree for a Java file is structured roughly this way:
CompilationUnit:
[ PackageDeclaration ]
{ ImportDeclaration }
{ TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | ; }
|
The CompilationUnit is the root type, which,
conceptually, is the Java file itself and is a container for
TypeDeclarations (which are either classes or
interfaces). There are also MethodInvocations,
MethodDeclarations, and many more node types that you
will use regularly to write rules. A complete description of all nodes is
available in the Eclipse Help system. There are more than 100 Application Server
Toolkit (AST) node types in the documentation, but don't be intimidated,
because the Javadoc information is well-written and complete.
To perform queries on the AST parse tree, the Java IDE uses a visitor pattern. This offers great performance, but it can be somewhat intimidating to write a visitor class to get valid, useful results. The analysis API eliminates most of the challenges associated with visiting AST nodes by providing a common visitor class and abstracting the query mechanism. This API will be described throughout the remainder of this article. For now, all you need is a basic understanding of the AST tree structure, and the Eclipse Java IDE Help can provide that. Take some time to peruse this documentation, because you will eventually need to write AST code for some of your more advanced rules.
Java code review extension points
We won't go into a deep description here of all extension points available in the Analyzer analysis framework, because there are many. Instead we will focus on just few that you need to create new categories and rules. We will cover others, such as the provider and result extension points, in the next article of this series.
The Code Review for Java provider is available in Rational Software Analyzer, Rational Software Architect, and Rational Application Developer, and any rule that you write will be deployable to any of those tools. If you open the analysis configuration dialog and expand this provider, you will see that it has several categories. Each of these is contributed with an extension in a plugin.xml file, such as the one that you will find in the com.ibm.rsaz.analysis.codereview.java.rules plug-in in Analyzer. For example, consider this arbitrary category from the plugin.xml source file:
<analysisCategory class="com.ibm.rsaz.analysis.core.category.DefaultAnalysisCategory" id="codereview.java.category.awt" label="%label.category.j2sebestpractices.awt" category="codereview.java.j2sebestpractices" help="com.ibm.rsaz.analysis.codereview.java.rules.awt"/> |
The class attribute defines a class that manages the
category. Even though a custom category class can be written, this code uses the
default category supplied by the API, which will be effective in most cases.
Custom categories must handle common characteristics of a category, such as
managing a list of contained children, label, icon name, and so forth. This is
beyond the scope of this article so, for now, just accept that the default
category can provide all of the services required for any category. In almost all
situations, you will use the supplied class for a category.
A category also has a unique ID, which is used by other categories and rules to determine containment. Naturally, a category must also have a label and a description, which are shown to the user when this category is displayed.
In this example, the extension also has a category
attribute that indicates that this category is nested within another category with
a unique ID of codereview.java.j2sebestpractives. If
you want to create a top-level category, replace the
category attribute with a
provider=provider.id, as in this example, where
codereview.java.analysisProvider is the unique
identifier of the Java code review provider:
<analysisCategory class="com.ibm.rsaz.analysis.core.category.DefaultAnalysisCategory" id="codereview.java.j2sebestpractices" label="%label.category.j2sebestpractices" provider="codereview.java.analysisProvider" help="com.ibm.rsaz.analysis.codereview.java.rules.j2sebestpractices" </analysisCategory> |
Rule extensions work in a similar way but include a few more details. This is a sample extension for a rule:
<analysisRule category="codereview.java.category.awt" class="com.ibm.rsaz.analysis.codereview.java.internal.rules.awt.RuleAwtPeer" id="codereview.java.rules.awt.RuleAwtPeer" label="%label.relrule.j2sebestpractices.awt.awtpeer" severity="2" help="com.ibm.rsaz.analysis.codereview.java.rules.awtpeer"> </analysisRule> |
You should recognize the first part of the rule extension, because it is almost
identical to the category extension previously shown. In this case, the
class attribute contains a fully qualified class path
for the rule.
The rule also contains additional information. The Help tag supplies an ID for a help context in a related help.xml file. This allows a rule to provide nicely formatted example and solution information to the user. We will discuss Help and other advanced rule concepts in the next article. (See the link at the top to other articles in this series.)
As we discussed in the previous section, the first half of a rule definition is
an Eclipse extension. The second half is a Java class that uses the rule API or
parts of JDT, or both, to query the content of a class and produce results for any
issues that match the rule criteria. The rule class is quite simple, typically
containing only a single method. Given that rules usually extend a default rule
class provided by the Rational Software Analyzer analysis framework, most of the
necessary functionality is already implemented. The code in Listing 1 is a
complete rule that creates results for any line of code that uses the Java
"==" operator to compare two objects:
Listing 1. Rule for comparing two objects
public class RuleComparisonReferenceEquality
extends AbstractAnalysisRule
{
private static final String[] OPERATORS = { "==", "!=" };
private static final int[] OPERANDS = { ASTModifier.TYPE_PRIMITIVE,
ASTModifier.TYPE_NULLTYPE };
// Rule filters
private static IRuleFilter[] EXPFILTERS = {
new OperatorRuleFilter( OPERATORS, true ),
new LeftOperandRuleFilter( OPERANDS, false ),
new RightOperandRuleFilter( OPERANDS, false )
};
/**
* Analyze this rule
*
* @param history A reference to the history record for this analysis
*
* @throws CoreException
*/
public void analyze(final AnalysisHistory history,
final CodeReviewResource resource )
{
List list = resource.getTypedNodeList( resource.getResourceCompUnit(),
ASTNode.INFIX_EXPRESSION );
ASTHelper.satisfy( list, EXPFILTERS );
for(Iterator it=list.iterator(); it.hasNext(); ) {
InfixExpression tempInf = (InfixExpression)it.next();
ITypeBinding leftBinding = tempInf.getLeftOperand().resolveTypeBinding();
ITypeBinding rightBinding = tempInf.getRightOperand().resolveTypeBinding();
if( (leftBinding != null && leftBinding.isPrimitive()) ||
(rightBinding != null && rightBinding.isPrimitive()) ) {
it.remove();
}
}
resource.generateResultsForASTNodes( this, history.getHistoryId(), list );
}
}
|
The rule class extends com.ibm.rsaz.analysis.codereview.java.AbstractCodeReviewRule from the analysis framework, and, because this class is abstract, the derived rule must implement the ##analyze() method. This method takes one parameter (history), which points to the analysis session for which rules that are being executed. Every time that the user performs an analysis, a new history is registered to collect results. In addition to results, the history element also keeps track of which providers, categories, and rules were selected.
The parameters passed into the analyze() method contain information about the
scan history where any results will be stored and a reference to the resource
being analyzed. The AbstractCodeReviewRule class, which
is part of the Java code review provider, keeps track of the compilation unit for
the class file being analyzed and manages queries into the AST tree.
Because the rule in this example is concerned with
infix expressions (expressions with a left and right
side, such as a comparison), it uses the code review resource to get a list of
such expressions in the compilation unit:
List list = resource.getTypedNodeList( resource.getResourceCompUnit(), ASTNode.INFIX_EXPRESSION ); |
Next, the rule uses the ASTHelper.satisfy() method to
filter expressions from the list that do not meet a given criteria. Criteria are
defined in the static block at the top of the class:
// Rule filters
private static IRuleFilter[] EXPFILTERS = {
new OperatorRuleFilter( OPERATORS, true ),
new LeftOperandRuleFilter( OPERANDS, false ),
new RightOperandRuleFilter( OPERANDS, false )
};
|
The EXPFILTERS array contains three types of rule
filters. The first removes any expressions where the operator is neither
"==" nor
"!=". The second filter removes any
list items where the left side of the expression is a primitive type or a null.
The final filter repeats this for the right side of the expression. The satisfy()
method accepts the input list and the filter list and performs all filtering in
one step. After this line of code is executed the list will contain only
expressions where the left and right side are objects and the operator is either
"==" or
"!=". This is the only concern of
this rule; therefore, every item remaining in the list should be reported in the
result list. This is accomplished with the final line in the rule:
resource.generateResultsForASTNodes( this, history.getHistoryId(), list ); |
That was easy, wasn't it? The API for writing a Java rule contains just a few methods, but it is quite powerful.
Now that you have been lulled into the simplicity of code review rules, let's make it a bit more challenging. The rule that we previously examined is about as simple as a rule can get. It queries for only a single type of node in the AST tree and blindly reports all results remaining after filter. Let's consider all of the steps that are necessary to write a complete rule plug-in with a new category and rule.
To create a rule, you first need to create a plug-in:
- Use the Eclipse New Project wizard to create a new plug-in project in your workspace named #com.ibm.rsar.codereview.java.examples.
Figure 1. New Plug-in Project wizard
- On the second screen of the wizard (Figure 2), uncheck the check box that says "This plug-in makes contributions to the UI."
- Click the Finish button to create the plug-in.
Figure 2. Plug-in Content view
To successfully build rules, you need to add dependencies to the plug-in:
- Open the plug-in manifest files, and select the Dependencies tab.
- Add plug-ins by using the Add button to select org.eclipse.core.runtime plus these three plug-ins, as shown in Figure 3:
- com.ibm.rsaz.analysis.core, which contains the basic static analysis framework API and extension points
- com.ibm.rsaz.analysis.codereview.java, which contains the API for writing Java code review rules
- org.eclipse.jdt.core, which contains the JDT API including the AST parser and query framework
Figure 3. Add plug-ins
Typically, you need all three of these plug-in dependencies when creating new rules.
This first rule is practical. In this section, you will create a rule that
detects finalize() methods in Java code that do nothing
but call super.finalize(). If a
finalize() method calls only its parent, and then the
method can simply be removed. For example:
public class Example
{
private void method() {
// Do something
}
// Don't do this
protected void finalize() throws Throwable {
super.finalize();
}
}
|
So what do you need to do to detect this kind of problem? Let's examine these two steps:
- Step 1. You first need to build a list of method declarations with the source
code, specifically those named
finalize. Moreover, those method declarations should have no parameters.
- Step 2. After you have a list of method declarations that meet your criteria,
you need to look at the lines of code within them to see if they have just one
statement that is a
super.finalize()super method invocation.
You can build a rule by following these steps:
- First, create a new class in the com.ibm.rsar.codereview.java.examples
package of the examples plug-in. Call this class
RuleFinalizerSuper. - Make sure that this rule class extends com.ibm.rsaz.analysis.codereview.java.AbstractCodeReviewRule.
import com.ibm.rsaz.analysis.codereview.java.AbstractCodeReviewRule;
import com.ibm.rsaz.analysis.codereview.java.CodeReviewResource;
import com.ibm.rsaz.analysis.core.history.AnalysisHistory;
public class RuleFinalizerSuper extends AbstractCodeReviewRule
{
}
|
- You know that you will need an #analyze method, so add this code to the class:
/**
* Analyze this rule
*
* @param history A reference to the history record
*/
public void analyze(AnalysisHistory history, CodeReviewResource resource ) {
}
|
According to Step 1 of this algorithm, you need to collect a list of method declarations from the class that is being analyzed.
- Add the following to the
analyze()method to accomplish this:
List list = resource.getTypedNodeList( resource.getResourceCompUnit(), ASTNode.METHOD_DECLARATION ); |
This line visits the AST tree, starting at the compilation unit (the top-most
node), and queries for a list of all method declarations. Notice that the
getTypedNodeList() method has several signatures. This
one makes recursive calls by default; therefore, it will also find method
declarations in any inner classes.
To complete the requirements for Step 1 of the algorithm, you need to filter methods that you do not need out of the method declaration list. As in the first rule that we examined, you can create a list of rule filters to do this.
- Add the following lines to the top of the rule class:
// Rule filters
private static final IRuleFilter[] MIFILTERS = {
};
|
- First, you need to filter methods that are not declarations of
finalize(). In the empty static block add:
new MethodNameRuleFilter( "finalize", true ), |
The #MethodNameRuleFilter class tells the filtering mechanism that you are
interested in filtering by method names, specifically #finalize. The #true Boolean
indicates that finalize() methods should be retained in
the list. If this field were #false, then filtering would remove
finalize() methods and keep everything else.
You also need to ensure that you manage only true
finalize() methods. Given that it is possible for a
developer to create a finalize() method that returns a
value, you need your rule to ignore those.
- You can use the
ReturnTypeRuleFilterclass to add filtering to eliminatefinalize()methods that do not have avoidreturn type:
new ReturnTypeRuleFilter( "void", true ), |
To further help reduce the filtered list size, you need only finalize() methods that have no parameters. Methods with parameters are not class finalizers (in fact, a rule should be written to report these as invalid).
- Add the following line to the static block:
new ParameterCountRuleFilter( 0, true ) |
In this case, you tell the filter code to pay attention to the parameter count,
and it should be
0
.
The final filter array looks like Listing 2.
Listing 2. Final filter array
// Rule filters
private static final IRuleFilter[] MIFILTERS = {
new MethodNameRuleFilter( "finalize", true ),
new ReturnTypeRuleFilter( "void", true ),
new ParameterCountRuleFilter( 0, true )
};
|
The final step needed to complete Step 1 of the planned algorithm is to perform the actual filtering.
- At the end of the
analyze()method add this line:
ASTHelper.satisfy( list, MIFILTERS ); |
Make sure that there is only one line that is a super method invocation
The easy part of the rule is finished; now it gets a bit more complicated.
You need to examine the lines of code within the method and check to make sure that there is only one line. Remember that you have a list of method declarations. You need check each of them. There should be only one item in the list, because Java does not support more than one method declaration with the same signature.
- To be safe, create a list iterator by adding these lines to the end of the
analyze()method:
for( Iterator it = list.iterator(); it.hasNext(); ) {
MethodDeclaration md = (MethodDeclaration)it.next();
}
|
Every method declaration contains a body (the statements inside the braces). When
you have a method declaration, you can use the
getBody() method to get a
Block (this is an ASTNode). The body contains a list of
statements. Here, you care only about method declarations with a single statement.
- Add this code to the end of the iterator loop:
Block block = md.getBody();
if( md.getBody().statements().size() == 1 ) {
}
|
You're getting close. All that remains is to check the statement to see
if it is a call to super.finalize(). This
isn't as obvious is it might seem.
- Within the
ifstatement, add this code:
List superList =
resource.getTypedNodeList( block, ASTNode.SUPER_METHOD_INVOCATION );
if( superList.size() > 0 ) {
}
|
This needs some explanation. The body of a method declaration is made up of
statements, which can be any kind of action (for example: for statement, if
statement, or expression). You need to look in the body to see if there are any
super method invocations, which are a specific type of statement. You do this by
obtaining a list of ASTNodes within the block that have a
SUPER_METHOD_INVOCATION type. You already know that the
body has just one statement, so this list of super invocations will likely have 0
or 1 element. If the list has 1 (one) or more elements, then you can assume that
the body makes a call only to super.finalize().
The last step is to generate a result in the analysis results view. The code review engine provides a simple API for this.
- Within the empty
ifstatement, add this line:
resource.generateResultsForASTNode( this, history.getHistoryId(), md.getName() ); |
The first two parameters of this method call are always the same. They are used
to identify the rule that generates the result and the history collection where
the result will be placed. The third parameter indicates the ASTNode that will be
highlighted. In this case, for every matching method declaration (the
finalize() method), a result is created where the name
is highlighted.
The completed rule looks like Listing 3.
Listing 3. Completed rule
package com.ibm.rsar.codereview.java.examples;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import com.ibm.rsaz.analysis.codereview.java.AbstractCodeReviewRule;
import com.ibm.rsaz.analysis.codereview.java.CodeReviewResource;
import com.ibm.rsaz.analysis.codereview.java.IRuleFilter;
import com.ibm.rsaz.analysis.codereview.java.ast.ASTHelper;
import com.ibm.rsaz.analysis.codereview.java.rulefilter.MethodNameRuleFilter;
import com.ibm.rsaz.analysis.codereview.java.rulefilter.ParameterCountRuleFilter;
import com.ibm.rsaz.analysis.codereview.java.rulefilter.ReturnTypeRuleFilter;
import com.ibm.rsaz.analysis.core.history.AnalysisHistory;
public class RuleFinalizerSuper extends AbstractCodeReviewRule
{
// Rule filters
private static final IRuleFilter[] MIFILTERS = {
new MethodNameRuleFilter( "finalize", true ),
new ReturnTypeRuleFilter( "void", true ),
new ParameterCountRuleFilter( 0, true )
};
/**
* Analyze this rule
*
* @param history A reference to the history record for this analysis
*/
public void analyze
( final AnalysisHistory history, final CodeReviewResource resource ) {
List list =
resource.getTypedNodeList( resource.getResourceCompUnit(),
ASTNode.METHOD_DECLARATION );
ASTHelper.satisfy( list, MIFILTERS );
for( Iterator it = list.iterator(); it.hasNext(); ) {
MethodDeclaration md = (MethodDeclaration)it.next();
Block block = md.getBody();
if( md.getBody().statements().size() == 1 ) {
List superList =
resource.getTypedNodeList( block, ASTNode.SUPER_METHOD_INVOCATION );
if( superList.size() > 0 ) {
resource.generateResultsForASTNode( this, history.getHistoryId(), md.getName() );
}
}
}
}
}
|
After the rule class is completed, it needs to be described through the provided extension points in the analysis framework so that the code review engine can discover it. For this example, you will first create your own category, then you will associate the rule with that category.
Creating a new category is a relatively simple task:
- Open the example plug-in manifest created in the first part of this section.
- Select the Extensions tab in the editor, and click the Add button.
- From the list, select the com.ibm.rsaz.analysis.core.analysisCategory extension point, as shown in Figure 4.
Figure 4. Extension Point Selection view
- Under the Extension tab, you should now see a new extension point entry.
Right-click on it, and add a new
analysisCategory. Fill in these extension fields with the details shown (illustrated in Figure 5): - id*: analysis.codereview.java.examples
- label*: Examples
- category: codereview.java.j2sebestpractices
- class: com.ibm.rsaz.analysis.core.categoryDefaultAnalysisCategory (use the Browse button to select)
Figure 5. Extension Element Details view
This category has a parent category
(codereview.java.j2sebestpractices), which nests it
within the Java™ 2 Platform, Special Edition Best Practices category in
the user interface. The class, DefaultAnalysisCategory,
can be used to supply a predefined category that provides all of the functionality
required for most categories that you will ever create.
Populating these details results in the following text being inserted into the plugin.xml file:
<extension
point="com.ibm.rsaz.analysis.core.analysisCategory">
<analysisCategory
category="codereview.java.j2sebestpractices"
class="com.ibm.rsaz.analysis.core.category.DefaultAnalysisCategory"
id="analysis.codereview.java.examples"
label="Examples">
</analysisCategory>
</extension>
|
Next, you need to add your rule to the new category.
- Add a new extension to the plug-in as we did for the category. This time, select the com.ibm.rsaz.analysis.core.analysisRule extension point.
- In the Extensions tab, right-click on the rule extension and add a new
analysisRule. - Populate the rule details (shown in Figure 6):
- id*: codereview.java.example.finalSuper
- label*: Avoid finalize() methods that call only super
- category: analysis.codereview.java.examples
- class: com.ibm.rsar.codereview.java.examples.RuleFinalizerSuper (use Browse button to select)
- severity: 2 (use the drop-down menu to select)
Figure 6. Properties of analysisRule
- Enter a label and description (this will appear in the user interface when the user sees your rule).
Note:
These strings should be localized for any production rule,
but you can ignore this requirement for now.
The class field contains the qualified name of the rule class that you created earlier. The category field contains the identifier string for your Examples category. After the details are created, the plugin.xml file will contain the following text:
<extension
point="com.ibm.rsaz.analysis.core.analysisRule">
<analysisRule
category="com.ibm.rca.codereview.java.examples.RuleFinalizeSuper"
id="codereview.java.example.finalSuper"
label="Avoid finalize() methods that call only super"
severity="2">
</analysisRule>
</extension>
|
- From the Eclipse view, select the Run option, and create a new Eclipse Application.
- In the configuration panel, click the Run button. This invokes a new runtime workbench to test your rule.
- When the workbench appears, import some Java source code into it so that
there is some code to review. Try to find some code with a
finalize()method that calls onlysuper.finalize()so that you can test the rule - With source code in the workbench, select the Analysis option from the Eclipse Run menu.
- In the dialog that appears, create a new analysis configuration and go to the Domains tab.
- Expand the Java Code Review branch of the tree until the Example subcategory is visible (see Figure 7).
Figure 7. Java Code Review expanded to show Example
- With the new rule selected, click Analyze to start the code review process.
If the source code in the workbench has code with a finalize() method that fits
your rule, the analysis results view will contain a result like the one that
Figure 8 shows.
Figure 8. Analysis results view
In this section, we have examined certain rules and, more specifically, how they use Rule Filters. The API supplies rule filters to support most of the rules that you would ever want to write. This is a list of the rule filters provided by Rational Software Analyzer (the Javadoc for the Analysis API has more information on how to use each of these rule filters:
- ArgumentTypeRuleFilter
- ConstructorRuleFilter
- DeclaringClassRuleFilter
- EnclosingNodeRuleFilter
- ExceptionCountRuleFilter
- ExpressionRuleFilter
- ForInitializerCountRuleFilter
- ForUpdateCountRuleFilter
- FragmentCountRuleFilter
- IfElseStatementCountRuleFilter
- IfElseStatementRuleFilter
- IfThenStatementCountRuleFilter
- IfThenStatementRuleFilter
- ImplementedInterfaceRuleFilter
- LeftOperandRuleFilter
- MethodNameRuleFilter
- ModifierRuleFilter
- OperatorRuleFilter
- ParameterCountRuleFilter
- ParameterTypeRuleFilter
- ReturnTypeRuleFilter
- RightOperandRuleFilter
- SuperClassRuleFilter
- TypeRuleFilter
There are also two rule filters for logical operations
(LogicalOrFilter and
LogicalAndFilter). You can use these to avoid
duplication in rules that must compare a similar array of filters that differ in a
particular way. For example:
private static final IRuleFilter[] MIFILTERS = {
new MethodNameRuleFilter( "testMethod", true ),
new ReturnTypeRuleFilter( "void", true ),
new LogicalOrFilter(
new ParameterCountRuleFilter( 0, true ),
new ParameterCountRuleFilter( 1, true )
};
|
This code filters methods named testMethod() that
return void and contain 0 or
1 as parameters.
It is possible that the rule filter you need is not available, but you can write your own rule filters without much effort. The API provides an interface (IRuleFilter) the you can implement to plug into the filter system. Listing 4 is an example of one of the rule filters supplied with the Java code review provider in Rational Software Analyzer:
Listing 4. Example of a rule filter included in Rational Software Analyzer
public class SuperClassRuleFilter extends AbstractRuleFilter {
private static final String SATISFIES_SUPER_CLASS = "satisfiesSuperClass";
private String superclassName;
/**
* Constructor
*
* @param superclassName
* The super class name by which to filter
* @param inclusive
* True if filtering will include only nodes that match the
* filter criteria, false to exclude matching nodes
*/
public SuperClassRuleFilter( String superclassName, boolean inclusive ) {
super( inclusive );
this.superclassName = superclassName;
}
/**
* Determine if the node is satisfied by the specified filter rule
*
* @param node The ASTNode to test
* @return true if the node satisifes the filtering rule
*/
public boolean satisfies( ASTNode node ) {
try {
if (node.getNodeType() == ASTNode.TYPE_DECLARATION) {
// Get the super class type. It is null if this type
// declaration does not extend any type
Type superClassType =
((TypeDeclaration)node).getSuperclassType();
if( superClassType != null ) {
return superClassType.resolveBinding().getQualifiedName()
.equals( superclassName );
}
} else {
Log.severe (Messages.bind(Messages.RULE_FILTER_ERROR_,
new Object[]{ SATISFIES_SUPER_CLASS,
node.getClass().getName()}));
}
} catch (NullPointerException e) {
// Do nothing
}
return false;
}
}
|
As you can see, the code is straightforward:
- You need to create a constructor to accept the values that you need to make
the node evaluation. In the example shown here, the constructor accepts a string
that represent the superclass name.
Tip:
Always accept the Boolean parameter to support inclusionary and exclusionary filtering.
- You must also implement the
satisfy()method, which, in all cases, will accept the AST node under test.
- Finally, because rule filters must be reliable, you need to ensure that all
exceptions are caught within
satisfy(). In the example here, the code catchesNullPointerExceptionin case binding resolution in the code fails.
When your rule filter is created, you can use it like any of the predefined
filters by placing it in an IRuleFilter array and calling
ASTHelper.satisfy() within you rules.
Figure 9. Rules tab showing rule sets
This tutorial explained the inner workings of the analysis API as it applies to writing new code review rules for Java. It discussed the core concepts of creating categories and rule specification in the plugin.xml file, and then described how to write a class to create a basic rule. The next article covers the concepts of rule severity, custom rule parameters, and creating rule templates.
Learn
- Read part 1 of this series, Getting started, for an introduction to static analysis with Rational Software Analyzer".
- Part 3 of this series offers suggestions on Enhancing rules for Java code review.
- Part 4 of this series discusses techniques for Integrating your own analysis tools.
- Visit the Rational Software Analyzer area on developerWorks for introductory to in-depth information.
- Visit the
Rational software area on developerWorks
for technical resources and best practices for Rational Software Delivery Platform
products.
- Explore
Rational computer-based, Web-based, and instructor-led online courses.
Hone your skills and learn more about Rational tools with these courses, which
range from introductory to advanced. The courses on this catalog are available for
purchase through computer-based training or Web-based training. Additionally, some
"Getting Started" courses are available free of charge.
- Subscribe to the
Rational Edge newsletter
for articles on the concepts behind effective software development.
- Subscribe to the
IBM developerWorks newsletter,
a weekly update on the best of developerWorks tutorials, articles, downloads,
community activities, webcasts and events.
- Browse the
technology bookstore
for books on these and other technical topics.
Get products and technologies
- Download
trial versions of IBM Rational software.
- Download these
IBM product evaluation versions
and get your hands on application development tools and middleware products from
DB2®, Lotus®, Tivoli®, and WebSphere®.
Discuss
- Get involved in the developerWorks Static Analysis discussion forum: A place for users of Rational Software Analyzer.
- Check out
developerWorks blogs and
get involved in the
developerWorks community.

Steve Gutz is a development manager responsible for IBM Rational’s code analysis tools. In addition architecting and managing IBM’s commercial products Steve is also a past contributor on the Eclipse Test and Performance Tools project (TPTP), focusing on improvements in implementation and integration of basic code review tools. Previous to joining the IBM Ottawa Lab in 2002, he held senior management and executive positions in several public and private companies including two of his own successful start-ups. He is also the author of two books and many articles, and is a regular conference speaker.
Comments (Undergoing maintenance)





