Skip to content

PMD Stock Apex, HTML, Visualforce, and XML Rules

The stock rules file of Appendix F.1, in full: the stock PMD rules for Apex, HTML, Visualforce, and XML metadata. A project repository keeps it as config/pmd/pmd-stock-rules.xml (The PMD Folder).

<?xml version="1.0" encoding="UTF-8" ?>
<ruleset
    name="Stock Rules"
    xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
    <description>
        The stock PMD rules this reference adopts for Apex, HTML, Visualforce, and
        XML metadata, each with an explicit priority and, where a rule's behaviour
        is changed, the property overrides, and every other property at PMD's
        default. The stock PMD rules for JavaScript are
        in pmd-stock-rules-javascript.xml, and the custom rules are in
        pmd-custom-rules-apex.xml, pmd-custom-rules-markup.xml,
        pmd-custom-rules-metadata.xml, pmd-custom-rules-flow.xml, and, for
        JavaScript, pmd-custom-rules-javascript.xml; all seven files are listed
        under engines.pmd.custom_rulesets in code-analyzer.yml.
    </description>

    <!--
        How to read this file.
        - Every rule carries an explicit priority. Code Analyzer derives its own severity
          from the priority (1 becomes 2, 2 and 3 become 3, 4 and 5 become 4), so
          code-analyzer.yml overrides each rule's severity with the same number as its
          priority; priorities 1 and 2 then block the pull request. Where the priority differs from the one
          PMD ships, the comment names the PMD default.
        - Every property of every rule is listed, so that a reader sees each setting. A
          property whose value differs from PMD's default has a comment above it that
          names that default; a property without one is at PMD's default. The two
          properties that every rule has, violationSuppressRegex and
          violationSuppressXPath, are listed only where they are used, and an XPath
          rule's own xpath property is not listed.
        - violationSuppressXPath entries are evaluated with the violation node as the
          context, in PMD's legacy XPath form.
        - Defaults were read from PMD 7.26.0, the version Code Analyzer 5.16.0 bundles.
        - Every Apex, HTML, and Visualforce rule in that PMD version is here, and every JavaScript
          rule is in pmd-stock-rules-javascript.xml. The JavaScript rules have a file of their own
          because PMD ships the four brace rules under one name for Apex and for JavaScript, and
          Code Analyzer runs only the first of two rules that share a name in one file. A rule
          this reference does not recommend enforcing is commented out, with no priority,
          so that it is seen to be left out on purpose; it is on one line, unless it has
          properties, which are listed at PMD's defaults inside the same comment: ExcessivePublicCount;
          ApexCRUDViolation and ApexSharingViolations, whose ground the custom rules cover
          (RequireAccessMode, FlagSystemMode, and RequireExplicitSharing); and four that PMD
          has deprecated in favour of NcssCount (ExcessiveClassLength, NcssConstructorCount,
          NcssMethodCount, and NcssTypeCount). To enforce one, take it out of its comment and
          give it a priority.
    -->

    <exclude-pattern>.*/.sfdx/.*</exclude-pattern>
    <exclude-pattern>.*/.sf/.*</exclude-pattern>
    <exclude-pattern>.*/node_modules/.*</exclude-pattern>

    <!-- ============================================================ -->
    <!-- APEX: SECURITY                                               -->
    <!-- ============================================================ -->

    <rule ref="category/apex/security.xml/ApexBadCrypto">
        <!-- PMD default: 3 -->
        <priority>1</priority>
    </rule>

    <!--
        The access mode standard is enforced by RequireAccessMode and
        FlagSystemMode, and this rule repeats the first.
    -->
    <!-- <rule ref="category/apex/security.xml/ApexCRUDViolation">
        <properties>
            <property name="createAuthMethodPattern" value="" />
            <property name="createAuthMethodTypeParamIndex" value="0" />
            <property name="deleteAuthMethodPattern" value="" />
            <property name="deleteAuthMethodTypeParamIndex" value="0" />
            <property name="mergeAuthMethodPattern" value="" />
            <property name="mergeAuthMethodTypeParamIndex" value="0" />
            <property name="readAuthMethodPattern" value="" />
            <property name="readAuthMethodTypeParamIndex" value="0" />
            <property name="undeleteAuthMethodPattern" value="" />
            <property name="undeleteAuthMethodTypeParamIndex" value="0" />
            <property name="updateAuthMethodPattern" value="" />
            <property name="updateAuthMethodTypeParamIndex" value="0" />
        </properties>
    </rule> -->

    <rule ref="category/apex/security.xml/ApexDangerousMethods">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/security.xml/ApexInsecureEndpoint">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/security.xml/ApexOpenRedirect">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <!--
        RequireExplicitSharing is more restrictive, because it does not check
        for and depend on DML: it requires a sharing declaration on every outer
        class, test classes included, whether or not the class touches data.
        ApexSharingViolations reports only a class that holds a query, a DML
        statement, or a Database method call, and does not include tests. It
        also reports inner classes, where the standard recommends the
        declaration and does not require it.
    -->
    <!-- <rule ref="category/apex/security.xml/ApexSharingViolations" /> -->

    <rule ref="category/apex/security.xml/ApexSOQLInjection">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/security.xml/ApexSuggestUsingNamedCred">
        <!-- PMD default: 3 -->
        <priority>1</priority>
    </rule>

    <rule ref="category/apex/security.xml/ApexXSSFromEscapeFalse">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/security.xml/ApexXSSFromURLParam">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- APEX: PERFORMANCE                                            -->
    <!-- ============================================================ -->

    <rule ref="category/apex/performance.xml/AvoidDebugStatements">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/performance.xml/AvoidNonRestrictiveQueries">
        <!-- PMD default: 3 -->
        <priority>2</priority>
        <properties>
            <!-- not reported inside test classes; the source ruleset's document-wide //UserClass form is narrowed to the violation's own class -->
            <property
                name="violationSuppressXPath"
                value="ancestor::UserClass/ModifierNode[@Test = true()]" />
        </properties>
    </rule>

    <rule ref="category/apex/performance.xml/EagerlyLoadedDescribeSObjectResult">
        <!-- PMD default: 3 -->
        <priority>2</priority>
        <properties>
            <property name="noDefault" value="false" />
        </properties>
    </rule>

    <rule ref="category/apex/performance.xml/OperationWithHighCostInLoop">
        <priority>3</priority>
    </rule>

    <rule ref="category/apex/performance.xml/OperationWithLimitsInLoop">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- APEX: BEST PRACTICES                                         -->
    <!-- ============================================================ -->

    <rule
        ref="category/apex/bestpractices.xml/ApexAssertionsShouldIncludeMessage">
        <priority>3</priority>
    </rule>

    <rule
        ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts">
        <!-- PMD default: 3 -->
        <priority>2</priority>
        <properties>
            <property name="additionalAssertMethodPattern" value="" />
        </properties>
    </rule>

    <rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveRunAs">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule
        ref="category/apex/bestpractices.xml/ApexUnitTestMethodShouldHaveIsTestAnnotation">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule
        ref="category/apex/bestpractices.xml/ApexUnitTestShouldNotUseSeeAllDataTrue">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/bestpractices.xml/AvoidFutureAnnotation">
        <priority>4</priority>
    </rule>

    <rule ref="category/apex/bestpractices.xml/AvoidGlobalModifier">
        <!-- PMD default: 3 -->
        <priority>4</priority>
    </rule>

    <rule ref="category/apex/bestpractices.xml/AvoidLogicInTrigger">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/bestpractices.xml/DebugsShouldUseLoggingLevel">
        <!-- PMD default: 3 -->
        <priority>4</priority>
        <properties>
            <property name="strictMode" value="false" />
        </properties>
    </rule>

    <rule ref="category/apex/bestpractices.xml/QueueableWithoutFinalizer">
        <priority>5</priority>
    </rule>

    <rule ref="category/apex/bestpractices.xml/UnusedLocalVariable">
        <!-- PMD default: 5 -->
        <priority>3</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- APEX: ERROR PRONE                                            -->
    <!-- ============================================================ -->

    <rule ref="category/apex/errorprone.xml/ApexCSRF">
        <!-- PMD default: 3 -->
        <priority>1</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/AvoidDirectAccessTriggerMap">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/AvoidHardcodingId">
        <!-- PMD default: 3 -->
        <priority>1</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/AvoidInterfaceAsMapKey">
        <priority>3</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/AvoidNonExistentAnnotations">
        <priority>3</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/AvoidStatefulDatabaseResult">
        <!-- PMD default: 2 -->
        <priority>3</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/EmptyCatchBlock">
        <!-- PMD default: 3 -->
        <priority>2</priority>
        <properties>
            <property name="allowCommentedBlocks" value="false" />
            <property name="allowExceptionNameRegex" value="^(ignored|expected)$" />
        </properties>
    </rule>

    <rule ref="category/apex/errorprone.xml/EmptyIfStmt">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/EmptyStatementBlock">
        <!-- PMD default: 3 -->
        <priority>2</priority>
        <properties>
            <!-- PMD default: true -->
            <property name="reportEmptyPrivateNoArgConstructor" value="false" />
            <!-- PMD default: true -->
            <property name="reportEmptyVirtualMethod" value="false" />
            <!-- not reported: the block of a when else, which holds a comment when it does nothing -->
            <property name="violationSuppressXPath" value="./parent::ElseWhenBlock" />
        </properties>
    </rule>

    <rule ref="category/apex/errorprone.xml/EmptyTryOrFinallyBlock">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/EmptyWhileStmt">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/InaccessibleAuraEnabledGetter">
        <priority>3</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/InvocableClassNoArgConstructor">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/MethodWithSameNameAsEnclosingClass">
        <priority>3</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/OverrideBothEqualsAndHashcode">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/TestMethodsMustBeInTestClasses">
        <!-- PMD default: 3 -->
        <priority>1</priority>
    </rule>

    <rule ref="category/apex/errorprone.xml/TypeShadowsBuiltInNamespace">
        <!-- PMD default: 1 -->
        <priority>2</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- APEX: DOCUMENTATION                                          -->
    <!-- ============================================================ -->

    <rule ref="category/apex/documentation.xml/ApexDoc">
        <!-- PMD default: 3 -->
        <priority>4</priority>
        <properties>
            <property name="reportMissingDescription" value="true" />
            <!-- PMD default: false -->
            <property name="reportPrivate" value="true" />
            <!-- PMD default: true -->
            <property name="reportProperty" value="false" />
            <!-- PMD default: false -->
            <property name="reportProtected" value="true" />
        </properties>
    </rule>

    <!-- ============================================================ -->
    <!-- APEX: CODE STYLE                                             -->
    <!-- ============================================================ -->

    <rule ref="category/apex/codestyle.xml/AnnotationsNamingConventions">
        <!-- PMD default: 3 -->
        <priority>1</priority>
    </rule>

    <rule ref="category/apex/codestyle.xml/ClassNamingConventions">
        <priority>1</priority>
        <properties>
            <!-- The test class suffix and the I and Abstract prefixes are the naming standards of the General page. abstractClassPattern reads a top-level class only. -->
            <!-- PMD default: [A-Z][a-zA-Z0-9_]* -->
            <property
                name="abstractClassPattern"
                value="Abstract[A-Z][a-zA-Z0-9_]*" />
            <property name="classPattern" value="[A-Z][a-zA-Z0-9_]*" />
            <property name="enumPattern" value="[A-Z][a-zA-Z0-9_]*" />
            <property name="innerClassPattern" value="[A-Z][a-zA-Z0-9_]*" />
            <!-- PMD default: [A-Z][a-zA-Z0-9_]* -->
            <property name="innerInterfacePattern" value="I[A-Z][a-zA-Z0-9_]*" />
            <!-- PMD default: [A-Z][a-zA-Z0-9_]* -->
            <property name="interfacePattern" value="I[A-Z][a-zA-Z0-9_]*" />
            <!-- PMD default: [A-Z][a-zA-Z0-9_]* -->
            <property name="testClassPattern" value="[A-Z][a-zA-Z0-9_]*Tests?" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/FieldDeclarationsShouldBeAtStart">
        <!-- PMD default: 3 -->
        <priority>4</priority>
    </rule>

    <rule ref="category/apex/codestyle.xml/FieldNamingConventions">
        <priority>1</priority>
        <properties>
            <!-- Upper snake case for a constant (static final) and an enum value; camel case for a final, a static, and an instance field. -->
            <property name="constantPattern" value="[A-Z][A-Z0-9_]*" />
            <property name="enumConstantPattern" value="[A-Z][A-Z0-9_]*" />
            <property name="finalPattern" value="[a-z][a-zA-Z0-9]*" />
            <property name="instancePattern" value="[a-z][a-zA-Z0-9]*" />
            <property name="staticPattern" value="[a-z][a-zA-Z0-9]*" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/ForLoopsMustUseBraces">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/codestyle.xml/FormalParameterNamingConventions">
        <priority>1</priority>
        <properties>
            <property name="finalMethodParameterPattern" value="[a-z][a-zA-Z0-9]*" />
            <property name="methodParameterPattern" value="[a-z][a-zA-Z0-9]*" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/IfElseStmtsMustUseBraces">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/codestyle.xml/IfStmtsMustUseBraces">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/apex/codestyle.xml/LocalVariableNamingConventions">
        <priority>1</priority>
        <properties>
            <!-- PMD default: [a-z][a-zA-Z0-9]* -->
            <property name="finalLocalPattern" value="[a-zA-Z][a-zA-Z0-9]*" />
            <property name="localPattern" value="[a-z][a-zA-Z0-9]*" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/MethodNamingConventions">
        <priority>1</priority>
        <properties>
            <!-- Underscores are allowed in a test method name and discouraged: test methods have long been written with them, so the standards are lenient on purpose. An organisation should remove them as it revises its code -->
            <property name="instancePattern" value="[a-z][a-zA-Z0-9]*" />
            <property name="staticPattern" value="[a-z][a-zA-Z0-9]*" />
            <!-- PMD default: [a-z][a-zA-Z0-9]* -->
            <property name="testPattern" value="[a-z][a-zA-Z0-9_]*" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/OneDeclarationPerLine">
        <priority>1</priority>
        <properties>
            <property name="reportInForLoopInitializer" value="true" />
            <property name="strictMode" value="false" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/PropertyNamingConventions">
        <priority>1</priority>
        <properties>
            <property name="instancePattern" value="[a-z][a-zA-Z0-9]*" />
            <property name="staticPattern" value="[a-z][a-zA-Z0-9]*" />
        </properties>
    </rule>

    <rule ref="category/apex/codestyle.xml/WhileLoopsMustUseBraces">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- APEX: DESIGN                                                 -->
    <!-- ============================================================ -->

    <rule ref="category/apex/design.xml/AvoidBooleanMethodParameters">
        <!-- PMD default: 2 -->
        <priority>4</priority>
    </rule>

    <rule ref="category/apex/design.xml/AvoidDeeplyNestedIfStmts">
        <priority>3</priority>
        <properties>
            <property name="problemDepth" value="3" />
        </properties>
    </rule>

    <rule ref="category/apex/design.xml/CognitiveComplexity">
        <priority>3</priority>
        <properties>
            <property name="classReportLevel" value="50" />
            <property name="methodReportLevel" value="15" />
        </properties>
    </rule>

    <rule ref="category/apex/design.xml/CyclomaticComplexity">
        <priority>3</priority>
        <properties>
            <property name="classReportLevel" value="40" />
            <property name="methodReportLevel" value="10" />
        </properties>
    </rule>

    <!-- Deprecated by PMD in favour of NcssCount, which the stock rules file adopts. -->
    <!-- <rule ref="category/apex/design.xml/ExcessiveClassLength">
        <properties>
            <property name="minimum" value="1000" />
        </properties>
    </rule> -->

    <!-- These standards set no limit on the number of parameters of a method. -->
    <!-- <rule ref="category/apex/design.xml/ExcessiveParameterList">
        <properties>
            <property name="minimum" value="4" />
        </properties>
    </rule> -->

    <!-- These standards set no limit on the number of public members of a class. -->
    <!-- <rule ref="category/apex/design.xml/ExcessivePublicCount">
        <properties>
            <property name="minimum" value="20" />
        </properties>
    </rule> -->

    <!-- Deprecated by PMD in favour of NcssCount. -->
    <!-- <rule ref="category/apex/design.xml/NcssConstructorCount">
        <properties>
            <property name="minimum" value="20" />
        </properties>
    </rule> -->

    <rule ref="category/apex/design.xml/NcssCount">
        <!-- PMD default: 3 -->
        <priority>4</priority>
        <properties>
            <property name="classReportLevel" value="500" />
            <property name="methodReportLevel" value="40" />
        </properties>
    </rule>

    <!-- Deprecated by PMD in favour of NcssCount. -->
    <!-- <rule ref="category/apex/design.xml/NcssMethodCount">
        <properties>
            <property name="minimum" value="40" />
        </properties>
    </rule> -->

    <!-- Deprecated by PMD in favour of NcssCount. -->
    <!-- <rule ref="category/apex/design.xml/NcssTypeCount">
        <properties>
            <property name="minimum" value="500" />
        </properties>
    </rule> -->

    <!-- A duplicate of CyclomaticComplexity, which the stock rules file adopts: both count the decision points of a method, and CyclomaticComplexity also counts && and ||, so a complex method was reported twice. -->
    <!-- <rule ref="category/apex/design.xml/StdCyclomaticComplexity">
        <properties>
            <property name="reportLevel" value="10" />
            <property name="showClassesComplexity" value="true" />
            <property name="showMethodsComplexity" value="true" />
        </properties>
    </rule> -->

    <rule ref="category/apex/design.xml/TooManyFields">
        <!-- PMD default: 3 -->
        <priority>4</priority>
        <properties>
            <property name="maxfields" value="15" />
        </properties>
    </rule>

    <rule ref="category/apex/design.xml/UnusedMethod">
        <priority>3</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- HTML (LWC AND AURA): BEST PRACTICES                          -->
    <!-- ============================================================ -->

    <rule ref="category/html/bestpractices.xml/AvoidInlineStyles">
        <priority>3</priority>
    </rule>

    <!--
        Several kinds of HTML-like file go through the HTML engine, and one of
        them may need the type attribute, so a redundant one does no harm.
    -->
    <!-- <rule ref="category/html/bestpractices.xml/UnnecessaryTypeAttribute" /> -->

    <!--
        ImageWithoutAltHtmlLwcAura reports the same missing alt at a blocking
        severity, matches the tag in any case, and also reads Aura markup.
    -->
    <!-- <rule ref="category/html/bestpractices.xml/UseAltAttributeForImages" /> -->

    <!-- ============================================================ -->
    <!-- VISUALFORCE: SECURITY                                        -->
    <!-- ============================================================ -->

    <rule ref="category/visualforce/security.xml/VfCsrf">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/visualforce/security.xml/VfHtmlStyleTagXss">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <rule ref="category/visualforce/security.xml/VfUnescapeEl">
        <!-- PMD default: 3 -->
        <priority>2</priority>
    </rule>

    <!-- ============================================================ -->
    <!-- XML METADATA: BEST PRACTICES                                 -->
    <!-- ============================================================ -->

    <!--
        Salesforce writes the XML declaration, with its encoding, on every
        metadata file it retrieves.
    -->
    <!-- <rule ref="category/xml/bestpractices.xml/MissingEncoding" /> -->

    <!-- ============================================================ -->
    <!-- XML METADATA: ERROR PRONE                                    -->
    <!-- ============================================================ -->

    <!--
        Salesforce writes the metadata XML, and a mistyped CDATA section in a
        hand-written file fails the deployment itself.
    -->
    <!-- <rule ref="category/xml/errorprone.xml/MistypedCDATASection" /> -->
</ruleset>