[apex] Reorganize rules into categories

This commit is contained in:
Andreas Dangel
2017-11-03 14:05:40 +01:00
parent c466179c2a
commit e9425e34d8
18 changed files with 1373 additions and 1224 deletions

View File

@ -0,0 +1,140 @@
<?xml version="1.0"?>
<ruleset name="Best Practices"
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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules which enforce generally accepted best practices.
</description>
<rule name="ApexUnitTestClassShouldHaveAsserts"
since="5.5.1"
message="Apex unit tests should System.assert() or assertEquals() or assertNotEquals()"
class="net.sourceforge.pmd.lang.apex.rule.apexunit.ApexUnitTestClassShouldHaveAssertsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.html#apexunittestclassshouldhaveasserts">
<description>
Apex unit tests should include at least one assertion. This makes the tests more robust, and using assert
with messages provide the developer a clearer idea of what the test does.
</description>
<priority>3</priority>
<example>
<![CDATA[
@isTest
public class Foo {
public static testMethod void testSomething() {
Account a = null;
// This is better than having a NullPointerException
// System.assertNotEquals(a, null, 'account not found');
a.toString();
}
}
]]>
</example>
</rule>
<rule name="ApexUnitTestShouldNotUseSeeAllDataTrue"
since="5.5.1"
message="Apex unit tests should not use @isTest(seeAllData = true)"
class="net.sourceforge.pmd.lang.apex.rule.apexunit.ApexUnitTestShouldNotUseSeeAllDataTrueRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.html#apexunittestshouldnotuseseealldatatrue">
<description>
Apex unit tests should not use @isTest(seeAllData=true) because it opens up the existing database data for unexpected modification by tests.
</description>
<priority>3</priority>
<example>
<![CDATA[
@isTest(seeAllData = true)
public class Foo {
public static testMethod void testSomething() {
Account a = null;
// This is better than having a NullPointerException
// System.assertNotEquals(a, null, 'account not found');
a.toString();
}
}
]]>
</example>
</rule>
<rule name="AvoidGlobalModifier"
since="5.5.0"
message="Avoid using global modifier"
class="net.sourceforge.pmd.lang.apex.rule.style.AvoidGlobalModifierRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.html#avoidglobalmodifier">
<description>
Global classes should be avoided (especially in managed packages) as they can never be deleted or changed in signature. Always check twice if something needs to be global.
Many interfaces (e.g. Batch) required global modifiers in the past but don't require this anymore. Don't lock yourself in.
</description>
<priority>3</priority>
<example>
<![CDATA[
global class Unchangeable {
global UndeletableType unchangable(UndeletableType param) {
// ...
}
}
]]>
</example>
</rule>
<rule name="AvoidHardcodingId"
since="6.0.0"
message="Hardcoding Id's is bound to break when changing environments."
class="net.sourceforge.pmd.lang.apex.rule.style.AvoidHardcodingIdRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.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="AvoidLogicInTrigger"
since="5.5.0"
message="Avoid logic in triggers"
class="net.sourceforge.pmd.lang.apex.rule.style.AvoidLogicInTriggerRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.html#avoidlogicintrigger">
<description>
As triggers do not allow methods like regular classes they are less flexible and suited to apply good encapsulation style.
Therefore delegate the triggers work to a regular class (often called Trigger handler class).
See more here: https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices
</description>
<priority>3</priority>
<example>
<![CDATA[
trigger Accounts on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
for(Account acc : Trigger.new) {
if(Trigger.isInsert) {
// ...
}
// ...
if(Trigger.isDelete) {
// ...
}
}
}
]]>
</example>
</rule>
</ruleset>

View File

@ -0,0 +1,207 @@
<?xml version="1.0"?>
<ruleset name="Codestyle"
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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules which enforce a specific coding style.
</description>
<rule name="ClassNamingConventions"
since="5.5.0"
message="Class names should begin with an uppercase character"
class="net.sourceforge.pmd.lang.apex.rule.style.ClassNamingConventionsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#classnamingconventions">
<description>
Class names should always begin with an upper case character.
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {}
]]>
</example>
</rule>
<rule name="IfElseStmtsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using 'if...else' statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#ifelsestmtsmustusebraces">
<description>
Avoid using if..else statements without using surrounding braces. If the code formatting
or indentation is lost then it becomes difficult to separate the code being controlled
from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//IfBlockStatement/BlockStatement[@CurlyBrace='false'][count(child::*) > 0]
|
//IfElseBlockStatement/BlockStatement[@CurlyBrace='false'][count(child::*) > 0]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
// this is OK
if (foo) x++;
// but this is not
if (foo)
x = x+1;
else
x = x-1;
]]>
</example>
</rule>
<rule name="IfStmtsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using if statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#ifstmtsmustusebraces">
<description>
Avoid using if statements without using braces to surround the code block. If the code
formatting or indentation is lost then it becomes difficult to separate the code being
controlled from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//IfBlockStatement/BlockStatement[@CurlyBrace='false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
if (foo) // not recommended
x++;
if (foo) { // preferred approach
x++;
}
]]>
</example>
</rule>
<rule name="ForLoopsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using 'for' statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#forloopsmustusebraces">
<description>
Avoid using 'for' statements without using surrounding braces. If the code formatting or
indentation is lost then it becomes difficult to separate the code being controlled
from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//ForLoopStatement/BlockStatement[@CurlyBrace='false']
|
//ForEachStatement/BlockStatement[@CurlyBrace='false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
for (int i = 0; i < 42; i++) // not recommended
foo();
for (int i = 0; i < 42; i++) { // preferred approach
foo();
}
]]>
</example>
</rule>
<rule name="MethodNamingConventions"
since="5.5.0"
message="Method name does not begin with a lower case character."
class="net.sourceforge.pmd.lang.apex.rule.style.MethodNamingConventionsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#methodnamingconventions">
<description>
Method names should always begin with a lower case character, and should not contain underscores.
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {
public void fooStuff() {
}
}
]]>
</example>
</rule>
<rule name="VariableNamingConventions"
since="5.5.0"
message="{0} variable {1} should begin with {2}"
class="net.sourceforge.pmd.lang.apex.rule.style.VariableNamingConventionsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#variablenamingconventions">
<description>
A variable naming conventions rule - customize this to your liking. Currently, it
checks for final variables that should be fully capitalized and non-final variables
that should not include underscores.
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {
public static final Integer MY_NUM = 0;
public String myTest = '';
DataModule dmTest = new DataModule();
}
]]>
</example>
</rule>
<rule name="WhileLoopsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using 'while' statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#whileloopsmustusebraces">
<description>
Avoid using 'while' statements without using braces to surround the code block. If the code
formatting or indentation is lost then it becomes difficult to separate the code being
controlled from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//WhileLoopStatement/BlockStatement[@CurlyBrace='false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
while (true) // not recommended
x++;
while (true) { // preferred approach
x++;
}
]]>
</example>
</rule>
</ruleset>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<ruleset name="Documentation"
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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules that are related to code documentation.
</description>
</ruleset>

