Code Analyzer Compliance
Introduction
Purpose
This document defines how developers use Salesforce Code Analyzer to validate code against project standards. It covers installation, configuration, local usage, and merge policy.
Scope
Code Analyzer compliance applies to all Apex, LWC, and related Salesforce source in your Salesforce/SFDX repository. Code must pass analyzer checks before merge using the repository ruleset.
Related Documentation
- Apex Coding Standards - Backend coding standards and patterns
- LWC Coding Standards - Frontend coding standards and patterns
- Testing Policy - Org-wide testing expectations, including Apex Testing and LWC Testing
Prerequisites and Installation
Requirements
- Salesforce CLI - Required. See Salesforce CLI Setup.
- Code Analyzer - JIT-installed when running commands, or install directly:
sf plugins install code-analyzer. - JDK 11+ - Required for PMD, CPD, and SFGE engines (Apex analysis).
- Python 3.10+ - Optional; only for Flow Scanner engine.
Verification
Confirm installation:
sf plugins
If Code Analyzer is installed, it appears in the output. Test the plugin:
sf code-analyzer rules
Project Configuration
In your Salesforce source repository (SFDX project), maintain:
code-analyzer.ymlat the project root for engine settings, log level, and rule overrides. See Customize Code Analyzer Configuration.- PMD ruleset XML (for example
rulesets/salesforce.xml) for custom Apex and Visualforce rules. Reference it fromcode-analyzer.ymlunderengines.pmd.custom_rulesets(or your team equivalent).
This docs site does not ship those files; keep them in the repository that contains your Apex, LWC, and metadata.
Running the Code Analyzer
Quick Start
From your SFDX project root (contains sfdx-project.json and usually code-analyzer.yml):
sf code-analyzer run
Fail on Critical/High violations:
sf code-analyzer run --severity-threshold 2
Scoping Analysis
Use --workspace for path scoping and --target for pattern scoping.
sf code-analyzer run --workspace .
sf code-analyzer run --workspace force-app/main/default
sf code-analyzer run --target "force-app/**/*.cls"
Output Formats
Write output to file:
sf code-analyzer run --output-file results.html
Supported extensions include .html, .csv, .json, .xml, and .sarif.
Severity Levels and Policy
Severity Levels
- 1 (Critical) - Must be fixed immediately.
- 2 (High) - Must be fixed before merge.
- 3 (Moderate) - Should be addressed.
- 4 (Low) - Consider addressing.
- 5 (Info) - Informational only.
Policy
Critical (1) and High (2) violations must be resolved before merge. Teams typically enforce this in pre-commit hooks and CI in the Salesforce source repository (not in this docs site).
Common Violations and How to Avoid Them
SOQL in Loops (OperationWithLimitsInLoop)
Violation: SOQL or DML executed inside a loop.
Fix: Query once before the loop, store in a Map for O(1) lookup, and perform bulk DML after the loop.
Logic in Triggers (AvoidLogicInTrigger, AvoidDirectAccessTriggerMap)
Violation: Business logic in trigger body, or direct use of Trigger.new and Trigger.old in business logic.
Fix: Use a trigger handler. In the trigger, pass context objects into handler methods.
Missing Sharing Declaration (ApexSharingViolations)
Violation: Class performs SOQL/DML but does not declare sharing model.
Fix: Use with sharing by default. Use without sharing only when justified and documented.
SOQL Injection (ApexSOQLInjection)
Violation: Variables or user input concatenated into dynamic SOQL.
Fix: Use bind variables. If dynamic assembly is required, sanitize inputs and avoid direct concatenation patterns.
CRUD/FLS Violations (ApexCRUDViolation)
Violation: SOQL or DML without CRUD/FLS checks.
Fix: Use WITH SECURITY_ENFORCED where applicable and
Security.stripInaccessible() before DML.
Missing Assert Messages (ApexAssertionsShouldIncludeMessage)
Violation: Assertions without descriptive failure message.
Fix: Always include assertion messages, for example:
Assert.areEqual(expected, actual, 'Expected status to be Active after save').
Empty Catch Blocks (EmptyCatchBlock)
Violation: Empty catch block.
Fix: Log, rethrow, or handle meaningfully; never leave catch blocks empty.
Unbraced Conditionals (IfStmtsMustUseBraces, etc.)
Violation: Conditional or loop body without braces.
Fix: Always use braces, even for single-line bodies.
Excessive Complexity (CognitiveComplexity, NcssCount)
Violation: Method/class exceeds configured thresholds.
Fix: Split complex logic into smaller methods, use early returns, and extract reusable strategies.
Hardcoded IDs (AvoidHardcodingId)
Violation: Hardcoded record IDs or org-specific values in source.
Fix: Use Custom Metadata, Custom Settings, or repository configuration.
Key Rules Reference
Rules most frequently violated and critical to compliance:
Complexity
- CognitiveComplexity: Method limit 15, class limit 50.
- NcssCount: Methods under 60 lines, classes under 1000 lines.
- ExcessiveParameterList: Maximum 5 parameters.
Security
- ApexSOQLInjection: Use bind variables only.
- ApexCRUDViolation: Enforce CRUD/FLS checks.
- ApexSharingViolations: Declare sharing model for data-access classes.
Performance
- OperationWithLimitsInLoop: No SOQL/DML in loops.
Triggers
- AvoidLogicInTrigger: Keep logic out of trigger body.
- AvoidDirectAccessTriggerMap: Keep Trigger context handling in handlers.
Tests
- ApexAssertionsShouldIncludeMessage: Always include assert messages.
- ApexUnitTestClassShouldHaveAsserts: Ensure tests contain assertions.
Code Style
- If/For/While must use braces.
- EmptyCatchBlock must be avoided.
Ruleset Requirements
Your PMD ruleset (commonly rulesets/salesforce.xml) applies to:
.cls- Apex classes.trigger- Apex triggers.page,.component- Visualforce pages/components
Rule priorities map to Code Analyzer severities. Priority 2 (High) and 3 (Moderate) are commonly enforced; Priority 4 (Low) should still be addressed.
PMD Rule Compliance
The following representative rules from rulesets/salesforce.xml apply to Apex and Visualforce code.
Complexity Rules
| Rule | Message | Configuration |
|---|---|---|
NcssCount |
Avoid really long classes (lines of code) | methodReportLevel: 60, classReportLevel: 1000 |
CognitiveComplexity |
Cognitive complexity too high | classReportLevel: 50, methodReportLevel: 15 |
ExcessiveParameterList |
Avoid long parameter lists | minimum: 5 |
ExcessivePublicCount |
Too many public methods and attributes | minimum: 25 |
TooManyFields |
Too many fields | maxfields: 20 |
AvoidDeeplyNestedIfStmts |
Deeply nested conditionals are hard to read | problemDepth: 4 |
Performance Rules
| Rule | Message |
|---|---|
OperationWithLimitsInLoop |
Avoid DML/SOQL statements inside loops |
Trigger Rules
| Rule | Message |
|---|---|
AvoidLogicInTrigger |
Avoid logic in triggers (delegate to handler classes) |
AvoidDirectAccessTriggerMap |
Avoid direct trigger context map access in business logic |
Test Rules
| Rule | Message |
|---|---|
ApexAssertionsShouldIncludeMessage |
Assertions should include descriptive messages |
ApexUnitTestMethodShouldHaveIsTestAnnotation |
Test methods must have @IsTest |
ApexUnitTestClassShouldHaveAsserts |
Test classes must include assertions |
ApexUnitTestShouldNotUseSeeAllDataTrue |
Do not use @isTest(seeAllData=true) |
Security Rules
| Rule | Message |
|---|---|
ApexSharingViolations |
Classes should declare sharing model for SOQL/DML |
ApexSOQLInjection |
Protect against SOQL injection |
ApexCRUDViolation |
Validate CRUD/FLS before data access |
ApexSuggestUsingNamedCred |
Use named credentials for authenticated callouts |
ApexInsecureEndpoint |
Use HTTPS callout endpoints |
Code Style and Naming Rules
| Rule | Message |
|---|---|
ClassNamingConventions |
Class names should begin with an uppercase character |
MethodNamingConventions |
Method names should begin with a lowercase character |
LocalVariableNamingConventions |
Local variables should follow naming conventions |
OneDeclarationPerLine |
One variable declaration per line |
Brace and Empty Block Rules
| Rule | Message |
|---|---|
IfStmtsMustUseBraces |
Use braces for if statements |
IfElseStmtsMustUseBraces |
Use braces for if/else statements |
ForLoopsMustUseBraces |
Use braces for for loops |
WhileLoopsMustUseBraces |
Use braces for while loops |
EmptyCatchBlock |
Avoid empty catch blocks |
EmptyIfStmt |
Avoid empty if statements |
EmptyWhileStmt |
Avoid empty while statements |
EmptyTryOrFinallyBlock |
Avoid empty try/finally blocks |
ESLint Rule Compliance
The ESLint engine runs against LWC and JavaScript sources. Point the ESLint engine at your team config via code-analyzer.yml.
LWC and JavaScript
- Base config:
@salesforce/eslint-config-lwc/recommendedandplugin:@lwc/lwc-platform/recommended - File extensions:
.js,.cjs,.mjs,.ts - Scope: LWC components and related JS/TS files
Example run:
sf code-analyzer run --workspace force-app/main/default/lwc
Troubleshooting and References
Common Issues
- Java not found: PMD/CPD/SFGE require JDK 11+ and
java/javacon PATH. - Plugin not installed: Run
sf plugins install code-analyzeror anysf code-analyzercommand for JIT install. - Engine dependency errors: Disable unused engines in
code-analyzer.yml.
References
- Salesforce Code Analyzer Overview
- CLI Commands to Analyze Code
- Customize Code Analyzer Configuration
Future Automation
Optional automation in your Salesforce source repository:
- Pre-commit: run analyzer on staged
.cls,.trigger,.js,.tsfiles and fail on severity threshold. - Pull requests: run the same checks in CI to block non-compliant merges.
Document exact commands and thresholds in your team repository README or engineering handbook.
Change History
Version 1.0 - 2026-03-26
- Added initial version history tracking for this document.
Last Updated: 2026-03-26 Version: 1.0