forcedotcom / forcedotcom/code-analyzer
[BUG][code-analyzer] sfge: a guard condition on a SOQL result aborts the entry point (TodoException in SchemaBasedValidationAnalyzer)
- Langage dominant
- TypeScript
- Étoiles
- 240
- Forks
- 52
- Merge moyen
- 1 j 23 h
- PR mergées (30 j)
- 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
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Commencez par SchemaBasedValidationAnalyzer.java, en particulier getDerivedApexValue et le chemin ApexSoqlValue décrit dans le rapport. Reproduisez la commande sfge sur le point d’entrée SoqlDerivedCondition fourni ; c’est terminé lorsqu’une condition non interprétée n’interrompt plus le point d’entrée et que l’analyse se poursuit sans InternalExecutionError.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- java
- Domaine
- devtools
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Active
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 72/100