View File

@ -0,0 +1,243 @@
<?xml version="1.0"?>
<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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors.
</description>
<rule name="AvoidDirectAccessTriggerMap"
since="6.0.0"
message="Avoid directly accessing Trigger.old and Trigger.new"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
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 | //ArrayLoadExpression/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.
foreach ( Account a : Trigger.new ){
//Good: Iterate through the trigger.new array instead.
}
}
]]>
</example>
</rule>
<rule name="EmptyCatchBlock"
language="apex"
since="6.0.0"
message="Avoid empty catch blocks"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
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="xpath">
<value>
<![CDATA[
//CatchBlockStatement[./BlockStatement[count(*) = 0]]
]]>
</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.apex.rule.ApexXPathRule"
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.apex.rule.ApexXPathRule"
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="xpath">
<value>
<![CDATA[
//Method/ModifierNode[@Abstract!='true' and ../BlockStatement[count(*) = 0]]
| //Method/BlockStatement//BlockStatement[count(*) = 0]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class Foo {
private int _bar;
public void setBar(int 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.apex.rule.ApexXPathRule"
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 {
int 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.apex.rule.ApexXPathRule"
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="MethodWithSameNameAsEnclosingClass"
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.style.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>
</ruleset>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<ruleset name="Multithreading"
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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules that flag issues when dealing with multiple threads of execution.
</description>
</ruleset>

View File

@ -0,0 +1,80 @@
<?xml version="1.0"?>
<ruleset name="Performance"
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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules that flag suboptimal code.
</description>
<rule name="AvoidDmlStatementsInLoops"
since="5.5.0"
message="Avoid DML statements inside loops"
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidDmlStatementsInLoopsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoiddmlstatementsinloops">
<description>
Avoid DML statements inside loops to avoid hitting the DML governor limit. Instead, try to batch up the data into a list and invoke your DML once on that list of data outside the loop.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Something {
public void foo() {
for (Integer i = 0; i < 151; i++) {
Account account;
// ...
insert account;
}
}
}
]]>
</example>
</rule>
<rule name="AvoidSoqlInLoops"
since="5.5.0"
message="Avoid Soql queries inside loops"
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoqlInLoopsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoidsoqlinloops">
<description>
New objects created within loops should be checked to see if they can created outside them and reused.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Something {
public static void main( String as[] ) {
for (Integer i = 0; i < 10; i++) {
List<Account> accounts = [SELECT Id FROM Account];
}
}
}
]]>
</example>
</rule>
<rule name="AvoidSoslInLoops"
since="6.0.0"
message="Avoid Sosl queries inside loops"
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoslInLoopsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoidsoslinloops">
<description>
Sosl calls within loops can cause governor limit exceptions.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Something {
public static void main( String as[] ) {
for (Integer i = 0; i < 10; i++) {
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
}
}
}
]]>
</example>
</rule>
</ruleset>

View File

