There are three ways to extend coding rules:
To implement a new coding rule, we recommend to start with XPath at it is the most simple way. If it cannot be achieved with XPath rules (either because the language plugin does not support XPath yet or because the rule is highly complex and cannot be defined with an XPath expression), then write your own Sonar plugin.
Sonar provides a quick and easy way to add new coding rules directly via the web interface for certain languages (C/C++, C#, Cobol, Flex, JavaScript, PL/I, PL/SQL, Python and VB.NET).
The rules have to be written in XPath to navigate the Abstract Syntax Tree (AST). For each language, an SSLR Toolkit is provided to navigate the AST. This SSLR Toolkit is a standalone application that displays the AST for a provided piece of code source. So that you quickly get the nodes names and attributes to write your XPath expression from your code sample. The proper SSLR Toolkit can be downloaded from the language plugin page. So, finally, knowing the XPath language is the only prerequisite. A lot of tutorials on XPath can be found online (see http://www.w3schools.com/xpath/ for example).
Let's take the following JavaScript source code sample:
function HelloWorld(hour) {
if (hour) {
this.hour = hour;
} else {
var date = new Date();
this.hour = date.getHours();
}
this.displayGreeting = function() {
if (this.hour >= 22 || this.hour <= 5)
document.write("Good night, World!");
else
document.write("Hello, World!");
}
} |
While parsing the source code, Sonar builds an Abstract Syntax Tree (AST).
An SSLR Toolkit is provided by each language supporting XPath to get a representation of this AST. Here's the AST for our JavaScript sample:

The XPath language provides a way to write coding rules by navigating this AST.
To create a new rule:


Write your XPath rule (it should comply to XPath 1.0):
Here are two examples of JavaScript XPath rules:
Do not use document.write:
//callExpression/memberExpression[count(*) = 3 and primaryExpression[@tokenValue = "document"] and identifierName[@tokenValue = "write"]] |
Always use curly braces for if/else statements:
//ifStatement/statement[not(block)] |

The following languages can be extended with new rules:
A code analyzer plugin executes the following steps:
This step relates to the extension point org.sonar.api.rules.RuleRepository. A RuleRepository defines a set of coding rules. It usually loads data from a XML file:
public class CheckstyleRuleRepository extends RuleRepository {
// this sonar component is injected in constructor
private XMLRuleParser xmlRuleParser;
public CheckstyleRuleRepository(XMLRuleParser xmlRuleParser) {
super("checkstyle", Java.KEY);
setName("Checkstyle");
this.xmlRuleParser = xmlRuleParser;
}
@Override public List<Rule> createRules() {
// the InputStream is closed in xmlRuleParser
return xmlRuleParser.parse(getClass().getResourceAsStream("/org/sonar/plugins/checkstyle/rules.xml")));
}
}
|
The XML file is available in the plugin classloader and looks like :
<rules>
<!-- the format used before sonar 2.3 is still supported : attributes key and priority on the node <rule> -->
<rule>
<!-- unique key within this repository -->
<key>com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck</key>
<name>Header</name>
<!-- default priority when the rule is activated (optional, default value is MAJOR). Values are INFO, MINOR,
MAJOR, CRITICAL, BLOCKER -->
<priority>MAJOR</priority>
<!-- this key is used later by the sensor to configure the code analyzer -->
<configKey>Checker/Header</configKey>
<!-- available ISO categories : Reliability, Portability, Maintainability, Efficiency, Usability -->
<category name="Usability"/>
<!--
This node is optional: default value is SINGLE.
MULTIPLE: the rule can be activated many times with different parameters and priority.
SINGLE: the rule can be activated once
-->
<cardinality>SINGLE</cardinality>
<description><![CDATA[Checks that ...]]></description>
<param>
<key>header</key>
<description><![CDATA[the required header specified inline. Individual header lines must be separated by the string "\n" (even on platforms with a different line separator)]]></description>
</param>
<param>
<key>ignore</key>
<description>...</description>
<defaultValue>false</defaultValue>
</param>
</rule>
</rules>
|
This step relates to the extension point org.sonar.api.profiles.ProfileDefinition. Quality profiles provided by plugins are registered at server startup.
This step relates to the extension point org.sonar.api.batch.Sensor.