Appendix F.6: Standards and Rules Cross-Reference¶
A standard is the plain statement of what matters. A rule is an implementation that enforces it. The two belong together, as the principle Every Rule Has a Standard, and Every Standard Has a Rule Where One Is Possible sets out. This page ties them together in both directions for the rules in this reference, so that a reader can go from a standard to the rules that enforce it, and from a rule to the standards it serves.
The page has two parts:
- Rules and Their Standards lists each rule that a standards page mentions, with its standard in one line and a link to every section that mentions it.
- Rules Without a Written Standard lists the rules that are in the reference rulesets but that no standards page mentions yet.
The reference uses rules of its own (custom PMD XPath, custom PMD Java, and custom Code Analyzer regex rules), stock PMD rules, and stock Code Analyzer rules. Those that a standards page mentions are listed first, with their standards, and the others under Rules Without a Written Standard.
Rules and Their Standards¶
Each rule that a standards page mentions, with its standard and every section that mentions it, most severe first.
| Rule | Kind | Severity | Standard | Where it is mentioned |
|---|---|---|---|---|
Abstract |
Custom PMD XPath | 1 | An abstract class declares a method or a constructor | Apex: Abstract Classes |
Annotations |
Stock PMD | 1 | Write annotations in Pascal case: @IsTest, not @isTest |
General: Apex |
Apex |
Stock PMD | 1 | Generate encryption keys and initialisation vectors; never write them into the code | Apex: Cookies and Cryptography |
ApexCSRF |
Stock PMD | 1 | Code that runs when a page loads changes no data: no DML in a constructor, an initializer block, or an init method |
Apex: Cross-Site Request Forgery |
Apex |
Stock PMD | 1 | Do not set the Authorization header directly; use a Named Credential |
Apex: Callouts |
Avoid |
Stock Code Analyzer PMD | 1 | Every Aura component is at API version 40.0 or later | Lightning Web Components and Aura: Aura |
Avoid |
Stock Code Analyzer PMD | 1 | No password is written into a call to System.setPassword |
Apex: Hard-Coded Credentials |
Avoid |
Custom PMD XPath | 1 | No record ID is written into a Flow | Automation: Hard-Coded Values Automation: Standards Not Adopted |
Avoid |
Custom PMD XPath | 1 | A Visualforce link does not point to a hard-coded record Id | HTML and Visualforce: Resources and Links |
Avoid |
Custom PMD XPath | 1 | No IP address is written into Apex; read it from a Named Credential, custom metadata, or a custom setting | Apex: Hard-Coded IP Addresses |
Avoid |
Custom PMD XPath | 1 | No endpoint in integration metadata is an IP address | Integration: Endpoints |
Avoid |
Stock PMD | 1 | No record ID is written into Apex; find the record by DeveloperName, an external ID, or a name |
Apex: Record IDs |
Avoid |
Stock Code Analyzer PMD | 1 | No s-control is committed; rebuild it as a Visualforce page or a Lightning web component | User Interface: S-Controls |
Class |
Stock PMD | 1 | Class, interface, and enum names are in Pascal case | General: Apex Metadata Standards: Naming |
Cyclic |
Stock Code Analyzer Flow | 1 | No subflow calls, directly or through a chain, a Flow that called it | Automation: Flow Structure |
Email |
Custom PMD XPath | 1 | No email address written into Apex | Apex: Hard-Coded Email Addresses |
Field |
Stock PMD | 1 | Field names are in camel case, and constant and enum value names in upper snake case | General: Apex Metadata Standards: Naming |
Formal |
Stock PMD | 1 | Parameter names are in camel case | General: Apex Metadata Standards: Naming |
Library |
Stock Code Analyzer RetireJS | 1 | No JavaScript library with a known vulnerability of critical severity | JavaScript: Third-Party Libraries |
Local |
Stock PMD | 1 | Local variable names are in camel case | General: Apex Metadata Standards: Naming |
Manage |
Custom PMD XPath | 1 | No profile or permission set grants ManageUsers |
Permissions and Security: High-Risk Permission Elements Within Profiles and Permission Sets |
Method |
Stock PMD | 1 | Method names are in camel case; underscores are allowed | General: Apex Metadata Standards: Naming |
Missing |
Stock Code Analyzer Flow | 1 | A Loop element has a next value connector | Automation: Flow Structure |
Modify |
Custom PMD XPath | 1 | No profile or permission set grants ViewAllData or ModifyAllData |
Permissions and Security: High-Risk Permission Elements Within Profiles and Permission Sets |
Multiple |
Custom PMD Java | 1 | Each object has at most one trigger | Apex: Triggers |
Non |
Custom PMD XPath | 1 | A custom object's internal and external org-wide defaults are Private, or controlled by the platform | Permissions and Security: Object Level Security |
Non |
Custom PMD XPath | 1 | A standard object's internal and external org-wide defaults are Private, or controlled by the platform | Permissions and Security: Object Level Security |
One |
Stock PMD | 1 | Declare each variable on its own line | Apex: Formatting |
Prohibited |
Custom PMD XPath | 1 | No metadata file of a Tier 0 type is committed to version control | Lightning Web Components and Aura: An Organisation Without Aura User Interface: S-Controls |
Property |
Stock PMD | 1 | Property names are in camel case | General: Apex Metadata Standards: Naming |
Require |
Custom PMD XPath | 1 | Every outer class declares its sharing, a test class included: with sharing by default, inherited sharing for a utility class |
Apex: Sharing and Access Mode Standards Apex: Sharing and Access Mode in Test Classes |
Require |
Custom PMD Java | 1 | A class with an @InvocableVariable member and an explicit constructor also has a visible no-argument constructor at API 66.0 and later |
Apex: Constructors |
Require |
Custom PMD XPath | 1 | Every outer class declares its access modifier | Apex: Access Modifiers |
Scheduled |
Custom PMD XPath | 1 | A schedule-triggered Flow runs on API version 61.0 or later | Automation: Schedule-Triggered Flows |
Test |
Stock PMD | 1 | Every test method is in a class that carries @IsTest |
Apex: Test Methods |
View |
Custom PMD XPath | 1 | No permission set grants ViewSetup |
Permissions and Security: High-Risk Permission Elements Within Profiles and Permission Sets |
View |
Custom PMD XPath | 1 | No custom profile grants ViewSetup |
Permissions and Security: High-Risk Permission Elements Within Profiles and Permission Sets |
@lwc/ |
Stock Code Analyzer ESLint | 2 | No $A, Aura, Sfdc, or sforce in a Lightning web component |
Lightning Web Components and Aura: Aura Globals |
@lwc/ |
Stock Code Analyzer ESLint | 2 | No import of an Aura library in a Lightning web component | Lightning Web Components and Aura: Aura Globals |
@lwc/ |
Stock Code Analyzer ESLint | 2 | No comment that switches off an ESLint rule for a line | General: Comments JavaScript: Comments |
@lwc/ |
Stock Code Analyzer ESLint | 2 | No HTML set from a string: no innerHTML, outerHTML, or insertAdjacentHTML |
Lightning Web Components and Aura: Input and Inserted HTML |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 2 | No private SLDS styling hook, one whose name starts with --_slds- or --slds-s- |
HTML and Visualforce: Safe Use of Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 2 | No SLDS linter suppression without an approving review from the owning team | General: Comments HTML and Visualforce: Suppression Comments |
Apex |
Stock PMD | 2 | No debug statement writes a credential, and no call to Configuration.disableTriggerCRUDSecurity() |
Apex: Debug Output and Error Disclosure |
Apex |
Stock Code Analyzer SFGE | 2 | Every query and DML statement on a path from an entry point runs in user mode or behind a permission check | Apex: Sharing and Access Mode Standards |
Apex |
Stock PMD | 2 | A callout goes over HTTPS; no http:// endpoint |
Apex: Callouts |
Apex |
Stock Code Analyzer SFGE | 2 | No operation on a value that may be null; assign it or check it first | Apex: Exception Handling |
Apex |
Stock PMD | 2 | A redirect goes to a page that the code chooses, never to a URL parameter as it is | Apex: Open Redirects |
Apex |
Stock PMD | 2 | No input is joined into a query string; use bind variables, an allowlist, or String.escapeSingleQuotes |
Apex: SOQL Injection |
Apex |
Stock PMD | 2 | Every test method asserts the behaviour it exercises | Apex: Assertions |
Apex |
Stock PMD | 2 | A test calls System.runAs for every user persona that reaches the code |
Apex: Running As a User |
Apex |
Stock PMD | 2 | No testMethod keyword; mark a test method with @IsTest |
Apex: Test Methods |
Apex |
Stock PMD | 2 | Do not use @IsTest(SeeAllData=true); a test creates the data it needs |
Apex: Test Classes |
Apex |
Stock PMD | 2 | An addError message that is not escaped holds no value that a user entered |
Apex: Cross-Site Scripting |
Apex |
Stock PMD | 2 | Escape or validate a value read from a URL parameter before the class uses or returns it | Apex: Cross-Site Scripting |
Assignment |
Stock PMD | 2 | No assignment in a condition: no =, ++, or -- in an if, while, do, for, or ternary test |
JavaScript: Assignments in Conditions |
Avoid |
Custom PMD XPath | 2 | Apex does not write {!$Api.Session_ID} into a string |
Apex: Session Ids |
Avoid |
Stock PMD | 2 | No console statements, in a component or in a Jest test |
JavaScript: Console and Debugger Statements |
Avoid |
Stock Code Analyzer SFGE | 2 | No query or DML statement inside a loop, in the loop or in a method it calls | Apex: Bulkification |
Avoid |
Stock PMD | 2 | No System.debug statements, in production code or in a test class |
Apex: Debug Output and Error Disclosure |
Avoid |
Stock PMD | 2 | No fixed index on Trigger.new or Trigger.old, such as Trigger.new[0] |
Apex: Bulkification |
Avoid |
Custom PMD XPath | 2 | No action inside a Flow loop; call it once, after the loop, with a collection | Automation: Limits |
Avoid |
Stock Code Analyzer Regex | 2 | No Limits.getHeapSize() inside a loop |
Apex: CPU Time and Heap |
Avoid |
Stock Code Analyzer PMD | 2 | No credential as the default value of an aura:attribute |
HTML and Visualforce: Credentials in Markup |
Avoid |
Stock Code Analyzer PMD | 2 | No credential in a field declaration; keep passwords, keys, and tokens in an External Credential | Apex: Hard-Coded Credentials |
Avoid |
Stock Code Analyzer PMD | 2 | No credential is written into a request header | Apex: Hard-Coded Credentials |
Avoid |
Stock Code Analyzer PMD | 2 | No credential assigned to a variable as a text literal | Apex: Hard-Coded Credentials |
Avoid |
Stock Code Analyzer PMD | 2 | No credential in a variable declaration as a text literal | Apex: Hard-Coded Credentials |
Avoid |
Custom PMD XPath | 2 | No secret is written into metadata, with one rule for each form of secret | Automation: Flow Security Objects and Fields: Secrets in Metadata |
Avoid |
Stock Code Analyzer PMD | 2 | No credential as the default value of an apex:attribute |
HTML and Visualforce: Credentials in Markup |
Avoid |
Custom PMD XPath | 2 | No security decision from the HTTP Referer header |
Apex: Untrusted Input |
Avoid |
Custom PMD XPath | 2 | No attribute in Lightning markup or plain HTML holds a javascript: URL, except javascript:void(0) |
HTML and Visualforce: Error Prevention Lightning Web Components and Aura: Scripts and Resources |
Avoid |
Custom PMD XPath | 2 | No attribute in Visualforce holds a javascript: URL, except javascript:void(0) |
HTML and Visualforce: Resources and Links |
Avoid |
Stock Code Analyzer PMD | 2 | A Lightning Message Channel is exposed only when a component in another namespace has to use it | User Interface: Lightning Message Channels |
Avoid |
Stock PMD | 2 | A trigger holds no logic: no if, switch, loop, or try block |
Apex: Triggers |
Avoid |
Stock Code Analyzer PMD | 2 | No custom event with both bubbles and composed set to true |
Lightning Web Components and Aura: Error Prevention |
Avoid |
Stock Code Analyzer SFGE | 2 | No Schema.getGlobalDescribe() or Schema.describeSObjects() inside a loop, or twice on one path |
Apex: Efficient Code |
Avoid |
Stock PMD | 2 | Every SOQL query and SOSL search has a WHERE clause or a LIMIT |
Apex: Queries |
Avoid |
Stock Code Analyzer Regex | 2 | Every metadata file states a recent API version | Apex: API Version JavaScript: API Version Metadata Standards: API Version |
Avoid |
Stock PMD | 2 | No trailing comma after the last item of an object literal or an array literal | Lightning Web Components and Aura: Code Style Lightning Web Components and Aura: Required Formatting |
Avoid |
Stock Code Analyzer PMD | 2 | Apex does not write the session Id into a string | Apex: Session Ids |
Avoid |
Stock Code Analyzer PMD | 2 | A Visualforce page does not read $Api.Session_ID |
HTML and Visualforce: Session Ids |
Avoid |
Stock Code Analyzer PMD | 2 | Apex does not read the session Id; no UserInfo.getSessionId() |
Apex: Session Ids |
Avoid |
Stock Code Analyzer PMD | 2 | A Visualforce page does not call GETSESSIONID() |
HTML and Visualforce: Session Ids |
Avoid |
Stock PMD | 2 | No with statement |
JavaScript: With Statements |
Broken |
Custom PMD XPath | 2 | A null check does not read the value it checks for null | Apex: Null Checks and Conditions |
Bump |
Custom PMD XPath | 2 | Every metadata file is at or above the API version floor | Apex: API Version JavaScript: API Version Metadata Standards: API Version |
Button |
Custom PMD XPath | 2 | Every image button, icon button, and image-map link has a name that a screen reader can announce | General: Buttons and Links |
Button |
Custom PMD XPath | 2 | Every image button and image-map link in a Visualforce page has a name that a screen reader can announce | General: Buttons and Links |
consistent-return |
Stock Code Analyzer ESLint | 2 | A function returns a value on every path, or on none | JavaScript: Return Values |
Consistent |
Stock PMD | 2 | A function returns a value on every path, or on none | JavaScript: Return Values |
curly |
Stock Code Analyzer ESLint | 2 | Wrap the body of every if, else, for, and while in braces, even one line |
JavaScript: Braces |
Database |
Stock Code Analyzer SFGE | 2 | Every database operation runs under a stated sharing declaration along the whole call path | Apex: Sharing and Access Mode Standards |
Db |
Stock Code Analyzer Flow | 2 | No Get, Create, Update, or Delete Records element inside a Flow loop | Automation: Limits |
Declare |
Custom PMD XPath | 2 | Every method except a test method declares its access modifier | Apex: Access Modifiers |
Dml |
Stock Code Analyzer ApexGuru | 2 | No DML statement inside a loop | Apex: Bulkification |
Dml |
Custom PMD XPath | 2 | No call inside a loop to a method that runs DML | Apex: Bulkification |
Do |
Custom PMD XPath | 2 | A test never runs as the current user | Apex: Running As a User |
Do |
Custom PMD XPath | 2 | A Flow runs in user context; system context is a reviewed exception | Automation: Flow Security |
Do |
Custom PMD XPath | 2 | No automation is built in Process Builder; rebuild every process as a Flow | Automation: Workflow & Process Builder |
Do |
Custom PMD XPath | 2 | without sharing is a deliberate, justified exception |
Apex: Sharing and Access Mode Standards |
Do |
Custom PMD XPath | 2 | No automation is built as a Workflow Rule; rebuild every rule as a Flow | Automation: Workflow & Process Builder |
Eagerly |
Stock PMD | 2 | Load describe results lazily with SObjectDescribeOptions.DEFERRED |
Apex: Efficient Code |
Empty |
Stock PMD | 2 | No empty catch block |
Apex: Empty Blocks |
Empty |
Stock PMD | 2 | No empty if block |
Apex: Empty Blocks |
Empty |
Stock PMD | 2 | No empty method or block, except a private no-argument constructor, a virtual base method, and a commented when else |
Apex: Empty Blocks |
Empty |
Stock PMD | 2 | No empty try or finally block |
Apex: Empty Blocks |
Empty |
Stock PMD | 2 | No empty while block |
Apex: Empty Blocks |
eqeqeq |
Stock Code Analyzer ESLint | 2 | Compare values with === and !==, not == and !=; value == null is the one exception |
JavaScript: Equality |
Equal |
Stock PMD | 2 | Compare values with === and !==, not == and !=; value == null is the one exception |
JavaScript: Equality |
Expensive |
Stock Code Analyzer ApexGuru | 2 | No debug statement whose argument is expensive to build | Apex: Debug Output and Error Disclosure |
Expensive |
Stock Code Analyzer ApexGuru | 2 | Refactor a method that uses a large share of the org's CPU time | Apex: Efficient Code |
Flag |
Custom PMD Java | 2 | User mode is the default; a system-mode operation is a deliberate exception, with its reason in a comment | Apex: Sharing and Access Mode Standards Apex: Sharing and Access Mode in Test Classes |
Flow |
Custom PMD XPath | 2 | A Get Records element has a filter | Automation: Limits |
Flow |
Custom PMD XPath | 2 | Every record-triggered Flow has a trigger order | Automation: Orchestration |
For |
Stock PMD | 2 | Wrap the body of every for loop in braces, even one line |
Apex: Braces JavaScript: Braces |
Hotspot |
Custom PMD XPath | 2 | Every place that reads JSON is reviewed | Apex: Untrusted Input |
Hotspot |
Custom PMD XPath | 2 | Every call that encrypts or decrypts is reviewed | Apex: Cookies and Cryptography |
If |
Stock PMD | 2 | Wrap the body of every else in braces, even one line |
Apex: Braces JavaScript: Braces |
If |
Stock PMD | 2 | Wrap the body of every if in braces, even one line |
Apex: Braces JavaScript: Braces |
Image |
Custom PMD XPath | 2 | Every image has an alternative text attribute | General: Images |
Image |
Custom PMD XPath | 2 | Every image in a Visualforce page has an alt attribute |
General: Images |
Invocable |
Stock PMD | 2 | A class with an @InvocableVariable member and an explicit constructor also has a visible no-argument constructor |
Apex: Constructors |
Layout |
Custom PMD XPath | 2 | A layout table carries no caption, th, summary, headers, or scope |
HTML and Visualforce: Tables |
Layout |
Custom PMD XPath | 2 | A layout table in a Visualforce page carries no caption, th, summary, headers, or scope |
HTML and Visualforce: Tables |
Library |
Stock Code Analyzer RetireJS | 2 | No JavaScript library with a known vulnerability of high severity | JavaScript: Third-Party Libraries |
Limits |
Stock Code Analyzer ApexGuru | 2 | Limits.getHeapSize() is not called often |
Apex: CPU Time and Heap |
Load |
Stock Code Analyzer PMD | 2 | An apex:stylesheet loads a stylesheet from a static resource |
HTML and Visualforce: External Scripts and Stylesheets |
Load |
Stock Code Analyzer PMD | 2 | A link tag in a Visualforce page loads a stylesheet from a static resource |
HTML and Visualforce: External Scripts and Stylesheets |
Load |
Stock Code Analyzer PMD | 2 | A script tag in a Visualforce page loads JavaScript from a static resource |
HTML and Visualforce: External Scripts and Stylesheets |
Load |
Stock Code Analyzer PMD | 2 | An apex:includeScript loads JavaScript from a static resource |
HTML and Visualforce: External Scripts and Stylesheets |
Metadata |
Custom PMD XPath | 2 | Every custom field carries a description of more than 10 characters | Objects and Fields: Descriptions |
Metadata |
Custom PMD XPath | 2 | Every custom object carries a description of more than 10 characters | Objects and Fields: Descriptions |
Metadata |
Custom PMD XPath | 2 | Every Flow, Flow test, Flow category, and Flow value map carries a description of more than 10 characters | Automation: Flow Attributes Objects and Fields: Descriptions |
Metadata |
Custom PMD XPath | 2 | Every permission set, profile, custom permission, permission set group, muting permission set, and user access policy carries a description of more than 10 characters | Objects and Fields: Descriptions |
Metadata |
Custom PMD XPath | 2 | Every API name of a Flow, a custom object, or a custom field starts with a capital letter | Metadata Standards: Naming Objects and Fields: Naming |
Min |
Stock Code Analyzer Regex | 2 | An abstract or virtual class with a private method is at API 61.0 or later | Apex: API Version |
Misuse |
Custom PMD XPath | 2 | No assertion fixed by a string, a number, or a new instance written into it | Apex: Assertions |
Modify |
Custom PMD XPath | 2 | No profile or permission set grants View All or Modify All Records on a custom object | Permissions and Security: High-Risk Permission Elements Within Profiles and Permission Sets |
Modify |
Custom PMD XPath | 2 | No profile or permission set grants View All or Modify All Records on a standard object | Permissions and Security: High-Risk Permission Elements Within Profiles and Permission Sets |
no-cond-assign |
Stock Code Analyzer ESLint | 2 | No assignment in a condition | JavaScript: Assignments in Conditions |
no-console |
Stock Code Analyzer ESLint | 2 | No console statements |
JavaScript: Console and Debugger Statements |
no-debugger |
Stock Code Analyzer ESLint | 2 | No debugger statements |
JavaScript: Console and Debugger Statements |
no-else-return |
Stock Code Analyzer ESLint | 2 | No else after an if block that ends in return |
JavaScript: Code Style |
no-extend-native |
Stock Code Analyzer ESLint | 2 | No property is added to a built-in JavaScript object | Lightning Web Components and Aura: Objects the Component Does Not Own |
no-global-assign |
Stock Code Analyzer ESLint | 2 | Nothing is assigned to a read-only global | Lightning Web Components and Aura: Strict Mode |
no-implied-eval |
Stock Code Analyzer ESLint | 2 | setTimeout and setInterval take a function, never a string of code |
JavaScript: Strings Run as Code |
no-restricted-syntax |
Stock Code Analyzer ESLint | 2 | No variable, parameter, function, class, or import named top or location |
JavaScript: Cookies Lightning Web Components and Aura: The Globals top and location Lightning Web Components and Aura: Error Prevention |
no-script-url |
Stock Code Analyzer ESLint | 2 | No javascript: URL is written in JavaScript |
JavaScript: Strings Run as Code |
no-shadow-restricted-names |
Stock Code Analyzer ESLint | 2 | No variable named undefined, NaN, Infinity, arguments, or eval |
Lightning Web Components and Aura: The Globals top and location |
no-undef |
Stock Code Analyzer ESLint | 2 | Every variable is declared, with const, let, or var |
Lightning Web Components and Aura: Strict Mode Lightning Web Components and Aura: Aura Globals |
no-unreachable |
Stock Code Analyzer ESLint | 2 | No statement follows a return, throw, break, or continue in the same block |
JavaScript: Unreachable Code |
No |
Custom PMD XPath | 2 | No colon between an ApexDoc tag and its text | Apex: ApexDoc |
No |
Custom Code Analyzer Regex | 2 | No console statement in a Visualforce page or component | HTML and Visualforce: Console Statements |
No |
Custom PMD Java | 2 | No credential is kept in a field; keep it in an External Credential | Objects and Fields: Secrets in Fields Settings: Custom Settings and Custom Metadata Types |
No |
Stock PMD | 2 | No else after an if block that ends in return |
JavaScript: Code Style |
No |
Custom PMD XPath | 2 | No @last modified tag, such as @last modified on, in an ApexDoc comment |
Apex: ApexDoc |
No |
Custom PMD XPath | 2 | No new list custom setting; use a custom metadata type | Settings: Custom Settings and Custom Metadata Types |
No |
Custom PMD XPath | 2 | A trigger declares no methods | Apex: Triggers |
Non |
Custom PMD XPath | 2 | Assertions only in test code | Apex: Assertions |
No |
Custom Code Analyzer Regex | 2 | Nothing loads from polyfill.io |
HTML and Visualforce: External Scripts and Stylesheets |
No |
Custom PMD XPath | 2 | Do not use WITH SECURITY_ENFORCED; use WITH USER_MODE |
Apex: Sharing and Access Mode Standards |
No |
Custom Code Analyzer Regex | 2 | The author is a person or a team, never a tool default such as ChangeMeIn@UserSettingsUnder.SFDoc |
Apex: ApexDoc General: Comments HTML and Visualforce: Comments JavaScript: Comments |
No |
Custom Code Analyzer Regex | 2 | No ESLint suppression without an approving review from the owning team | General: Comments JavaScript: Comments |
No |
Custom Code Analyzer Regex | 2 | No PMD or Code Analyzer suppression without an approving review from the owning team | Apex: Documentation General: Comments |
Operation |
Stock PMD | 2 | No SOQL, SOSL, DML, Database method, email send, or asynchronous call inside a loop |
Apex: Bulkification Apex: Asynchronous Apex |
Override |
Stock PMD | 2 | A class that overrides equals(Object) also overrides hashCode(), and the reverse |
Apex: Equality |
Prevent |
Stock Code Analyzer Flow | 2 | A Flow in system context without sharing never lets user-entered data choose the records it reads or writes | Automation: Flow Security |
Protect |
Stock Code Analyzer PMD | 2 | No credential is kept in a field of a custom object, a custom metadata type, or a custom setting | Objects and Fields: Secrets in Fields |
radix |
Stock Code Analyzer ESLint | 2 | parseInt is always given a radix, as in parseInt(value, 10) |
JavaScript: Number Parsing |
Require |
Custom PMD Java | 2 | Every database operation states its access mode: inline SOQL and SOSL, Database and Search methods, and DML |
Apex: Sharing and Access Mode Standards Apex: Sharing and Access Mode in Test Classes |
Require |
Custom PMD XPath | 2 | A cookie that JavaScript sets has the Secure attribute |
JavaScript: Cookies |
Require |
Custom PMD XPath | 2 | Every test class carries testFor, naming the classes and triggers it tests, or critical=true |
Apex: Test Selection |
Schema |
Stock Code Analyzer ApexGuru | 2 | Avoid Schema.getGlobalDescribe(); describe only the objects needed |
Apex: Efficient Code |
Server |
Custom PMD XPath | 2 | No image is a server-side image map | HTML and Visualforce: Media |
Server |
Custom PMD XPath | 2 | No image in a Visualforce page is a server-side image map | HTML and Visualforce: Media |
Soql |
Stock Code Analyzer ApexGuru | 2 | No SOQL query inside a loop | Apex: Bulkification |
Soql |
Stock Code Analyzer ApexGuru | 2 | Filter records in the WHERE clause, not in Apex after the query |
Apex: Queries |
Soql |
Stock Code Analyzer ApexGuru | 2 | Every SOQL query has a WHERE clause or a LIMIT |
Apex: Queries |
Statements |
Custom PMD XPath | 2 | Each statement on its own line | Apex: Formatting |
Trigger |
Stock Code Analyzer Flow | 2 | A record-triggered Flow makes no callout on its synchronous path | Automation: Record-Triggered Flows |
Trigger |
Stock Code Analyzer Flow | 2 | A record-triggered Flow has entry conditions in its trigger definition | Automation: Record-Triggered Flows |
Trigger |
Stock Code Analyzer Flow | 2 | A record-triggered Flow reaches no Wait element on its synchronous path | Automation: Record-Triggered Flows |
Type |
Stock PMD | 2 | No class, enum, or interface takes the name of a System or Schema type |
General: Apex |
Unnecessary |
Custom PMD XPath | 2 | No assertion fixed by true, false, or null written into it |
Apex: Assertions |
Unreachable |
Stock PMD | 2 | No statement follows a return, throw, break, or continue in the same block |
JavaScript: Unreachable Code |
Use |
Stock PMD | 2 | parseInt is always given a radix, as in parseInt(value, 10) |
JavaScript: Number Parsing |
Vf |
Stock PMD | 2 | A page changes no data when it loads; the action of apex:page calls no method that writes |
HTML and Visualforce: Cross-Site Request Forgery |
Vf |
Stock PMD | 2 | A merge expression in a style element is encoded |
HTML and Visualforce: Cross-Site Scripting |
Vf |
Stock PMD | 2 | A merge expression is always encoded for the place it is written | HTML and Visualforce: Cross-Site Scripting |
While |
Stock PMD | 2 | Wrap the body of every while loop in braces, even one line |
Apex: Braces JavaScript: Braces |
Writing |
Stock Code Analyzer ApexGuru | 2 | Never pad coverage with filler statements | Apex: Coverage |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 3 | No deprecated --lwc- design token; use the matching SLDS 2 styling hook, with the token as its fallback value |
HTML and Visualforce: Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 3 | A modal close button follows the SLDS modal blueprint | HTML and Visualforce: Modal Close Button |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 3 | No class that SLDS 2 does not have | HTML and Visualforce: SLDS Classes |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 3 | Every SLDS styling hook in var() has a fallback value |
HTML and Visualforce: Safe Use of Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 3 | No styling hook that SLDS 2 does not have | HTML and Visualforce: Styling Hooks |
Apex |
Stock PMD | 3 | Every assertion includes a message that says what went wrong, Assert.fail() included |
Apex: Assertions |
Avoid |
Custom PMD XPath | 3 | No absolute URL of a Salesforce org in Apex; use a page reference or a relative URL | Apex: Hard-Coded Salesforce URLs |
Avoid |
Custom PMD XPath | 3 | No absolute URL of a Salesforce org in a Flow; use a relative URL | Automation: Hard-Coded Values |
Avoid |
Custom PMD XPath | 3 | Lightning markup holds no absolute URL of a Salesforce org | HTML and Visualforce: Error Prevention |
Avoid |
Custom PMD XPath | 3 | A Visualforce page holds no absolute URL of a Salesforce org | HTML and Visualforce: Resources and Links |
Avoid |
Stock PMD | 3 | No deeply nested if statements |
Apex: Complexity and Unused Code |
Avoid |
Custom PMD XPath | 3 | Make a describe call whose result does not change once, before the loop | Apex: Efficient Code |
Avoid |
Custom PMD XPath | 3 | Link to a Visualforce page with $Page, not an /apex/ path |
HTML and Visualforce: Resources and Links |
Avoid |
Custom PMD XPath | 3 | Reference a static resource through $Resource, not a /resource/ path |
HTML and Visualforce: Resources and Links |
Avoid |
Stock PMD | 3 | Styling lives in a stylesheet, not in an inline style attribute |
HTML and Visualforce: CSS |
Avoid |
Custom PMD XPath | 3 | No style element, and no style, labelStyle, or html-style attribute, in a Visualforce page or component |
HTML and Visualforce: CSS |
Avoid |
Custom PMD XPath | 3 | Create a cookie with isSecure set to true |
Apex: Cookies and Cryptography |
Avoid |
Stock PMD | 3 | No interface as a Map key type where an abstract class implements it and defines equals or hashCode |
Apex: Equality |
Avoid |
Custom PMD XPath | 3 | A Visualforce page or component has one apex:form |
HTML and Visualforce: Standard Components |
Avoid |
Custom PMD XPath | 3 | No Flow loop inside another loop | Automation: Limits |
Avoid |
Custom PMD XPath | 3 | No switch inside a switch |
Apex: Switch Statements |
Avoid |
Stock PMD | 3 | Every annotation is one that Apex defines | Apex: Annotations |
Avoid |
Custom PMD XPath | 3 | Do not call getRecordTypeInfosByName(); use getRecordTypeInfosByDeveloperName() |
Apex: Record Types |
Avoid |
Custom PMD XPath | 3 | Count records with an aggregate query, not size() on a query |
Apex: Queries |
Avoid |
Stock PMD | 3 | A Database.Stateful batch class keeps no Database result, such as a SaveResult, in an instance field |
Apex: Asynchronous Apex |
Avoid |
Custom PMD XPath | 3 | Use an algorithm of the SHA-2 family for a digest, a MAC, or a signature; no MD5 or SHA-1 | Apex: Cookies and Cryptography |
Busy |
Stock Code Analyzer ApexGuru | 3 | No loop written to pass time; use a delayed Queueable job or a scheduled job | Apex: CPU Time and Heap |
Checkbox |
Custom PMD XPath | 3 | A checkbox field name starts with Is, never with IsNot |
Metadata Standards: Naming Objects and Fields: Naming |
Cognitive |
Stock PMD | 3 | Keep the cognitive complexity of a method low | Apex: Complexity and Unused Code |
Copying |
Stock Code Analyzer ApexGuru | 3 | Copy a list or a set with addAll(), not element by element in a loop |
Apex: Efficient Code |
Cyclomatic |
Stock PMD | 3 | Keep the cyclomatic complexity of a method low | Apex: Complexity and Unused Code |
Default |
Stock Code Analyzer Flow | 3 | An element pasted in Flow Builder is renamed and reviewed | Automation: Naming |
Fix |
Custom PMD XPath | 3 | Each branch of an if / else if chain tests a different condition |
Apex: Null Checks and Conditions |
Flow |
Custom PMD XPath | 3 | A screen after a record change does not offer the Previous button | Automation: Screen Flows |
Flow |
Custom PMD XPath | 3 | A Decision's label is the question it answers, and ends with a question mark | Automation: Naming Metadata Standards: Naming |
Flow |
Custom PMD XPath | 3 | The Flow settings file does not switch off deploy as active | Settings: Deploy Flows as Active |
Flow |
Custom PMD XPath | 3 | A Flow element's name starts with the verb for its type | Automation: Naming Metadata Standards: Naming |
Flow |
Custom PMD XPath | 3 | A Get Records element has a fault path | Automation: Error Handling |
Flow |
Custom PMD XPath | 3 | A Flow checks the result of a Get Records element for null before it uses it | Automation: Error Handling |
Flow |
Custom PMD XPath | 3 | A Flow's name has four parts: the owner code, the object, the kind code, and the purpose | Automation: Naming Metadata Standards: Naming |
Idempotent |
Custom PMD XPath | 3 | No assignment of a value to itself | Apex: Null Checks and Conditions |
Inaccessible |
Stock PMD | 3 | The getter of an @AuraEnabled property is public or global |
Apex: Access Modifiers |
Layout |
Custom PMD XPath | 3 | No table is used for layout | HTML and Visualforce: Tables |
Layout |
Custom PMD XPath | 3 | No table is used for layout in a Visualforce page | HTML and Visualforce: Tables |
Library |
Stock Code Analyzer RetireJS | 3 | No JavaScript library with a known vulnerability of medium severity | JavaScript: Third-Party Libraries |
Lightning |
Custom PMD XPath | 3 | The Security settings file does not switch off Lightning Web Security or its stricter Content Security Policy | Settings: Lightning Web Security |
Logic |
Custom PMD XPath | 3 | Negate a comparison with the opposite operator | Apex: Expressions |
Master |
Custom PMD XPath | 3 | A master-detail field that does not allow reparenting is a choice made on purpose | Data Management: Master-Detail Reparenting |
max-depth |
Stock Code Analyzer ESLint | 3 | Blocks nest no more than 3 deep in a function | JavaScript: Complexity |
Metadata |
Custom PMD XPath | 3 | Every component carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: Business rules Objects and Fields: Service Cloud Objects and Fields: Collaboration Objects and Fields: Experience Cloud and sites Objects and Fields: Territories Objects and Fields: Data Cloud Objects and Fields: Industries and other products |
Metadata |
Custom PMD XPath | 3 | Every component of the data model, and every process on it, carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: Data model and process |
Metadata |
Custom PMD XPath | 3 | Every data quality component carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: Data quality |
Metadata |
Custom PMD XPath | 3 | Every agent or Einstein component carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: Agents and Einstein |
Metadata |
Custom PMD XPath | 3 | Every integration component carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: Integration |
Metadata |
Custom PMD XPath | 3 | Every sharing or access component, and every sharing rule, carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: Access and sharing |
Metadata |
Custom PMD XPath | 3 | Every user interface or code component carries a description of more than 10 characters | Objects and Fields: Descriptions Objects and Fields: User interface and code |
Metadata |
Custom PMD XPath | 3 | Every label of a Flow, a custom object, or a custom field starts with a capital letter | Metadata Standards: Naming Objects and Fields: Naming |
Method |
Stock PMD | 3 | Only a constructor has the name of its class | Apex: Constructors |
Missing |
Stock Code Analyzer Flow | 3 | Every Flow element that can fail has a fault path | Automation: Error Handling |
Missing |
Stock Code Analyzer SFGE | 3 | Check a variable used in a WHERE clause for null first |
Apex: Exception Handling |
Missing |
Custom PMD XPath | 3 | A class with only private constructors has a public static member | Apex: Constructors |
Mouse |
Custom PMD XPath | 3 | Every function that a mouse reaches, a keyboard reaches too | HTML and Visualforce: Keyboard |
Mouse |
Custom PMD XPath | 3 | Every function that a mouse reaches in a Visualforce page, a keyboard reaches too | HTML and Visualforce: Keyboard |
Nested |
Custom PMD XPath | 3 | A script block does not hold the text of another script tag | HTML and Visualforce: Script Blocks |
no-implicit-globals |
Stock Code Analyzer ESLint | 3 | No top-level declaration becomes a global | Lightning Web Components and Aura: Strict Mode |
no-lone-blocks |
Stock Code Analyzer ESLint | 3 | No block that belongs to no statement and declares nothing | JavaScript: Code Style |
no-param-reassign |
Stock Code Analyzer ESLint | 3 | A function does not change a property of an argument it receives | Lightning Web Components and Aura: Objects the Component Does Not Own |
no-with |
Stock Code Analyzer ESLint | 3 | No with statement |
JavaScript: With Statements |
No |
Custom Code Analyzer Regex | 3 | At most one blank line in a row | Apex: Formatting |
No |
Custom Code Analyzer Regex | 3 | No empty block comment | Apex: Documentation |
No |
Custom PMD XPath | 3 | A web link does not hold the absolute URL of a Salesforce org | User Interface: Web Links |
No |
Custom PMD XPath | 3 | An event attribute in Aura markup names a controller action, not a script | Lightning Web Components and Aura: Scripts and Resources |
No |
Custom PMD XPath | 3 | An Aura application should not be a Lightning Out (beta) dependency app | Lightning Web Components and Aura: Aura |
No |
Custom PMD XPath | 3 | A Visualforce page or component should not use Lightning Out (beta) | HTML and Visualforce: External Scripts and Stylesheets |
No |
Custom PMD XPath | 3 | No one-letter variable names, except i and j as loop counters and e in a catch block |
General: Apex |
Obsolete |
Custom PMD XPath | 3 | A Flow that has been deactivated is removed from the repository | Automation: Deployment |
Operation |
Stock PMD | 3 | Make an expensive call, such as Schema.describeSObjects(), once before a loop, never inside it |
Apex: Efficient Code |
Position |
Custom PMD XPath | 3 | Call equals on the string literal, not on the variable |
Apex: Null Checks and Conditions |
Redundant Soql |
Stock Code Analyzer ApexGuru | 3 | Do not run the same query twice in a transaction; keep the result in a map | Apex: Queries |
Require |
Custom PMD XPath | 3 | An inner class should declare its sharing too | Apex: Sharing and Access Mode Standards |
Return |
Custom PMD XPath | 3 | Return an empty collection, not null |
Apex: Null Checks and Conditions |
Same |
Stock Code Analyzer Flow | 3 | A record-triggered Flow changes its own record before the save, not after it | Automation: Record-Triggered Flows |
S |
Stock Code Analyzer ApexGuru | 3 | Build a map of records by Id with the map constructor or putAll(), not put in a loop |
Apex: Efficient Code |
Soql Aggregation |
Stock Code Analyzer ApexGuru | 3 | Use an aggregate query (COUNT(), SUM()) for counts and totals, not a loop |
Apex: Queries |
Soql |
Stock Code Analyzer ApexGuru | 3 | No SOQL query in a method that a loop calls | Apex: Bulkification |
symbol-description |
Stock Code Analyzer ESLint | 3 | A Symbol is created with a description, as in Symbol('rowId') |
JavaScript: Symbol Descriptions |
Test |
Custom PMD XPath | 3 | Every test class has a test method, except a test helper | Apex: Test Classes |
Trigger |
Custom PMD XPath | 3 | A trigger name ends in Trigger, or in the one suffix the organisation sets |
General: Apex Metadata Standards: Naming |
Unconditional |
Custom PMD XPath | 3 | No if condition that is always true or always false |
Apex: Null Checks and Conditions |
Unused |
Stock PMD | 3 | Remove a local variable that is never read | Apex: Complexity and Unused Code |
Unused |
Stock PMD | 3 | Remove a method that is never called | Apex: Complexity and Unused Code |
Unused |
Stock Code Analyzer Flow | 3 | A Flow has no variable that it does not use | Automation: Flow Structure |
Use |
Custom PMD XPath | 3 | Compare two values with Assert.areEqual, not == in Assert.isTrue |
Apex: Assertions |
Use |
Custom PMD XPath | 3 | Compare two values with Assert.areEqual, not equals() in Assert.isTrue |
Apex: Assertions |
Use |
Custom PMD XPath | 3 | Check a Boolean with Assert.isTrue or Assert.isFalse, not Assert.areEqual |
Apex: Assertions |
Video |
Custom PMD XPath | 3 | A video has a track of captions or subtitles |
HTML and Visualforce: Media |
Video |
Custom PMD XPath | 3 | A video in a Visualforce page has a track of captions or subtitles |
HTML and Visualforce: Media |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | An SLDS class modifier takes a single underscore, as in slds-button_brand, not a double dash |
HTML and Visualforce: SLDS Classes |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | A component styling hook has its current SLDS 2 name | HTML and Visualforce: Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | No legacy --sds- styling hook; use the --slds- hook of the same name |
HTML and Visualforce: Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | Colours, spacing, and type sizes come from SLDS 2 styling hooks, not from hard-coded values | HTML and Visualforce: Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | No override of an SLDS class; give the component a class of its own | HTML and Visualforce: SLDS Classes |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | A custom styling hook has a name in the component's own namespace, not in --slds- or --sds- |
HTML and Visualforce: Safe Use of Styling Hooks |
@salesforce-ux/ |
Stock Code Analyzer ESLint | 4 | An --slds- styling hook is never the fallback value of an --lwc- design token |
HTML and Visualforce: Styling Hooks |
Apex |
Stock PMD | 4 | Every class, method, and property has an ApexDoc comment with a description, a @param for each parameter, and a @return where a value is returned |
Apex: ApexDoc |
Apex |
Custom PMD XPath | 4 | Every ApexDoc description has at least 10 characters that say what the thing is for | Apex: ApexDoc |
Aura |
Custom PMD XPath | 4 | A class that a Lightning component calls ends in Controller |
General: Apex Metadata Standards: Naming |
Avoid |
Stock PMD | 4 | No Boolean parameter that switches what a public or global method does; use two methods or an enum |
Apex: Architecture |
Avoid |
Stock PMD | 4 | Start asynchronous work as a Queueable job, not a future method | Apex: Asynchronous Apex |
Avoid |
Stock PMD | 4 | global only where another namespace or the platform requires it |
Apex: Access Modifiers |
Avoid |
Custom PMD XPath | 4 | A Visualforce page does not frame another page | HTML and Visualforce: Standard Components |
Avoid |
Custom PMD XPath | 4 | Declare a value once as a constant (static final); no magic numbers other than 0, 1, and -1 |
Apex: Expressions Apex: Constants |
Avoid |
Custom PMD XPath | 4 | Write filters that can use an index; no NOT IN, !=, or LIKE with a leading wildcard |
Apex: Queries |
Avoid |
Stock Code Analyzer Regex | 4 | Language is inclusive: allowlist and denylist, never whitelist and blacklist | Principles: Inclusive for Everyone |
Avoid |
Custom PMD XPath | 4 | A value that is only read is a property, not a field with a getter method | Apex: Expressions |
Avoid |
Custom PMD XPath | 4 | Production code does not call Test.isRunningTest() |
Apex: Testing Patterns |
Boolean |
Custom PMD XPath | 4 | A Boolean method is named as a question, not with get |
General: Apex |
Combine |
Custom PMD XPath | 4 | Combine nested if statements with nothing else in the outer one into one if with && |
Apex: Complexity and Unused Code |
complexity |
Stock Code Analyzer ESLint | 4 | A function has a cyclomatic complexity of 10 or less | JavaScript: Complexity |
Debugs |
Stock PMD | 4 | Any debug statement that remains specifies a LoggingLevel |
Apex: Debug Output and Error Disclosure |
Deprecated |
Custom PMD XPath | 4 | Every element with the @Deprecated annotation has a @deprecated tag with the reason and the alternative |
Apex: ApexDoc |
Empty |
Custom PMD XPath | 4 | No empty instance initializer block | Apex: Empty Blocks |
Exception |
Custom PMD XPath | 4 | A method comment names each exception it throws with @throws |
Apex: ApexDoc |
Expensive |
Stock Code Analyzer ApexGuru | 4 | Compare strings with equals or equalsIgnoreCase, not == |
Apex: Efficient Code |
Field |
Stock PMD | 4 | Declare fields before the first method of a class | Apex: Formatting |
Field |
Custom PMD XPath | 4 | A field or property does not take the name of its class, and a local variable does not take the name of a class | General: Apex |
Field |
Custom PMD XPath | 4 | A field or property does not share its name with a method of its class | General: Apex |
Fieldset |
Custom PMD XPath | 4 | A fieldset has a legend that names its group of controls |
HTML and Visualforce: Form Groups, Frames, and Lists |
Fieldset |
Custom PMD XPath | 4 | A fieldset in a Visualforce page has a legend that names its group of controls |
HTML and Visualforce: Form Groups, Frames, and Lists |
Flow |
Custom PMD XPath | 4 | A Get Records element names the fields that the Flow uses | Automation: Limits |
Flow |
Custom PMD XPath | 4 | A Flow is built in auto-layout | Automation: Flow Attributes |
Flow |
Custom PMD XPath | 4 | A Flow resource's name starts with the prefix for its type | Automation: Naming Metadata Standards: Naming |
Frame |
Custom PMD XPath | 4 | An iframe or a frame has a title that says what it holds |
HTML and Visualforce: Form Groups, Frames, and Lists |
Frame |
Custom PMD XPath | 4 | An iframe, a frame, or an apex:iframe in a Visualforce page has a title that says what it holds |
HTML and Visualforce: Form Groups, Frames, and Lists |
Image |
Custom PMD XPath | 4 | Only a decorative image has an empty alternative text | General: Images |
Image |
Custom PMD XPath | 4 | Only a decorative image in a Visualforce page has an empty alt |
General: Images |
Inefficient |
Custom PMD XPath | 4 | Test for a blank string with String.isBlank |
Apex: Expressions |
Library |
Stock Code Analyzer RetireJS | 4 | No JavaScript library with a known vulnerability of low severity | JavaScript: Third-Party Libraries |
List |
Custom PMD XPath | 4 | A list item is inside a list: an li in a ul, ol, or menu, and a dt or dd in a dl |
HTML and Visualforce: Form Groups, Frames, and Lists |
List |
Custom PMD XPath | 4 | A list item in a Visualforce page is inside a list | HTML and Visualforce: Form Groups, Frames, and Lists |
max-lines-per-function |
Stock Code Analyzer ESLint | 4 | A function has no more than 50 lines of code, not counting blank lines and comments | JavaScript: Complexity |
Metadata |
Custom PMD XPath | 4 | A report, dashboard, or analytics asset carries a description of more than 10 characters, where the organisation asks for one | Objects and Fields: Descriptions Objects and Fields: Analytics |
Metadata |
Custom PMD XPath | 4 | A standard field that the org uses in its own way carries a description of more than 10 characters | Objects and Fields: Descriptions |
Missing |
Stock Code Analyzer Flow | 4 | A Flow, and every element, variable, and resource in it, carries a description | Automation: Flow Attributes |
Ncss |
Stock PMD | 4 | A method has at most 40 statements, and a class at most 500 | Apex: Complexity and Unused Code |
Object |
Custom PMD XPath | 4 | An object element holds fallback content |
HTML and Visualforce: Media |
Object |
Custom PMD XPath | 4 | An object element in a Visualforce page holds fallback content |
HTML and Visualforce: Media |
Prefer |
Custom PMD XPath | 4 | Use the null coalescing operator for a default: name ?? 'none' |
Apex: Expressions |
Prefer |
Custom PMD XPath | 4 | Use the safe navigation operator for one call on an object that may be null: account?.close() |
Apex: Expressions |
Prefer |
Custom PMD XPath | 4 | Use switch, not an if / else if chain, for a string, an integer, an enum, or an sObject type |
Apex: Switch Statements |
Prevent |
Stock Code Analyzer Flow | 4 | A Flow in system context with sharing never lets user-entered data choose the records it reads or writes | Automation: Flow Security |
Refactor |
Custom PMD XPath | 4 | Assertions use the Assert class, not System.assert |
Apex: Assertions |
Regex |
Custom PMD XPath | 4 | Compile a regular expression that runs more than once as a static final Pattern |
Apex: Efficient Code |
Repeated |
Custom PMD XPath | 4 | Landmarks with the same role have different labels | HTML and Visualforce: Landmarks |
Repeated |
Custom PMD XPath | 4 | Landmarks with the same role in a Visualforce page have different labels | HTML and Visualforce: Landmarks |
Require |
Custom PMD XPath | 4 | A getter that queries loads its value lazily | Apex: Lazy Loading |
Screen |
Custom PMD XPath | 4 | A screen Flow launched from a record declares recordId as a record variable of the object |
Automation: Screen Flows |
Simplified |
Custom PMD XPath | 4 | No ternary expression with true or false as a result |
Apex: Expressions |
Simplify |
Custom PMD XPath | 4 | Return a condition directly, not through an if that returns true or false |
Apex: Expressions |
Simplify |
Custom PMD XPath | 4 | No null check next to instanceof |
Apex: Expressions |
Soql |
Stock Code Analyzer ApexGuru | 4 | No NOT IN or != in a WHERE clause; they cannot use an index |
Apex: Queries |
Soql |
Stock Code Analyzer ApexGuru | 4 | Serve a query that runs often, on data that rarely changes, from Platform Cache | Apex: Queries |
Soql |
Stock Code Analyzer ApexGuru | 4 | Select only the fields the code reads | Apex: Queries |
Soql |
Stock Code Analyzer ApexGuru | 4 | No LIKE filter that starts with a wildcard; it cannot use an index |
Apex: Queries |
Sorting |
Stock Code Analyzer ApexGuru | 4 | Sort records with ORDER BY, not in Apex after the query |
Apex: Queries |
Switch |
Custom PMD XPath | 4 | Every switch has a when else block |
Apex: Switch Statements |
Table |
Custom PMD XPath | 4 | A headers attribute names only the id of a th in the same table |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A headers attribute in a Visualforce page names only the id of a th in the same table |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A header cell has a scope, or an id that cells name in their headers attribute |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A header cell in a Visualforce page has a scope, or an id that cells name in their headers attribute |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A data table says what it holds, in a caption or an ARIA label |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A data table in a Visualforce page says what it holds, in a caption or an ARIA label |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A data table marks its header cells with th |
HTML and Visualforce: Tables |
Table |
Custom PMD XPath | 4 | A data table in a Visualforce page marks its header cells with th |
HTML and Visualforce: Tables |
Too |
Stock PMD | 4 | Split a class with too many fields; related fields belong in a type of their own | Apex: Complexity and Unused Code |
Unimplemented |
Stock Code Analyzer SFGE | 4 | An abstract class or an interface that is not global has at least one implementation |
Apex: Architecture |
Unit |
Custom PMD XPath | 4 | A test method calls Test.startTest() and Test.stopTest() |
Apex: Test Methods |
Unnecessary |
Stock PMD | 4 | No redundant parentheses around an expression | JavaScript: Code Style |
Unreachable |
Stock Code Analyzer Flow | 4 | Every Flow element is connected to the start element | Automation: Flow Structure |
Unused |
Custom PMD XPath | 4 | A null check before equals checks the object whose method is called |
Apex: Null Checks and Conditions |
Use |
Custom PMD XPath | 4 | Test for an empty collection with isEmpty() |
Apex: Expressions |
Using |
Stock Code Analyzer ApexGuru | 4 | No testMethod keyword; mark a test method with @IsTest |
Apex: Test Methods |
Visualforce |
Custom PMD XPath | 4 | A custom controller's name ends in Controller, and a controller extension's in Extension or Ext |
General: Controller Names Metadata Standards: Naming |
Visualforce |
Custom Code Analyzer Regex | 4 | A Visualforce page or component starts with a comment that says what it is for | HTML and Visualforce: Comments |
apexguru-other |
Stock Code Analyzer ApexGuru | 5 | A finding of a new ApexGuru rule is reported for information until these standards place it | Apex: ApexGuru |
Detect |
Stock Code Analyzer CPD | 5 | No copied blocks of Apex; share a method or a base class | Apex: Architecture |
Detect |
Stock Code Analyzer CPD | 5 | No copied blocks of HTML markup; share a component | HTML and Visualforce: Duplicated Markup |
Detect |
Stock Code Analyzer CPD | 5 | No copied blocks of JavaScript; share a function in a module | JavaScript: Duplicated Code |
Detect |
Stock Code Analyzer CPD | 5 | No copied blocks of TypeScript; share a function in a module | JavaScript: Duplicated Code |
Detect |
Stock Code Analyzer CPD | 5 | No copied blocks of Visualforce markup; share a component | HTML and Visualforce: Duplicated Markup |
Detect |
Stock Code Analyzer CPD | 5 | No block of metadata XML copied by hand from one file to another | Metadata Standards: Duplicated Metadata |
Flow |
Custom PMD XPath | 5 | Activate a Flow that has never been activated | Automation: Deployment |
No |
Stock Code Analyzer Regex | 5 | No line ends in a space or a tab, and no line is only whitespace | Apex: Formatting |
No |
Custom PMD XPath | 5 | Return a value directly: return calculate();, not a variable that is set and then only returned |
Apex: Expressions |
No |
Custom Code Analyzer Regex | 5 | No TODO, TO-DO, FIXME, FIX-ME, or HACK comment stays in Apex |
Apex: Documentation General: Comments |
No |
Custom Code Analyzer Regex | 5 | No TODO, TO-DO, FIXME, FIX-ME, or HACK comment stays in JavaScript |
General: Comments JavaScript: Comments |
No |
Custom Code Analyzer Regex | 5 | No TODO, TO-DO, FIXME, FIX-ME, or HACK stays in a markup comment |
General: Comments HTML and Visualforce: Comments |
Queueable |
Stock PMD | 5 | A Queueable job whose failure needs a recovery action attaches a finalizer | Apex: Asynchronous Apex |
Test |
Custom PMD XPath | 5 | A test class states IsParallel=true or IsParallel=false |
Apex: Test Classes |
Rules Without a Written Standard¶
A rule here is in the reference rulesets, so the pipeline enforces it, but no standards page mentions it yet.
Custom PMD Rules¶
| Rule | Kind | Severity | What it does |
|---|---|---|---|
Null |
Custom PMD XPath | 2 | A null check placed after an isEmpty() call on the same expression runs too late; the isEmpty() call throws first. Put the null check first. |
Field |
Custom PMD XPath | 3 | Every field, standard and custom, must carry a Compliance Categorization (the complianceGroup element: PII, HIPAA, GDPR, PCI, COPPA, CCPA, or None). Fields in the metadata-API object shape (CustomObject/fields) are covered too. |
Field |
Custom PMD XPath | 3 | Every field, standard and custom, must carry a Data Sensitivity Level (the securityClassification element: Public, Internal, Confidential, Restricted, or MissionCritical). |
Field |
Custom PMD XPath | 3 | A field whose Compliance Categorization includes PII or HIPAA must have a Data Sensitivity Level of Confidential, Restricted, or MissionCritical. complianceGroup is a semicolon-separated list, so it is matched with a regular expression. |
Stock Code Analyzer Rules¶
| Rule | Kind | Severity | What it does |
|---|---|---|---|
array-callback-return |
Stock Code Analyzer ESLint | 2 | A callback of an array method, such as map, filter, or reduce, that does not return a value. |
no-await-in-loop |
Stock Code Analyzer ESLint | 2 | An await inside the body of a loop, which runs the operations one after another and not in parallel. |
no-constant-binary-expression |
Stock Code Analyzer ESLint | 2 | A comparison or logical expression whose result is always the same, whatever its operands are. |
no-constructor-return |
Stock Code Analyzer ESLint | 2 | A return statement with a value in a class constructor. |
no-duplicate-imports |
Stock Code Analyzer ESLint | 2 | Two or more import statements from the same module. |
no-new-native-nonconstructor |
Stock Code Analyzer ESLint | 2 | new applied to Symbol or BigInt, which are not constructors. |
no-self-compare |
Stock Code Analyzer ESLint | 2 | A comparison of a value with itself, such as x === x. |
no-unassigned-vars |
Stock Code Analyzer ESLint | 2 | A let or var variable that is read but never assigned a value. |
no-unreachable-loop |
Stock Code Analyzer ESLint | 2 | A loop whose body can run only once, because every path through it ends the loop. |
no-unused-private-class-members |
Stock Code Analyzer ESLint | 2 | A private class member (#name) that the class never reads. |
no-use-before-define |
Stock Code Analyzer ESLint | 2 | A variable, function, or class used before it is declared. |
no-useless-assignment |
Stock Code Analyzer ESLint | 2 | An assignment whose value is never read before the variable is assigned again or goes out of scope. |
block-scoped-var |
Stock Code Analyzer ESLint | 3 | A var variable used outside the block in which it is declared. |
camelcase |
Stock Code Analyzer ESLint | 3 | An identifier written with underscores and not in camel case. |
consistent-this |
Stock Code Analyzer ESLint | 3 | A variable that holds this under a name other than the configured one, which is that by default. |
default-case |
Stock Code Analyzer ESLint | 3 | A switch statement with no default case and no comment that says none is needed. |
dot-notation |
Stock Code Analyzer ESLint | 3 | A property read with square brackets where dot notation would do, as in record['Name']. |
guard-for-in |
Stock Code Analyzer ESLint | 3 | A for...in loop whose body does not filter the keys with an if statement first. |
new-cap |
Stock Code Analyzer ESLint | 3 | A constructor called with new whose name starts with a lower-case letter, or a capitalised function called without new. |
no-alert |
Stock Code Analyzer ESLint | 3 | A call to alert, confirm, or prompt. |
no-caller |
Stock Code Analyzer ESLint | 3 | A use of arguments.caller or arguments.callee. |
no-continue |
Stock Code Analyzer ESLint | 3 | A continue statement. |
no-empty-function |
Stock Code Analyzer ESLint | 3 | A function with an empty body and no comment that says why. |
no-empty-static-block |
Stock Code Analyzer ESLint | 3 | An empty static block in a class. |
no-eval |
Stock Code Analyzer ESLint | 3 | A call to eval(). |
no-extra-bind |
Stock Code Analyzer ESLint | 3 | A call to .bind() on a function that does not use this. |
no-iterator |
Stock Code Analyzer ESLint | 3 | A use of the obsolete \_\_iterator\_\_ property. |
no-label-var |
Stock Code Analyzer ESLint | 3 | A label with the same name as a variable in scope. |
no-labels |
Stock Code Analyzer ESLint | 3 | A labelled statement, or a break or continue that names a label. |
no-lonely-if |
Stock Code Analyzer ESLint | 3 | An if statement that is the only statement in an else block, where else if would do. |
no-loop-func |
Stock Code Analyzer ESLint | 3 | A function created inside a loop that refers to a variable the loop changes. |
no-multi-str |
Stock Code Analyzer ESLint | 3 | A string continued onto the next line with a backslash. |
no-nested-ternary |
Stock Code Analyzer ESLint | 3 | A ternary expression inside another ternary expression. |
no-new |
Stock Code Analyzer ESLint | 3 | A new expression whose result is neither assigned nor compared: an object made only for its side effects. |
no-new-func |
Stock Code Analyzer ESLint | 3 | A function made from a string, with new Function() or Function(). |
no-new-wrappers |
Stock Code Analyzer ESLint | 3 | new applied to String, Number, or Boolean, which makes a wrapper object and not a primitive value. |
no-octal-escape |
Stock Code Analyzer ESLint | 3 | An octal escape sequence in a string, such as \\251. |
no-proto |
Stock Code Analyzer ESLint | 3 | A use of the \_\_proto\_\_ property. |
no-restricted-globals |
Stock Code Analyzer ESLint | 3 | A use of a global variable that the ESLint configuration restricts. Salesforce's LWC configuration restricts the confusing browser globals, such as event and name. |
no-restricted-imports |
Stock Code Analyzer ESLint | 3 | An import of a module that the ESLint configuration restricts. |
no-return-assign |
Stock Code Analyzer ESLint | 3 | An assignment inside a return statement. |
no-sequences |
Stock Code Analyzer ESLint | 3 | A comma operator that joins expressions, outside the initialiser and the update of a for loop. |
no-shadow |
Stock Code Analyzer ESLint | 3 | A variable with the same name as a variable in an outer scope, which it hides. |
no-throw-literal |
Stock Code Analyzer ESLint | 3 | A throw of a value that is not an Error object, such as a string. |
no-undef-init |
Stock Code Analyzer ESLint | 3 | A variable initialised to undefined, which it already is. |
no-unneeded-ternary |
Stock Code Analyzer ESLint | 3 | A ternary expression that a simpler expression can replace, such as x ? true : false. |
no-unused-expressions |
Stock Code Analyzer ESLint | 3 | An expression statement that has no effect, such as a value on a line of its own. |
no-useless-computed-key |
Stock Code Analyzer ESLint | 3 | A computed key with a literal value, such as { ['name']: value }. |
no-useless-concat |
Stock Code Analyzer ESLint | 3 | Two literals joined with + that could be one literal. |
no-useless-constructor |
Stock Code Analyzer ESLint | 3 | A constructor that does nothing, or only calls super with the same arguments. |
no-useless-rename |
Stock Code Analyzer ESLint | 3 | An import, export, or destructuring that renames a name to itself. |
no-useless-return |
Stock Code Analyzer ESLint | 3 | A return statement with no value at the end of a function. |
no-var |
Stock Code Analyzer ESLint | 3 | A var declaration, where let or const belongs. |
no-void |
Stock Code Analyzer ESLint | 3 | A use of the void operator. |
object-shorthand |
Stock Code Analyzer ESLint | 3 | An object literal property or method written in full where the shorthand would do, as in { name: name }. |
operator-assignment |
Stock Code Analyzer ESLint | 3 | An assignment such as x = x + y where the shorthand x += y would do. |
prefer-arrow-callback |
Stock Code Analyzer ESLint | 3 | A function expression passed as a callback where an arrow function would do. |
prefer-const |
Stock Code Analyzer ESLint | 3 | A let variable that is never reassigned, where const belongs. |
prefer-numeric-literals |
Stock Code Analyzer ESLint | 3 | A call to parseInt() with a radix of 2, 8, or 16 on a literal, where a binary, octal, or hexadecimal literal would do. |
yoda |
Stock Code Analyzer ESLint | 3 | A comparison with the literal first, such as 'red' === colour. |
unicode-bom |
Stock Code Analyzer ESLint | 4 | A file that starts with a Unicode byte order mark. |
vars-on-top |
Stock Code Analyzer ESLint | 5 | A var declaration that is not at the top of its function or script. |