<?xml version="1.0" encoding="UTF-8"?>

<ruleset name="Error Prone"
         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>
Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors.
    </description>

    <rule name="ApexCSRF"
          language="apex"
          since="5.5.3"
          message="Avoid making DML operations in Apex class constructor or initializers"
          class="net.sourceforge.pmd.lang.apex.rule.errorprone.ApexCSRFRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#apexcsrf">
        <description>
Having DML operations in Apex class constructor or initializers can have unexpected side effects:
By just accessing a page, the DML statements would be executed and the database would be modified.
Just querying the database is permitted.

In addition to constructors and initializers, any method called `init` is checked as well.

Salesforce Apex already protects against this scenario and raises a runtime exception.

Note: This rule has been moved from category "Security" to "Error Prone" with PMD 6.21.0, since
using DML in constructors is not a security problem, but crashes the application.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
public class Foo {
    // initializer
    {
        insert data;
    }

    // static initializer
    static {
        insert data;
    }

    // constructor
    public Foo() {
        insert data;
    }
}
]]>
        </example>
    </rule>

    <rule name="AvoidDirectAccessTriggerMap"
          language="apex"
          since="6.0.0"
          message="Avoid directly accessing Trigger.old and Trigger.new"
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#avoiddirectaccesstriggermap">
        <description>
Avoid directly accessing Trigger.old and Trigger.new as it can lead to a bug. Triggers should be bulkified and iterate through the map to handle the actions for each item separately.
        </description>
        <priority>3</priority>
            <properties>
            <property name="xpath">
                <value>
<![CDATA[
//ArrayLoadExpression[TriggerVariableExpression and LiteralExpression]
]]>
                </value>
            </property>
        </properties>
        <example>
<![CDATA[
trigger AccountTrigger on Account (before insert, before update) {
   Account a = Trigger.new[0]; //Bad: Accessing the trigger array directly is not recommended.

   for ( Account a : Trigger.new ) {
        //Good: Iterate through the trigger.new array instead.
   }
}
]]>
        </example>
    </rule>

    <rule name="AvoidHardcodingId"
          language="apex"
          since="6.0.0"
          message="Hardcoding Id's is bound to break when changing environments."
          class="net.sourceforge.pmd.lang.apex.rule.errorprone.AvoidHardcodingIdRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#avoidhardcodingid">
        <description>
When deploying Apex code between sandbox and production environments, or installing Force.com AppExchange packages,
it is essential to avoid hardcoding IDs in the Apex code. By doing so, if the record IDs change between environments,
the logic can dynamically identify the proper data to operate against and not fail.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
public without sharing class Foo {
    void foo() {
        //Error - hardcoded the record type id
        if (a.RecordTypeId == '012500000009WAr') {
            //do some logic here.....
        } else if (a.RecordTypeId == '0123000000095Km') {
            //do some logic here for a different record type...
        }
    }
}
]]>
        </example>
    </rule>

    <rule name="AvoidNonExistentAnnotations"
          language="apex"
          since="6.5.0"
          message="Use of non existent annotations will lead to broken Apex code which will not compile in the future."
          class="net.sourceforge.pmd.lang.apex.rule.errorprone.AvoidNonExistentAnnotationsRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#avoidnonexistentannotations">
        <description>
            Apex supported non existent annotations for legacy reasons.
            In the future, use of such non-existent annotations could result in broken apex code that will not compile.
            This will prevent users of garbage annotations from being able to use legitimate annotations added to Apex in the future.
            A full list of supported annotations can be found at https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation.htm
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
@NonExistentAnnotation public class ClassWithNonexistentAnnotation {
    @NonExistentAnnotation public void methodWithNonExistentAnnotation() {
        // ...
    }
}
]]>
        </example>
    </rule>

    <rule name="EmptyCatchBlock"
          language="apex"
          since="6.0.0"
          message="Avoid empty catch blocks"
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#emptycatchblock">
        <description>
Empty Catch Block finds instances where an exception is caught, but nothing is done.
In most circumstances, this swallows an exception which should either be acted on
or reported.
        </description>
        <priority>3</priority>
        <properties>
            <property name="allowCommentedBlocks" type="Boolean" description="Empty blocks containing comments will be skipped" value="false"/>
            <property name="allowExceptionNameRegex" type="Regex" description="Empty blocks catching exceptions with names matching this regular expression will be skipped" value="^(ignored|expected)$"/>
            <property name="xpath">
                <value>