@ -0,0 +1,274 @@
<?xml version="1.0"?>
<ruleset name="Security"
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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Rules that flag potential security flaws.
</description>
<rule name="ApexBadCrypto"
since="5.5.3"
message="Apex classes should use random IV/key"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexBadCryptoRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexbadcrypto">
<description>
The rule makes sure you are using randomly generated IVs and keys for `Crypto` calls.
Hard-wiring these values greatly compromises the security of encrypted data.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
Blob hardCodedIV = Blob.valueOf('Hardcoded IV 123');
Blob hardCodedKey = Blob.valueOf('0000000000000000');
Blob data = Blob.valueOf('Data to be encrypted');
Blob encrypted = Crypto.encrypt('AES128', hardCodedKey, hardCodedIV, data);
}
]]>
</example>
</rule>
<rule name="ApexCRUDViolation"
since="5.5.3"
message="Validate CRUD permission before SOQL/DML operation"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexCRUDViolationRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexcrudviolation">
<description>
The rule validates you are checking for access permissions before a SOQL/SOSL/DML operation.
Since Apex runs in system mode not having proper permissions checks results in escalation of
privilege and may produce runtime errors. This check forces you to handle such scenarios.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public Contact foo(String status, String ID) {
Contact c = [SELECT Status__c FROM Contact WHERE Id=:ID];
// Make sure we can update the database before even trying
if (!Schema.sObjectType.Contact.fields.Name.isUpdateable()) {
return null;
}
c.Status__c = status;
update c;
return c;
}
}
]]>
</example>
</rule>
<rule name="ApexCSRF"
since="5.5.3"
message="Avoid making DML operations in Apex class constructor/init method"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexCSRFRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexcsrf">
<description>
Check to avoid making DML operations in Apex class constructor/init method. This prevents
modification of the database just by accessing a page.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public init() {
insert data;
}
public Foo() {
insert data;
}
}
]]>
</example>
</rule>
<rule name="ApexDangerousMethods"
since="5.5.3"
message="Calling potentially dangerous method"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexDangerousMethodsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexdangerousmethods">
<description>
Checks against calling dangerous methods.
For the time being, it reports:
* Against `FinancialForce`'s `Configuration.disableTriggerCRUDSecurity()`. Disabling CRUD security
opens the door to several attacks and requires manual validation, which is unreliable.
* Calling `System.debug` passing sensitive data as parameter, which could lead to exposure
of private data.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public Foo() {
Configuration.disableTriggerCRUDSecurity();
}
}
]]>
</example>
</rule>
<rule name="ApexInsecureEndpoint"
since="5.5.3"
message="Apex callouts should use encrypted communication channels"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexInsecureEndpointRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexinsecureendpoint">
<description>
Checks against accessing endpoints under plain **http**. You should always use
**https** for security.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
void foo() {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://localhost:com');
}
}
]]>
</example>
</rule>
<rule name="ApexOpenRedirect"
since="5.5.3"
message="Apex classes should safely redirect to a known location"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexOpenRedirectRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexopenredirect">
<description>
Checks against redirects to user-controlled locations. This prevents attackers from
redirecting users to phishing sites.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
String unsafeLocation = ApexPage.getCurrentPage().getParameters.get('url_param');
PageReference page() {
return new PageReference(unsafeLocation);
}
}
]]>
</example>
</rule>
<rule name="ApexSharingViolations"
since="5.5.3"
message="Apex classes should declare a sharing model if DML or SOQL/SOSL is used"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexSharingViolationsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexsharingviolations">
<description>
Detect classes declared without explicit sharing mode if DML methods are used. This
forces the developer to take access restrictions into account before modifying objects.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
// DML operation here
}
]]>
</example>
</rule>
<rule name="ApexSOQLInjection"
since="5.5.3"
message="Avoid untrusted/unescaped variables in DML query"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexSOQLInjectionRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexsoqlinjection">
<description>
Detects the usage of untrusted / unescaped variables in DML queries.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public void test1(String t1) {
Database.query('SELECT Id FROM Account' + t1);
}
}
]]>
</example>
</rule>
<rule name="ApexSuggestUsingNamedCred"
since="5.5.3"
message="Suggest named credentials for authentication"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexSuggestUsingNamedCredRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexsuggestusingnamedcred">
<description>
Detects hardcoded credentials used in requests to an endpoint.
You should refrain from hardcoding credentials:
* They are hard to mantain by being mixed in application code
* Particularly hard to update them when used from different classes
* Granting a developer access to the codebase means granting knowledge
of credentials, keeping a two-level access is not possible.
* Using different credentials for different environments is troublesome
and error-prone.
Instead, you should use *Named Credentials* and a callout endpoint.
For more information, you can check [this](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_named_credentials.htm)
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public void foo(String username, String password) {
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
}
}
]]>
</example>
</rule>
<rule name="ApexXSSFromEscapeFalse"
since="5.5.3"
message="Apex classes should escape Strings in error messages"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexXSSFromEscapeFalseRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexxssfromescapefalse">
<description>
Reports on calls to `addError` with disabled escaping. The message passed to `addError`
will be displayed directly to the user in the UI, making it prime ground for XSS
attacks if unescaped.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
Trigger.new[0].addError(vulnerableHTMLGoesHere, false);
}
]]>
</example>
</rule>
<rule name="ApexXSSFromURLParam"
since="5.5.3"
message="Apex classes should escape/sanitize Strings obtained from URL parameters"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexXSSFromURLParamRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexxssfromurlparam">
<description>
Makes sure that all values obtained from URL parameters are properly escaped / sanitized
to avoid XSS attacks.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
String unescapedstring = ApexPage.getCurrentPage().getParameters.get('url_param');
String usedLater = unescapedstring;
}
]]>
</example>
</rule>
</ruleset>

View File

@ -8,51 +8,7 @@
These rules deal with different problems that can occur with Apex unit tests.
</description>
<rule name="ApexUnitTestClassShouldHaveAsserts"
since="5.5.1"
message="Apex unit tests should System.assert() or assertEquals() or assertNotEquals()"
class="net.sourceforge.pmd.lang.apex.rule.apexunit.ApexUnitTestClassShouldHaveAssertsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_apexunit.html#apexunittestclassshouldhaveasserts">
<description>
Apex unit tests should include at least one assertion. This makes the tests more robust, and using assert
with messages provide the developer a clearer idea of what the test does.
</description>
<priority>3</priority>
<example>
<![CDATA[
@isTest
public class Foo {
public static testMethod void testSomething() {
Account a = null;
// This is better than having a NullPointerException
// System.assertNotEquals(a, null, 'account not found');
a.toString();
}
}
]]>
</example>
</rule>
<rule name="ApexUnitTestShouldNotUseSeeAllDataTrue"
since="5.5.1"
message="Apex unit tests should not use @isTest(seeAllData = true)"
class="net.sourceforge.pmd.lang.apex.rule.apexunit.ApexUnitTestShouldNotUseSeeAllDataTrueRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_apexunit.html#apexunittestshouldnotuseseealldatatrue">
<description>
Apex unit tests should not use @isTest(seeAllData=true) because it opens up the existing database data for unexpected modification by tests.
</description>
<priority>3</priority>
<example>
<![CDATA[
@isTest(seeAllData = true)
public class Foo {
public static testMethod void testSomething() {
Account a = null;
// This is better than having a NullPointerException
// System.assertNotEquals(a, null, 'account not found');
a.toString();
}
}
]]>
</example>
</rule>
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts" deprecated="true" />
<rule ref="category/apex/bestpractices.xml/ApexUnitTestShouldNotUseSeeAllDataTrue" deprecated="true" />
</ruleset>

