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.

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.yml at 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 from code-analyzer.yml under engines.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/recommended and plugin:@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/javac on PATH.
  • Plugin not installed: Run sf plugins install code-analyzer or any sf code-analyzer command for JIT install.
  • Engine dependency errors: Disable unused engines in code-analyzer.yml.

References

Future Automation

Optional automation in your Salesforce source repository:

  • Pre-commit: run analyzer on staged .cls, .trigger, .js, .ts files 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