<![CDATA[
//CatchBlockStatement[./BlockStatement[count(*) = 0] and
    not(matches(@VariableName, $allowExceptionNameRegex)) and
    ($allowCommentedBlocks = false() or @ContainsComment = false())]
]]>
                </value>
            </property>
        </properties>
        <example>
<![CDATA[
public void doSomething() {
    ...
    try {
        insert accounts;
    } catch (DmlException dmle) {
        // not good
    }
}
]]>
        </example>
    </rule>

    <rule name="EmptyIfStmt"
          language="apex"
          since="6.0.0"
          message="Avoid empty 'if' statements"
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#emptyifstmt">
        <description>
Empty If Statement finds instances where a condition is checked but nothing is done about it.
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
<![CDATA[
//IfBlockStatement
 [BlockStatement[count(*) = 0]]
]]>
                </value>
            </property>
        </properties>
        <example>
<![CDATA[
public class Foo {
    public void bar(Integer x) {
        if (x == 0) {
            // empty!
        }
    }
}
]]>
        </example>
    </rule>

    <rule name="EmptyStatementBlock"
          language="apex"
          since="6.0.0"
          message="Avoid empty block statements."
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#emptystatementblock">
        <description>
Empty block statements serve no purpose and should be removed.
        </description>
        <priority>3</priority>
        <properties>
            <property name="reportEmptyPrivateNoArgConstructor" type="Boolean" value="true" description="If false, empty private no-arg constructors are not flagged. This supports a common idiom used by singleton pattern implementations, utility classes, etc."/>
            <property name="reportEmptyVirtualMethod" type="Boolean" value="true" description="If false, empty virtual methods are not flagged. This supports abstract base classes with default no-op implementations."/>
            <property name="xpath">
                <value>
<![CDATA[
//Method[$reportEmptyPrivateNoArgConstructor = true()
    or (@Constructor != true()
    or ./ModifierNode[@Private != true()]
    or ./Parameter[count(*) > 0])]/ModifierNode[@Abstract != true()
        and ($reportEmptyVirtualMethod = true() or @Virtual != true())
        and ../BlockStatement[count(*) = 0]
    ]
| //Method/BlockStatement//BlockStatement
    [not(parent::CatchBlockStatement)]
    [count(*) = 0]
    [@RealLoc = true()]
]]>
                </value>
            </property>
        </properties>
        <example>
<![CDATA[
public class Foo {

   private Integer _bar;

   public void setBar(Integer bar) {
        // empty
   }

}
]]>
        </example>
    </rule>

    <rule name="EmptyTryOrFinallyBlock"
          language="apex"
          since="6.0.0"
          message="Avoid empty try or finally blocks"
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#emptytryorfinallyblock">
        <description>
Avoid empty try or finally blocks - what's the point?
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
<![CDATA[
//TryCatchFinallyBlockStatement[./BlockStatement[count(*) = 0]]
]]>
                </value>
            </property>
        </properties>
        <example>