View File

@ -8,142 +8,9 @@
The Braces ruleset contains rules regarding the use and placement of braces.
</description>
<rule name="IfStmtsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using if statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_braces.html#ifstmtsmustusebraces">
<description>
Avoid using if statements without using braces to surround the code block. If the code
formatting or indentation is lost then it becomes difficult to separate the code being
controlled from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//IfBlockStatement/BlockStatement[@CurlyBrace='false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
if (foo) // not recommended
x++;
if (foo) { // preferred approach
x++;
}
]]>
</example>
</rule>
<rule name="WhileLoopsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using 'while' statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_braces.html#whileloopsmustusebraces">
<description>
Avoid using 'while' statements without using braces to surround the code block. If the code
formatting or indentation is lost then it becomes difficult to separate the code being
controlled from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//WhileLoopStatement/BlockStatement[@CurlyBrace='false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
while (true) // not recommended
x++;
while (true) { // preferred approach
x++;
}
]]>
</example>
</rule>
<rule name="IfElseStmtsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using 'if...else' statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_braces.html#ifelsestmtsmustusebraces">
<description>
Avoid using if..else statements without using surrounding braces. If the code formatting
or indentation is lost then it becomes difficult to separate the code being controlled
from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//IfBlockStatement/BlockStatement[@CurlyBrace='false'][count(child::*) > 0]
|
//IfElseBlockStatement/BlockStatement[@CurlyBrace='false'][count(child::*) > 0]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
// this is OK
if (foo) x++;
// but this is not
if (foo)
x = x+1;
else
x = x-1;
]]>
</example>
</rule>
<rule name="ForLoopsMustUseBraces"
language="apex"
since="5.6.0"
message="Avoid using 'for' statements without curly braces"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_braces.html#forloopsmustusebraces">
<description>
Avoid using 'for' statements without using surrounding braces. If the code formatting or
indentation is lost then it becomes difficult to separate the code being controlled
from the rest.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//ForLoopStatement/BlockStatement[@CurlyBrace='false']
|
//ForEachStatement/BlockStatement[@CurlyBrace='false']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
for (int i = 0; i < 42; i++) // not recommended
foo();
for (int i = 0; i < 42; i++) { // preferred approach
foo();
}
]]>
</example>
</rule>
<rule ref="category/apex/codestyle.xml/IfElseStmtsMustUseBraces" deprecated="true" />
<rule ref="category/apex/codestyle.xml/IfStmtsMustUseBraces" deprecated="true" />
<rule ref="category/apex/codestyle.xml/ForLoopsMustUseBraces" deprecated="true" />
<rule ref="category/apex/codestyle.xml/WhileLoopsMustUseBraces" deprecated="true" />
</ruleset>

View File

