CodeNarc - CodeNarc - Creating a Rule

##### General

- Home
- Downloads
- Javadocs
- Mailing Lists
- Bug Tracker
- SourceForge Project
- GitHub Project

##### Running

- Ant Task Usage
- Command-Line
- Run as a Test
- Other Tools/Frameworks

##### Using

- Creating a RuleSet
- Creating a Rule
- Configuring Rules
- Starter RuleSet (All)

##### Report Types

- HTML Report
- XML Report
- Text and IDE Reports

##### Sample Reports

- Sample HTML Report
- Sample XML Report

##### Rules

- Rule Index
- Basic Rules
- Braces Rules
- Concurrency Rules
- Convention Rules
- Design Rules
- DRY Rules
- Enhanced Rules
- Exceptions Rules
- Formatting Rules
- Generic Rules
- Grails Rules
- Groovyism Rules
- Imports Rules
- JDBC Rules
- JUnit Rules
- Logging Rules
- Naming Rules
- Size/Complexity Rules
- Security Rules
- Serialization Rules
- Unnecessary Rules
- Unused Rules

##### Developing

- Developer Guide

##### Project Documentation

- Project Information
- Project Reports

## CodeNarc - Creating a Rule

CodeNarc includes many predefined rules, but you can also create your own custom rules. See the site navigation menu for a list of rules provided out of the box by CodeNarc. CodeNarc provides abstract superclasses and helper classes for creating new rules.

See this screencast showing how easy it is to create a new rule.

### The Rule Interface

All rules must implement the `org.codenarc.rule.Rule` interface. This interface specifies that all rules must define a name, a priority (from 1 to 3), and also implement the `List applyTo(SourceCode sourceCode)` method. The method returns the List of `Violation` objects that result from applying the rule to a single source file.

### The AbstractRule Class

The `org.codenarc.rule.AbstractRule` class is the abstract superclass (or ancestor) for all rules provided with CodeNarc. It provides many standard properties and helper methods for subclasses, as described in Standard Properties for Configuring Rules.

#### A Sample Rule Subclass of AbstractRule

Here is an example rule class that is a subclass of `AbstractRule`:

    import org.codenarc.rule.AbstractRule
    import org.codenarc.source.SourceCode

    /**
     * Sample rule. Checks for static fields.
     */
    class MyStaticFieldRule extends AbstractRule {
        String name = 'MyStaticField'
        int priority = 2

        void applyTo(SourceCode sourceCode, List violations) {
            sourceCode.ast.classes.each { clazz ->
                clazz.fields.each { fieldNode ->
                    if (fieldNode.static) {
                        violations << createViolation(sourceCode, fieldNode)
                    }
                }
            }
        }
    }

Things to note about `MyStaticFieldRule` class:

- It extends `AbstractRule`.
- It provides name and priority properties as mandated by the `Rule` interface.
- It implements the `void applyTo(SourceCode sourceCode, List violations)` method which is declared abstract in the `AbstractRule` superclass.
- It accesses the AST for the source code, which is an instance of the `org.codehaus.groovy.ast.ModuleNode` class from Groovy.
- It uses the `createViolation()` helper method from `AbstractRule`.

See the CodeNarc source code for other examples (look for rule classes that are direct subclasses of `AbstractRule`).

### The AbstractAstVisitorRule and AbstractAstVisitor Classes

Many of the rules included with CodeNarc are implemented using the Visitor pattern, as supported by the Groovy AST (Abstract Syntax Tree). See the `ClassCodeVisitorSupport` class within the Groovy distribution (Javadocs).

#### A Sample Rule Using AbstractAstVisitorRule and AbstractAstVisitor

Here is an example rule class that is a subclass of `AbstractAstVisitorRule` that uses an associated AST Visitor class that is a subclass of `AbstractAstVisitor`. This is the code for the EmptyTryBlock rule included with CodeNarc.

    import org.codenarc.rule.AbstractAstVisitor
    import org.codenarc.rule.AbstractAstVisitorRule
    import org.codehaus.groovy.ast.stmt.TryCatchStatement
    import org.codenarc.util.AstUtil

    class EmptyTryBlockRule extends AbstractAstVisitorRule {
        String name = 'EmptyTryBlock'
        int priority = 2
        Class astVisitorClass = EmptyTryBlockAstVisitor
    }

    class EmptyTryBlockAstVisitor extends AbstractAstVisitor  {
        void visitTryCatchFinally(TryCatchStatement tryCatchStatement) {
            if (AstUtil.isEmptyBlock(tryCatchStatement.tryStatement)) {
                addViolation(tryCatchStatement)
            }
            super.visitTryCatchFinally(tryCatchStatement)
        }
    }

Things to note about this example:

- This file contains two classes. The `EmptyTryBlockRule` class extends `AbstractAstVisitorRule`. The `EmptyTryBlockAstVisitor` extends `AbstractAstVisitor`.
- `EmptyTryBlockRule` includes an astVisitorClass property that specifies that it uses the `EmptyTryBlockAstVisitor` class.
- `EmptyTryBlockAstVisitor` implements the `void visitTryCatchFinally(TryCatchStatement)` visitor method defined by the `ClassCodeVisitorSupport` so that it will visit every try/catch statement within the source code.
- It uses the `AstUtil` utility class.

See the CodeNarc source code and javadocs for more information and further examples.

### Creating a Rule Script

You can also create a new rule using a Groovy script file (typically a .groovy file). The script must still define a class that implements the `org.codenarc.rule.Rule` interface.

The main advantage is that the rule does not have to be compiled into a .class file first, so you can avoid the compile/build phase, and its associated hassles. The Groovy script file is parsed (and compiled) at runtime.

#### A Sample Rule Script

Here is an example rule script. Note that this is the same source code as in the sample rule class shown above.

    import org.codenarc.rule.AbstractRule
    import org.codenarc.source.SourceCode

    /**
     * Sample rule script. Checks for static fields.
     */
    class MyStaticFieldRule extends AbstractRule {
        String name = 'MyStaticField'
        int priority = 2

        void applyTo(SourceCode sourceCode, List violations) {
            sourceCode.ast.classes.each { clazz ->
                clazz.fields.each { fieldNode ->
                    if (fieldNode.static) {
                        violations << createViolation(sourceCode, fieldNode)
                    }
                }
            }
        }
    }