forcedotcom / forcedotcom/code-analyzer

[BUG][code-analyzer] sfge: a guard condition on a SOQL result aborts the entry point (TodoException in SchemaBasedValidationAnalyzer)

Offen
#2,095 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
TypeScript
Sterne
240
Forks
52
Ø Merge
1 T. 23 Std.
Gemergte PRs (30 T.)
5

Beschreibung

### 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

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

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.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
java
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
72/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.