@ -8,283 +8,14 @@
The Complexity ruleset contains rules that find problems related to code size or complexity.
</description>
<rule name="AvoidDeeplyNestedIfStmts"
since="5.5.0"
message="Deeply nested if..then statements are hard to read"
class="net.sourceforge.pmd.lang.apex.rule.complexity.AvoidDeeplyNestedIfStmtsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#avoiddeeplynestedifstmts">
<description>
Avoid creating deeply nested if-then statements since they are harder to read and error-prone to maintain.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public void bar(Integer x, Integer y, Integer z) {
if (x>y) {
if (y>z) {
if (z==x) {
// !! too deep
}
}
}
}
}
]]>
</example>
</rule>
<rule name="ExcessiveParameterList"
since="5.5.0"
message="Avoid long parameter lists."
class="net.sourceforge.pmd.lang.apex.rule.complexity.ExcessiveParameterListRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#excessiveparameterlist">
<description>
Methods with numerous parameters are a challenge to maintain, especially if most of them share the
same datatype. These situations usually denote the need for new objects to wrap the numerous parameters.
</description>
<priority>3</priority>
<example>
<![CDATA[
// too many arguments liable to be mixed up
public void addPerson(int birthYear, int birthMonth, int birthDate, int height, int weight, int ssn) {
// ...
}
// preferred approach
public void addPerson(Date birthdate, BodyMeasurements measurements, int ssn) {
// ...
}
]]>
</example>
</rule>
<rule name="ExcessiveClassLength"
since="5.5.0"
message="Avoid really long classes."
class="net.sourceforge.pmd.lang.apex.rule.complexity.ExcessiveClassLengthRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#excessiveclasslength">
<description>
Excessive class file lengths are usually indications that the class may be burdened with excessive
responsibilities that could be provided by external classes or functions. In breaking these methods
apart the code becomes more managable and ripe for reuse.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public void bar1() {
// 1000 lines of code
}
public void bar2() {
// 1000 lines of code
}
public void bar3() {
// 1000 lines of code
}
public void barN() {
// 1000 lines of code
}
}
]]>
</example>
</rule>
<rule name="NcssMethodCount"
since="5.5.0"
message="The method ''{0}()'' has an NCSS line count of {1}"
class="net.sourceforge.pmd.lang.apex.rule.complexity.NcssMethodCountRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#ncssmethodcount">
<description>
This rule uses the NCSS (Non-Commenting Source Statements) algorithm to determine the number of lines
of code for a given method. NCSS ignores comments, and counts actual statements. Using this algorithm,
lines of code that are split are counted as one.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo extends Bar {
//this method only has 1 NCSS lines
public Integer methd() {
super.methd();
return 1;
}
}
]]>
</example>
</rule>
<rule name="NcssTypeCount"
since="5.5.0"
message="The type has an NCSS line count of {0}"
class="net.sourceforge.pmd.lang.apex.rule.complexity.NcssTypeCountRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#ncsstypecount">
<description>
This rule uses the NCSS (Non-Commenting Source Statements) algorithm to determine the number of lines
of code for a given type. NCSS ignores comments, and counts actual statements. Using this algorithm,
lines of code that are split are counted as one.
</description>
<priority>3</priority>
<example>
<![CDATA[
//this class only has 6 NCSS lines
public class Foo extends Bar {
public Foo() {
super();
super.foo();
}
}
]]>
</example>
</rule>
<rule name="NcssConstructorCount"
since="5.5.0"
message="The constructor has an NCSS line count of {0}"
class="net.sourceforge.pmd.lang.apex.rule.complexity.NcssConstructorCountRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#ncssconstructorcount">
<description>
This rule uses the NCSS (Non-Commenting Source Statements) algorithm to determine the number of lines
of code for a given constructor. NCSS ignores comments, and counts actual statements. Using this algorithm,
lines of code that are split are counted as one.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo extends Bar {
//this constructor only has 1 NCSS lines
public Foo() {
super();
super.foo();
}
}
]]>
</example>
</rule>
<rule name="StdCyclomaticComplexity"
since="5.5.0"
message="The {0} ''{1}'' has a Standard Cyclomatic Complexity of {2}."
class="net.sourceforge.pmd.lang.apex.rule.complexity.StdCyclomaticComplexityRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#stdcyclomaticcomplexity">
<description>
Complexity directly affects maintenance costs is determined by the number of decision points in a method
plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls.
Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote
high complexity, and 11+ is very high complexity.
</description>
<priority>3</priority>
<example>
<![CDATA[
// This has a Cyclomatic Complexity = 12
public class Foo {
1 public void example() {
2 if (a == b || (c == d && e == f)) {
3 if (a1 == b1) {
fiddle();
4 } else if a2 == b2) {
fiddle();
} else {
fiddle();
}
5 } else if (c == d) {
6 while (c == d) {
fiddle();
}
7 } else if (e == f) {
8 for (int n = 0; n < h; n++) {
fiddle();
}
} else {
switch (z) {
9 case 1:
fiddle();
break;
10 case 2:
fiddle();
break;
11 case 3:
fiddle();
break;
12 default:
fiddle();
break;
}
}
}
]]>
</example>
</rule>
<rule name="TooManyFields"
since="5.5.0"
message="Too many fields"
class="net.sourceforge.pmd.lang.apex.rule.complexity.TooManyFieldsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#toomanyfields">
<description>
Classes that have too many fields can become unwieldy and could be redesigned to have fewer fields,
possibly through grouping related fields in new objects. For example, a class with individual
city/state/zip fields could park them within a single Address field.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Person {
// too many separate fields
int birthYear;
int birthMonth;
int birthDate;
float height;
float weight;
}
public class Person {
// this is more manageable
Date birthDate;
BodyMeasurements measurements;
}
]]>
</example>
</rule>
<rule name="ExcessivePublicCount"
since="5.5.0"
message="This class has a bunch of public methods and attributes"
class="net.sourceforge.pmd.lang.apex.rule.complexity.ExcessivePublicCountRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_complexity.html#excessivepubliccount">
<description>
Classes with large numbers of public methods and attributes require disproportionate testing efforts
since combinational side effects grow rapidly and increase risk. Refactoring these classes into
smaller ones not only increases testability and reliability but also allows new variations to be
developed easily.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public String value;
public Bar something;
public Variable var;
// [... more more public attributes ...]
public void doWork() {}
public void doMoreWork() {}
public void doWorkAgain() {}
// [... more more public methods ...]
}
]]>
</example>
</rule>
<rule ref="category/apex/design.xml/AvoidDeeplyNestedIfStmts" deprecated="true" />
<rule ref="category/apex/design.xml/ExcessiveClassLength" deprecated="true" />
<rule ref="category/apex/design.xml/ExcessiveParameterList" deprecated="true" />
<rule ref="category/apex/design.xml/ExcessivePublicCount" deprecated="true" />
<rule ref="category/apex/design.xml/NcssConstructorCount" deprecated="true" />
<rule ref="category/apex/design.xml/NcssMethodCount" deprecated="true" />
<rule ref="category/apex/design.xml/NcssTypeCount" deprecated="true" />
<rule ref="category/apex/design.xml/StdCyclomaticComplexity" deprecated="true" />
<rule ref="category/apex/design.xml/TooManyFields" deprecated="true" />
</ruleset>

View File

