Search code examples
javapmd

How do I create a custom PMD rule to check if an instance of DSLContext is begin referenced in a loop?


I am trying to create a custom PMD rule that will cause a violation if an instance of org.jooq.DSLContext is being referenced in a loop.

I am completely new to PMD so I have no idea where to start.

Can anyone help?


Solution

  • the starting point is clear: https://pmd.github.io/latest/pmd_userdocs_extending_writing_rules_intro.html

    For the concrete question, I'd suggest to create a XPath based rule. You can use the custom XPath function "pmd-java:typeIs" to check for a specific type.

    E.g. to find all usages, you can use this query:

    //PrimaryPrefix[pmd-java:typeIs("org.jooq.DSLContext")]
    

    In order to restict the query for something inside a loop, you'll need to write probably this:

    //(ForStatement | WhileStatement | DoStatement)
        //PrimaryPrefix[pmd-java:typeIs("org.jooq.DSLContext")]
    

    Note: Due to a bug in PMD (https://github.com/pmd/pmd/pull/3499) this query needs to be expanded manually, see below the final expression in the XML rule snippet.

    The complete rule XML snippet might look like this:

    <rule name="DontReferenceDSLContextInLoops"
          language="java"
          message="Do not reference DSLContext in Loops"
          class="net.sourceforge.pmd.lang.rule.XPathRule" >
        <description>
    TODO
    
    Why is it bad to reference DSLContext?
    
    What should you do instead?
    
    Are there exceptions - when is it valid to suppress this violation?
        </description>
        <priority>3</priority>
        <properties>
            <property name="version" value="2.0"/>
            <property name="xpath">
                <value>
    <![CDATA[
    //ForStatement//PrimaryPrefix[pmd-java:typeIs("org.jooq.DSLContext")]
    |
    //WhileStatement//PrimaryPrefix[pmd-java:typeIs("org.jooq.DSLContext")]
    |
    //DoStatement//PrimaryPrefix[pmd-java:typeIs("org.jooq.DSLContext")]
    ]]>
                </value>
            </property>
        </properties>
    </rule>