forcedotcom / forcedotcom/code-analyzer
[BUG][code-analyzer] sfge: a guard condition on a SOQL result aborts the entry point (TodoException in SchemaBasedValidationAnalyzer)
- Dominant language
- TypeScript
- Stars
- 240
- Forks
- 52
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 5
Description
### Have you tried to resolve this issue yourself first?
- [x] I confirm I have gone through the above steps and still have an issue to report.
### Bug Description
**Engine:** `sfge` (Salesforce Graph Engine) · **Rule:** `ApexFlsViolation` (DevPreview) · **Selector:** `--rule-selector sfge`
`SchemaBasedValidationAnalyzer.getDerivedApexValue` accepts four `ApexValue` kinds and throws for everything else:
```java
// SchemaBasedValidationAnalyzer.java:85-91
if (!(apexValue instanceof ApexBooleanValue)
&& !(apexValue instanceof ApexCustomValue)
&& !(apexValue instanceof ApexForLoopValue)
&& !(apexValue instanceof ApexSingleValue)) {
throw new TodoException(
"What should I do if ApexValue from StandardCondition is not an ApexBooleanValue, "
+ "ApexCustomValue, ApexForLoopValue, or ApexSingleValue: ApexValue=" ...
```
`ApexSoqlValue` reaches it easily: `ApexSoqlValue.apply` returns `Optional.empty()` for every method it does not model, so a condition calling an unmodelled method on a SOQL-derived value resolves back to the `ApexSoqlValue` itself.
The triggering shape is "query with `WITH USER_MODE`, guard, loop, branch on a field, DML" — the single most common shape in a Lightning controller.
### Output / Logs
```shell
TodoException: What should I do if ApexValue from StandardCondition is not an ApexBooleanValue,
ApexCustomValue, ApexForLoopValue, or ApexSingleValue: ApexValue=ApexValue(ApexSoqlValue)
{status=INITIALIZED, declarationVertex=null, valueVertex=SoqlExpression{...Query=[ SELECT Id, Title,
FileType, Checksum FROM ContentVersion WHERE Id IN :versionIds WITH USER_MODE ]...}, resolvedValues={},
returnedFrom=null, invocableExpression=null, method=null}, parent=Unknown{conditionType=UNKNOWN, ...},
vertex=MethodCallExpressionVertex{fullMethodName=file.FileType.startsWith, ...}:
com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.getDerivedApexValue(SchemaBasedValidationAnalyzer.java:89);
com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.getDerivedApexValue(SchemaBasedValidationAnalyzer.java:117);
com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.checkForValidation(SchemaBasedValidationAnalyzer.java:74); ...
```
### Steps To Reproduce
1. Create an empty SFDX project (`sfdx-project.json` with a single `force-app` package directory).
2. Add `force-app/main/default/classes/SoqlDerivedCondition.cls` with the class shown below, plus a standard `SoqlDerivedCondition.cls-meta.xml` (apiVersion 62.0).
3. Add `code-analyzer.yml`:
```yaml
engines:
sfge:
java_thread_timeout: 900000
java_thread_count: 4
```
4. Run:
```
sf code-analyzer run --rule-selector sfge --workspace . --config-file code-analyzer.yml
```
5. The run reports an `InternalExecutionError` for the entry point instead of analysing it. That entry point yields no `ApexFlsViolation` findings at all, and nothing in the summary indicates coverage was lost.
```apex
public with sharing class SoqlDerivedCondition {
@AuraEnabled
public static void run(Set versionIds) {
List fileData = [
SELECT Id, Title, FileType, Checksum
FROM ContentVersion
WHERE Id IN :versionIds
WITH USER_MODE
];
if (fileData == null || fileData.isEmpty()) {
return;
}
List out = new List();
for (ContentVersion file : fileData) {
String endpoint = 'https://example.com/';
if (file.FileType.startsWith('image')) {
endpoint += 'images';
} else {
endpoint += 'documents';
}
file.Title = endpoint;
out.add(file);
}
update out;
}
}
```
### Expected Behavior
A condition the analyzer cannot interpret is not evidence of anything — it should contribute no schema-based validation and let evaluation continue. The sibling branch twenty lines above already does exactly that:
```java
if (!apexValueOptional.isPresent()) {
// If standard condition does not resolve to an ApexValue, there isn't much we can do
return results;
}
```
Throwing instead costs the whole entry point's coverage over a condition that was never going to be a sanitizer.
### Operating System
macOS 26.5.2
### Salesforce CLI Version
@salesforce/cli/2.147.7 darwin-arm64 node-v24.5.0
### Code Analyzer Plugin (code-analyzer) Version
code-analyzer 5.15.0
### Node Version
v24.5.0
### Java Version
openjdk version "11.0.32" 2026-07-21
### Python Version
N/A
### Additional Context (Screenshots, Files, etc)
5 occurrences across 3 distinct `@AuraEnabled` entry points in our codebase.
Reported verbatim as #1747 in February 2025 and closed as a duplicate of #1497. #1497 has since been closed too, so there is no longer an open home for it.
### Workaround
Hoist the field into a local before the condition (`String fileType = file.FileType;` then branch on `fileType`). Fragile — it depends on which method the condition calls.
### Urgency
Moderate
Contributor guide
Research direction
Start with SchemaBasedValidationAnalyzer.java, especially getDerivedApexValue and the ApexSoqlValue path described in the report. Reproduce the sfge command against the supplied SoqlDerivedCondition entry point; done means an uninterpreted condition no longer aborts the entry point and analysis continues without an InternalExecutionError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100