@ -9,184 +9,10 @@ The Empty Code ruleset contains rules that find empty statements of any kind (em
empty block statement, empty try or catch block,...).
</description>
<rule name="EmptyCatchBlock"
language="apex"
since="6.0.0"
message="Avoid empty catch blocks"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_empty.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="xpath">
<value>
<![CDATA[
//CatchBlockStatement[./BlockStatement[count(*) = 0]]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public void doSomething() {
...
try {
insert accounts;
} catch (DmlException dmle) {
// not good
}
}
]]>
</example>
</rule>
<rule ref="category/apex/errorprone.xml/EmptyCatchBlock" deprecated="true" />
<rule ref="category/apex/errorprone.xml/EmptyIfStmt" deprecated="true" />
<rule ref="category/apex/errorprone.xml/EmptyStatementBlock" deprecated="true" />
<rule ref="category/apex/errorprone.xml/EmptyTryOrFinallyBlock" deprecated="true" />
<rule ref="category/apex/errorprone.xml/EmptyWhileStmt" deprecated="true" />
<rule name="EmptyIfStmt"
language="apex"
since="6.0.0"
message="Avoid empty 'if' statements"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_empty.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="EmptyTryOrFinallyBlock"
language="apex"
since="6.0.0"
message="Avoid empty try or finally blocks"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_empty.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 {
int 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.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_empty.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="EmptyStatementBlock"
language="apex"
since="6.0.0"
message="Avoid empty block statements."
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_empty.html#emptystatementblock">
<description>
Empty block statements serve no purpose and should be removed.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//Method/ModifierNode[@Abstract!='true' and ../BlockStatement[count(*) = 0]]
| //Method/BlockStatement//BlockStatement[count(*) = 0]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class Foo {
private int _bar;
public void setBar(int bar) {
// empty
}
}
]]>
</example>
</rule>
</ruleset>

View File

@ -9,57 +9,5 @@
These are rules which use the Metrics Framework to calculate metrics.
</description>
<rule name="CyclomaticComplexity"
message="The {0} ''{1}'' has a{2} cyclomatic complexity of {3}."
since="6.0.0"
class="net.sourceforge.pmd.lang.apex.metrics.rule.CyclomaticComplexityRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_metrics.html#cyclomaticcomplexity">
<description>
<![CDATA[
The complexity of methods directly affects maintenance costs and readability. Concentrating too much decisional logic
in a single method makes its behaviour hard to read and change.
Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method,
plus one for the method entry. Decision points are places where the control flow jumps to another place in the
program. As such, they include all control flow statements, such as 'if', 'while', 'for', and 'case'.
Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote
high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10.
Additionnally, classes with many methods of moderate complexity get reported as well once the total of their
methods' complexities reaches 40, even if none of the methods was directly reported.
Reported methods should be broken down into several smaller methods. Reported classes should probably be broken down
into subcomponents.
]]>
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Complicated {
public void example() { // This method has a cyclomatic complexity of 12
int x = 0, y = 1, z = 2, t = 2;
boolean a = false, b = true, c = false, d = true;
if (a && b || b && d) {
if (y == z) {
x = 2;
} else if (y == t && !d) {
x = 2;
} else {
x = 2;
}
} else if (c && d) {
while (z < y) {
x = 2;
}
} else {
for (int n = 0; n < t; n++) {
x = 2;
}
}
}
}
]]>
</example>
</rule>
<rule ref="category/apex/design.xml/CyclomaticComplexity" deprecated="true" />
</ruleset>

View File

@ -8,72 +8,8 @@
The Performance ruleset contains a collection of good practices which should be followed.
</description>
<rule name="AvoidSoqlInLoops"
since="5.5.0"
message="Avoid Soql queries inside loops"
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoqlInLoopsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoidsoqlinloops">
<description>
New objects created within loops should be checked to see if they can created outside them and reused.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Something {
public static void main( String as[] ) {
for (Integer i = 0; i < 10; i++) {
List<Account> accounts = [SELECT Id FROM Account];
}
}
}
]]>
</example>
</rule>
<rule name="AvoidSoslInLoops"
since="6.0.0"
message="Avoid Sosl queries inside loops"
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoslInLoopsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoidsoslinloops">
<description>
Sosl calls within loops can cause governor limit exceptions.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Something {
public static void main( String as[] ) {
for (Integer i = 0; i < 10; i++) {
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
}
}
}
]]>
</example>
</rule>
<rule name="AvoidDmlStatementsInLoops"
since="5.5.0"
message="Avoid DML statements inside loops"
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidDmlStatementsInLoopsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoiddmlstatementsinloops">
<description>
Avoid DML statements inside loops to avoid hitting the DML governor limit. Instead, try to batch up the data into a list and invoke your DML once on that list of data outside the loop.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Something {
public void foo() {
for (Integer i = 0; i < 151; i++) {
Account account;
// ...
insert account;
}
}
}
]]>
</example>
</rule>
<rule ref="category/apex/performance.xml/AvoidDmlStatementsInLoops" deprecated="true" />
<rule ref="category/apex/performance.xml/AvoidSoqlInLoops" deprecated="true" />
<rule ref="category/apex/performance.xml/AvoidSoslInLoops" deprecated="true" />
</ruleset>

View File

@ -3,10 +3,15 @@
#
rulesets.filenames=\
rulesets/apex/apexunit.xml,\
rulesets/apex/braces.xml,\
rulesets/apex/complexity.xml,\
rulesets/apex/empty.xml,\
rulesets/apex/performance.xml,\
rulesets/apex/security.xml,\
rulesets/apex/style.xml
category/apex/bestpractices.xml,\
category/apex/codestyle.xml,\
category/apex/design.xml,\
category/apex/errorprone.xml,\
category/apex/performance.xml,\
category/apex/security.xml
#
# categories with no rules yet
#
#category/apex/documentation.xml
#category/apex/multithreading.xml

View File