<![CDATA[
public class Foo {
    public void bar() {
        try {
          // empty !
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Foo {
    public void bar() {
        try {
            Integer x=2;
        } finally {
            // empty!
        }
    }
}
]]>
        </example>
    </rule>

    <rule name="EmptyWhileStmt"
          language="apex"
          since="6.0.0"
          message="Avoid empty 'while' statements"
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#emptywhilestmt">
        <description>
Empty While Statement finds all instances where a while statement does nothing.
If it is a timing loop, then you should use Thread.sleep() for it; if it is
a while loop that does a lot in the exit expression, rewrite it to make it clearer.
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
<![CDATA[
//WhileLoopStatement[./BlockStatement[count(*) = 0]]
]]>
                </value>
            </property>
        </properties>
        <example>
<![CDATA[
public void bar(Integer a, Integer b) {
  while (a == b) {
    // empty!
  }
}
]]>
        </example>
    </rule>

    <rule name="InaccessibleAuraEnabledGetter"
          language="apex"
          since="6.36.0"
          message="AuraEnabled getter must be public or global if is referenced in Lightning components"
          class="net.sourceforge.pmd.lang.apex.rule.errorprone.InaccessibleAuraEnabledGetterRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#inaccessibleauraenabledgetter">
        <description>
In the Summer '21 release, a mandatory security update enforces access modifiers on Apex properties in
Lightning component markup. The update prevents access to private or protected Apex getters from Aura
and Lightning Web Components.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
public class Foo {
    @AuraEnabled
    public Integer counter { private get; set; } // Violating - Private getter is inaccessible to Lightning components

    @AuraEnabled
    public static Foo bar()
    {
        Foo foo = new Foo();
        foo.counter = 2; 
        return foo;
    }
}
]]>
        </example>
        <example>
<![CDATA[
public class Foo {
    @AuraEnabled
    public Integer counter { protected get; set; } // Violating - Protected getter is inaccessible to Lightning components

    @AuraEnabled
    public static Foo bar()
    {
        Foo foo = new Foo();
        foo.counter = 2; 
        return foo;
    }
}
]]>
        </example>
        <example>
<![CDATA[
public class Foo {
    @AuraEnabled
    public Integer counter { get; set; } // Compliant - Public getter is accessible to Lightning components

    @AuraEnabled
    public static Foo bar()
    {
        Foo foo = new Foo();
        foo.counter = 2; 
        return foo;
    }
}
]]>
        </example>
    </rule>

    <rule name="MethodWithSameNameAsEnclosingClass"
          language="apex"
          since="5.5.0"
          message="Classes should not have non-constructor methods with the same name as the class"
          class="net.sourceforge.pmd.lang.apex.rule.errorprone.MethodWithSameNameAsEnclosingClassRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#methodwithsamenameasenclosingclass">
        <description>
Non-constructor methods should not have the same name as the enclosing class.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
public class MyClass {
    // this is OK because it is a constructor
    public MyClass() {}
    // this is bad because it is a method
    public void MyClass() {}
}
]]>
        </example>
    </rule>

    <rule name="OverrideBothEqualsAndHashcode"
          language="apex"
          since="6.31.0"
          message="Ensure you override both equals() and hashCode()"
          class="net.sourceforge.pmd.lang.apex.rule.errorprone.OverrideBothEqualsAndHashcodeRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#overridebothequalsandhashcode">
        <description>
Override both `public Boolean equals(Object obj)`, and `public Integer hashCode()`, or override neither.
Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly
delegating to your superclass.

This is especially important when [Using Custom Types in Map Keys and Sets](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections_maps_keys_userdefined.htm).
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
public class Bar {        // poor, missing a hashCode() method
    public Boolean equals(Object o) {
      // do some comparison
    }
}
public class Baz {        // poor, missing an equals() method
    public Integer hashCode() {
      // return some hash value
    }
}
public class Foo {        // perfect, both methods provided
    public Boolean equals(Object other) {
      // do some comparison
    }
    public Integer hashCode() {
      // return some hash value
    }
}
]]>
        </example>
    </rule>

    <rule name="TestMethodsMustBeInTestClasses"
          language="apex"
          since="6.22.0"
          message="Test methods must be in test classes"
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#testmethodsmustbeintestclasses">
       <description>
          Test methods marked as a testMethod or annotated with @IsTest,
          but not residing in a test class should be moved to a proper
          class or have the @IsTest annotation added to the class.

          Support for tests inside functional classes was removed in Spring-13 (API Version 27.0),
          making classes that violate this rule fail compile-time. This rule is mostly usable when
          dealing with legacy code.
       </description>
       <priority>3</priority>
       <properties>
          <property name="xpath">
             <value>
    <![CDATA[
    //UserClass[
      not(./ModifierNode/Annotation[lower-case(@Name) = 'istest']) and
      (
        (./Method/ModifierNode/Annotation[lower-case(@Name) = 'istest']) or
        (./Method/ModifierNode[@Test = true()])
      )
    ]

    ]]>
             </value>
          </property>
       </properties>
       <example>
           <![CDATA[// Violating
private class TestClass {
  @IsTest static void myTest() {
    // Code here
  }
}

private class TestClass {
  static testMethod void myTest() {
    // Code here
  }
}

// Compliant
@IsTest
private class TestClass {
  @IsTest static void myTest() {
    // Code here
  }
}

@IsTest
private class TestClass {
  static testMethod void myTest() {
    // Code here
  }
}
]]>
       </example>
    </rule>
</ruleset>
