CodeNarc

repository·master·Indexed 43 days ago

https://github.com/codenarc/codenarc

A static analysis tool for Groovy source code that enforces coding standards through a rule-based system. It provides detailed violation reports in HTML, XML, JSON, and other formats, and can be executed via the command line or as an Ant task using the org.codenarc.ant.CodeNarcTask class.

Tokens
88.2K
Snippets
302
Records
426
Agent score
54%

What's inside CodeNarc

  1. What is CodeNarc

    master

    CodeNarc is a static analysis tool specifically designed for Groovy source code. It allows developers to monitor and enforce coding standards and best practices by applying a set of predefined or custom Rules to Groovy files.

    CodeNarc generates reports in HTML or XML formats, providing:

    • A list of rules violated per source file.
    • Violation counts per package.
    • Total violation counts for the entire project.
  2. Review Design Rules in CodeNarc

    master

    CodeNarc provides several design-oriented rules to enforce best practices in Groovy/Java code. Key categories include:

    • Class Structure: AbstractClassWithPublicConstructor, AbstractClassWithoutAbstractMethod, EmptyMethodInAbstractClass, FinalClassWithProtectedMember.
    • Type Safety & Interfaces: CloneableWithoutClone, CompareToWithoutComparable, ConstantsOnlyInterface, ImplementationAsType, Instanceof.
    • Method Integrity: BooleanMethodReturnsNull, BuilderMethodWithSideEffects.
    • State & Side Effects: AssignmentToStaticFieldFromInstanceMethod, CloseWithoutCloseable, LocaleSetDefault.
    • Complexity: NestedForLoop.
  3. Avoid catching overly broad or dangerous exceptions

    master

    Several rules prevent catching exceptions that are too general or can mask critical system failures. Avoid the following patterns:

    • CatchError: Catching java.lang.Error is dangerous as it can catch ThreadDeath or OutOfMemoryError.
    • CatchThrowable: Catching java.lang.Throwable is too broad and can catch system-level errors.
    • CatchException: Catching java.lang.Exception is often too general for application code; it should typically be restricted to framework or infrastructure code.
    • CatchRuntimeException: Catching java.lang.RuntimeException is often too broad for application code.
    • SwallowThreadDeath: Never catch java.lang.ThreadDeath without re-throwing it, as this prevents the thread from terminating correctly.
    // Violation: Swallowing ThreadDeath
    try {
        def a = 0
    } catch (ThreadDeath td) {
        td.printStackTrace()
    }
  4. Understand Enhanced Classpath Rules in CodeNarc

    master

    Some CodeNarc rules (the "Enhanced" rules) use a later compilation phase to generate a richer and more complete Abstract Syntax Tree (AST). This allows for deeper analysis but requires that the application classes being analyzed, as well as all their referenced classes, are present on the classpath.

    Important Behavior: If an enhanced rule is enabled in your ruleset but a required class is missing from the classpath, CodeNarc will:

    1. Log a WARN message for each source file containing the missing reference.
    2. Skip processing that specific file for that rule.

    List of Enhanced Rules:

    • CloneWithoutCloneable (in enhanced ruleset)
    • JUnitAssertEqualsConstantActualValue (in enhanced ruleset)
    • UnsafeImplementationAsMap (in enhanced ruleset)
    • MissingOverrideAnnotation (in enhanced ruleset)
    • GrailsDomainGormMethods (in grails ruleset)
    • NonSerializableFieldInSerializableClass (in serialization ruleset)
    • ParameterOrReturnTypeNotSerializable (in jenkins ruleset)
    • ObjectOverrideOnlyNonCpsMethods (in jenkins ruleset)
    • ForbiddenCallInCpsMethod (in jenkins ruleset)
    • ExpressionInCpsMethodNotSerializable (in jenkins ruleset)
    • CpsCallFromNonCpsMethod (in jenkins ruleset)
    • ClassNotSerializable (in jenkins ruleset)
  5. Prefer collectNested over nested collect calls

    master

    The UseCollectNested rule suggests using collectNested{} instead of nesting multiple collect{} calls to improve code clarity.

    def list = [1, 2, [3, 4, 5, 6], [7]]
    
    // Violation
    list.collect { elem ->
        if (elem instanceof List)
            elem.collect {it *2}
        else elem * 2
    }
    
    // Better readability
    list.collectNested { it * 2 }
  6. Filter rule application by Class Name or Package

    master

    For rules that are subclasses of AbstractAstVisitorRule (most AST-based rules), you can control which classes they apply to using class name patterns.

    • applyToClassNames: The rule is only applied to classes matching these names.
    • doNotApplyToClassNames: The rule is NOT applied to classes matching these names.

    Pattern Rules:

    • Supports single names or comma-separated lists.
    • Supports wildcards: * (zero or more characters) and ? (exactly one character).
    • Can use fully-qualified class names (including package) or simple class names.

    Note: These properties are not available for rules handling imports, blank lines, or other file-based elements.

    # Do not apply to specific classes regardless of package
    CatchThrowable.doNotApplyToClassNames=BaseController,AbstractTest
    
    # Apply only to a specific class or any class in a specific package
    FieldName.applyToClassNames=org.codenarc.CodeNarc,org.codenarc.extra.*
  7. Configure CodeNarc reporting output

    master

    The -report parameter allows you to specify the format and destination of the analysis report.

    Format Syntax: TYPE[:FILENAME|stdout]

    Available Types:

    • html (Default if no report specified)
    • xml
    • text
    • json
    • gitlab
    • sarif
    • console
    • A fully-qualified class name implementing org.codenarc.report.ReportWriter.

    Output Destinations:

    • Standard Out: Append :stdout to the type (e.g., json:stdout).
    • File: Provide a filename after the colon (e.g., html:MyReport.html). If the filename is omitted, CodeNarc uses a default (e.g., CodeNarcReport.html for html).
    # Generate an HTML report to a specific file
    java org.codenarc.CodeNarc -report=html:MyProject.html
    
    # Output a JSON report to stdout
    java org.codenarc.CodeNarc -report=json:stdout
    
    # Use a custom ReportWriter class
    java org.codenarc.CodeNarc -report=org.codenarc.report.HtmlReportWriter
  8. Monitor GrailsServletContextReference usage

    master

    The GrailsServletContextReference rule monitors and controls access to the servletContext object within Grails controllers and taglibs. Direct access to servletContext can inhibit scalability and requires manual synchronization for thread safety.

    Usage Guidance:

    • Use this rule as a governance tool in teams to limit servletContext access.
    • If specific files require access, exclude them using doNotApplyToFilenames or doNotApplyToFilesMatching.

    Default Behavior:

    • Applies to files matching grails-app/controllers or grails-app/taglib.
  9. Avoid using GStrings as Map keys

    master

    The GStringAsMapKey rule flags the use of GStrings as keys in a Map because their hashCode is not guaranteed to be stable. You should call .toString() on the key instead.

    // Violation
    Map map = ["${someRef}" : 'invalid' ]
    
    // Recommended
    Map map = [someRef.toString() : 'invalid' ]
  10. Avoid Grails Mass Assignment vulnerabilities

    master

    The GrailsMassAssignment rule flags code where untrusted input (like params) is used to set arbitrary object fields without restriction. This can allow attackers to modify sensitive fields (e.g., isAdmin) by including them in the request parameters.

    Avoid patterns like:

    • new Person(params)
    • person.properties = params
    // VIOLATION
    def person = new Person(params)
    person.save()
    
    // VIOLATION
    def person = Person.get(1)
    person.properties = params
    person.save()
  11. Use safe dereference instead of explicit null checks

    master

    The UnnecessaryNullCheck rule encourages using Groovy's safe dereference operator (?.) instead of explicit x == null checks in conditional statements.

    Rules:

    • Avoid if (obj != null && obj.method()). Use if (obj?.method()).
    • Do not test this or super for null equality (e.g., if (this == null) is always pointless).
    • Do not check for null before an instanceof check, as instanceof returns false for null arguments.

    Example:

    // Violation
    if (x != null && x instanceof MyClass) { ... }
    
    // Acceptable
    if (x instanceof MyClass) { ... }
    // Violation
    if (obj != null && obj.prop) { }
    
    // Acceptable
    if (obj?.prop) { }
  12. Ensure exceptions are actually thrown

    master

    The ExceptionNotThrown rule checks that if you instantiate an exception inside a catch block, it is actually thrown as the last statement. Simply calling the constructor without throw is a violation.

    // Violation: Constructor called but not thrown
    void execute() {
        try { }
        catch(Exception e) {
            new Exception(e) 
        }
    }
    
    // OK: Exception is thrown
    try {
        doStuff()
    } catch(Exception e) {
        throw new DaoException(e)
    }