@ -8,268 +8,16 @@
These rules deal with different security problems that can occur within Apex.
</description>
<rule name="ApexSharingViolations"
since="5.5.3"
message="Apex classes should declare a sharing model if DML or SOQL/SOSL is used"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexSharingViolationsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexsharingviolations">
<description>
Detect classes declared without explicit sharing mode if DML methods are used. This
forces the developer to take access restrictions into account before modifying objects.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
// DML operation here
}
]]>
</example>
</rule>
<rule name="ApexOpenRedirect"
since="5.5.3"
message="Apex classes should safely redirect to a known location"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexOpenRedirectRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexopenredirect">
<description>
Checks against redirects to user-controlled locations. This prevents attackers from
redirecting users to phishing sites.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
String unsafeLocation = ApexPage.getCurrentPage().getParameters.get('url_param');
PageReference page() {
return new PageReference(unsafeLocation);
}
}
]]>
</example>
</rule>
<rule name="ApexInsecureEndpoint"
since="5.5.3"
message="Apex callouts should use encrypted communication channels"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexInsecureEndpointRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexinsecureendpoint">
<description>
Checks against accessing endpoints under plain **http**. You should always use
**https** for security.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
void foo() {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://localhost:com');
}
}
]]>
</example>
</rule>
<rule name="ApexXSSFromURLParam"
since="5.5.3"
message="Apex classes should escape/sanitize Strings obtained from URL parameters"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexXSSFromURLParamRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexxssfromurlparam">
<description>
Makes sure that all values obtained from URL parameters are properly escaped / sanitized
to avoid XSS attacks.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
String unescapedstring = ApexPage.getCurrentPage().getParameters.get('url_param');
String usedLater = unescapedstring;
}
]]>
</example>
</rule>
<rule name="ApexXSSFromEscapeFalse"
since="5.5.3"
message="Apex classes should escape Strings in error messages"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexXSSFromEscapeFalseRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexxssfromescapefalse">
<description>
Reports on calls to `addError` with disabled escaping. The message passed to `addError`
will be displayed directly to the user in the UI, making it prime ground for XSS
attacks if unescaped.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
Trigger.new[0].addError(vulnerableHTMLGoesHere, false);
}
]]>
</example>
</rule>
<rule name="ApexBadCrypto"
since="5.5.3"
message="Apex classes should use random IV/key"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexBadCryptoRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexbadcrypto">
<description>
The rule makes sure you are using randomly generated IVs and keys for `Crypto` calls.
Hard-wiring these values greatly compromises the security of encrypted data.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
Blob hardCodedIV = Blob.valueOf('Hardcoded IV 123');
Blob hardCodedKey = Blob.valueOf('0000000000000000');
Blob data = Blob.valueOf('Data to be encrypted');
Blob encrypted = Crypto.encrypt('AES128', hardCodedKey, hardCodedIV, data);
}
]]>
</example>
</rule>
<rule name="ApexCSRF"
since="5.5.3"
message="Avoid making DML operations in Apex class constructor/init method"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexCSRFRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexcsrf">
<description>
Check to avoid making DML operations in Apex class constructor/init method. This prevents
modification of the database just by accessing a page.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public init() {
insert data;
}
public Foo() {
insert data;
}
}
]]>
</example>
</rule>
<rule name="ApexSOQLInjection"
since="5.5.3"
message="Avoid untrusted/unescaped variables in DML query"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexSOQLInjectionRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexsoqlinjection">
<description>
Detects the usage of untrusted / unescaped variables in DML queries.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public void test1(String t1) {
Database.query('SELECT Id FROM Account' + t1);
}
}
]]>
</example>
</rule>
<rule name="ApexCRUDViolation"
since="5.5.3"
message="Validate CRUD permission before SOQL/DML operation"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexCRUDViolationRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexcrudviolation">
<description>
The rule validates you are checking for access permissions before a SOQL/SOSL/DML operation.
Since Apex runs in system mode not having proper permissions checks results in escalation of
privilege and may produce runtime errors. This check forces you to handle such scenarios.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public Contact foo(String status, String ID) {
Contact c = [SELECT Status__c FROM Contact WHERE Id=:ID];
// Make sure we can update the database before even trying
if (!Schema.sObjectType.Contact.fields.Name.isUpdateable()) {
return null;
}
c.Status__c = status;
update c;
return c;
}
}
]]>
</example>
</rule>
<rule name="ApexDangerousMethods"
since="5.5.3"
message="Calling potentially dangerous method"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexDangerousMethodsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexdangerousmethods">
<description><![CDATA[
Checks against calling dangerous methods.
For the time being, it reports:
* Against `FinancialForce`'s `Configuration.disableTriggerCRUDSecurity()`. Disabling CRUD security
opens the door to several attacks and requires manual validation, which is unreliable.
* Calling `System.debug` passing sensitive data as parameter, which could lead to exposure
of private data.
]]>
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public Foo() {
Configuration.disableTriggerCRUDSecurity();
}
}
]]>
</example>
</rule>
<rule name="ApexSuggestUsingNamedCred"
since="5.5.3"
message="Suggest named credentials for authentication"
class="net.sourceforge.pmd.lang.apex.rule.security.ApexSuggestUsingNamedCredRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#apexsuggestusingnamedcred">
<description><![CDATA[
Detects hardcoded credentials used in requests to an endpoint.
You should refrain from hardcoding credentials:
* They are hard to mantain by being mixed in application code
* Particularly hard to update them when used from different classes
* Granting a developer access to the codebase means granting knowledge
of credentials, keeping a two-level access is not possible.
* Using different credentials for different environments is troublesome
and error-prone.
Instead, you should use *Named Credentials* and a callout endpoint.
For more information, you can check [this](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_named_credentials.htm)
]]>
</description>
<priority>3</priority>
<example>
<![CDATA[
public class Foo {
public void foo(String username, String password) {
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
}
}
]]>
</example>
</rule>
<rule ref="category/apex/security.xml/ApexBadCrypto" deprecated="true" />
<rule ref="category/apex/security.xml/ApexCRUDViolation" deprecated="true" />
<rule ref="category/apex/security.xml/ApexCSRF" deprecated="true" />
<rule ref="category/apex/security.xml/ApexDangerousMethods" deprecated="true" />
<rule ref="category/apex/security.xml/ApexInsecureEndpoint" deprecated="true" />
<rule ref="category/apex/security.xml/ApexOpenRedirect" deprecated="true" />
<rule ref="category/apex/security.xml/ApexSharingViolations" deprecated="true" />
<rule ref="category/apex/security.xml/ApexSOQLInjection" deprecated="true" />
<rule ref="category/apex/security.xml/ApexSuggestUsingNamedCred" deprecated="true" />
<rule ref="category/apex/security.xml/ApexXSSFromEscapeFalse" deprecated="true" />
<rule ref="category/apex/security.xml/ApexXSSFromURLParam" deprecated="true" />
</ruleset>

View File

@ -8,193 +8,15 @@
The Style Ruleset contains rules regarding preferred usage of names and identifiers.
</description>
<rule name="VariableNamingConventions"
since="5.5.0"
message="{0} variable {1} should begin with {2}"
class="net.sourceforge.pmd.lang.apex.rule.style.VariableNamingConventionsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.html#variablenamingconventions">
<description>
A variable naming conventions rule - customize this to your liking. Currently, it
checks for final variables that should be fully capitalized and non-final variables
that should not include underscores.
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {
public static final Integer MY_NUM = 0;
public String myTest = '';
DataModule dmTest = new DataModule();
}
]]>
</example>
</rule>
<rule ref="category/apex/codestyle.xml/ClassNamingConventions" deprecated="true" />
<rule ref="category/apex/codestyle.xml/MethodNamingConventions" deprecated="true" />
<rule ref="category/apex/codestyle.xml/VariableNamingConventions" deprecated="true" />
<rule name="MethodNamingConventions"
since="5.5.0"
message="Method name does not begin with a lower case character."
class="net.sourceforge.pmd.lang.apex.rule.style.MethodNamingConventionsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.html#methodnamingconventions">
<description>
Method names should always begin with a lower case character, and should not contain underscores.
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {
public void fooStuff() {
}
}
]]>
</example>
</rule>
<rule ref="category/apex/errorprone.xml/AvoidDirectAccessTriggerMap" deprecated="true" />
<rule ref="category/apex/errorprone.xml/MethodWithSameNameAsEnclosingClass" deprecated="true" />
<rule name="ClassNamingConventions"
since="5.5.0"
message="Class names should begin with an uppercase character"
class="net.sourceforge.pmd.lang.apex.rule.style.ClassNamingConventionsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.html#classnamingconventions">
<description>
Class names should always begin with an upper case character.
</description>
<priority>1</priority>
<example>
<![CDATA[
public class Foo {}
]]>
</example>
</rule>
<rule name="MethodWithSameNameAsEnclosingClass"
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.style.MethodWithSameNameAsEnclosingClassRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.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="AvoidLogicInTrigger"
since="5.5.0"
message="Avoid logic in triggers"
class="net.sourceforge.pmd.lang.apex.rule.style.AvoidLogicInTriggerRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.html#avoidlogicintrigger">
<description>
As triggers do not allow methods like regular classes they are less flexible and suited to apply good encapsulation style.
Therefore delegate the triggers work to a regular class (often called Trigger handler class).
See more here: https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices
</description>
<priority>3</priority>
<example>
<![CDATA[
trigger Accounts on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
for(Account acc : Trigger.new) {
if(Trigger.isInsert) {
// ...
}
// ...
if(Trigger.isDelete) {
// ...
}
}
}
]]>
</example>
</rule>
<rule name="AvoidGlobalModifier"
since="5.5.0"
message="Avoid using global modifier"
class="net.sourceforge.pmd.lang.apex.rule.style.AvoidGlobalModifierRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.html#avoidglobalmodifier">
<description>
Global classes should be avoided (especially in managed packages) as they can never be deleted or changed in signature. Always check twice if something needs to be global.
Many interfaces (e.g. Batch) required global modifiers in the past but don't require this anymore. Don't lock yourself in.
</description>
<priority>3</priority>
<example>
<![CDATA[
global class Unchangeable {
global UndeletableType unchangable(UndeletableType param) {
// ...
}
}
]]>
</example>
</rule>
<rule name="AvoidDirectAccessTriggerMap"
since="6.0.0"
message="Avoid directly accessing Trigger.old and Trigger.new"
class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.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 | //ArrayLoadExpression/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.
foreach ( Account a : Trigger.new ){
//Good: Iterate through the trigger.new array instead.
}
}
]]>
</example>
</rule>
<rule name="AvoidHardcodingId"
since="6.0.0"
message="Hardcoding Id's is bound to break when changing environments."
class="net.sourceforge.pmd.lang.apex.rule.style.AvoidHardcodingIdRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_style.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 ref="category/apex/bestpractices.xml/AvoidGlobalModifier" deprecated="true" />
<rule ref="category/apex/bestpractices.xml/AvoidLogicInTrigger" deprecated="true" />
<rule ref="category/apex/bestpractices.xml/AvoidHardcodingId" deprecated="true" />
</ruleset>