forcedotcom / forcedotcom/code-analyzer

[BUG][code-analyzer] sfge: indexing a value the engine cannot resolve aborts the entry point instead of degrading

Aperta
#2,097 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
TypeScript
Stelle
240
Fork
52
Merge medio
1g 23h
PR unite (30g)
5

Descrizione

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

An array/index load whose target resolves to an indeterminate `ApexSingleValue` aborts path evaluation — in a method that already returns an indeterminate value for every other input.

```apex
List parts = (List) byKey.get('k'); // byKey is Map
String first = parts[0];
```

`ApexMapValue.apply` takes the indeterminate branch of `METHOD_GET` (`ApexMapValue.java:183-191`) and returns a bare indeterminate value typed from the map's declared value type. Because that type is `Object`, `build()` yields an `ApexSingleValue` rather than an `ApexListValue`, and indexing it hits the unhandled `else` at `PathScopeVisitor.java:894`. The Apex cast to `List` does not help — the engine keeps the map's declared value type. `JSONDeserializeFactory.java:78-79` builds the same shape for types it declines to model, so this is not the only route in.

**The fix already exists in the same method:**

```java
// PathScopeVisitor.java:874-902
private ApexValue getIndeterminantArrayLoadValue(@Nullable ApexValue apexValue) {
final Typeable listType;
if (apexValue instanceof ApexListValue) { ...
} else if (apexValue instanceof ApexForLoopValue) { ...
} else if (apexValue instanceof ApexSoqlValue) { ...
} else if (apexValue == null) {
listType = null; // <-- null is fine
} else {
throw new UnexpectedException(apexValue); // <-- everything else aborts
}

ApexValueBuilder builder = ApexValueBuilder.get(this).withStatus(ValueStatus.INDETERMINANT);
if (listType != null) {
return builder.declarationVertex(listType).build();
} else {
return builder.buildUnknownType(); // <-- the null branch lands here
}
}
```

A `null` `apexValue` — strictly *less* information than an indeterminate `ApexSingleValue` — falls through to `buildUnknownType()`.

### Output / Logs

```shell
UnexpectedException: ApexValue(ApexSingleValue) {status=INDETERMINANT, declarationVertex=SyntheticTypedVertex@...,
valueVertex=null, returnedFrom=ApexValue(ApexMapValue) {status=INDETERMINANT,
declarationVertex=Parameter{... Type=Map ... Name=byKey}} ...}
at com.salesforce.graph.symbols.PathScopeVisitor.getIndeterminantArrayLoadValue(PathScopeVisitor.java:894)
at com.salesforce.graph.symbols.PathScopeVisitor.afterVisit(PathScopeVisitor.java:810)
at com.salesforce.graph.symbols.DefaultSymbolProviderVertexVisitor.afterVisit(DefaultSymbolProviderVertexVisitor.java:737)
at com.salesforce.graph.vertex.ArrayLoadExpressionVertex.afterVisit(ArrayLoadExpressionVertex.java:58)
```

### 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/IndeterminateMapGetIndex.cls` with the class shown below, plus a standard `IndeterminateMapGetIndex.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 IndeterminateMapGetIndex {
@AuraEnabled
public static void run(Map byKey) {
List parts = (List) byKey.get('k');
String first = parts[0];
Account a = new Account();
a.Name = first;
insert a;
}
}
```

### Expected Behavior

Routing the `else` to `listType = null` would make the unknown case behave like the already-unknown case, which is what the method's name and Javadoc promise ("Generates a single indeterminant value based on the type contained in `apexValue`").

The caller has the same gap: `PathScopeVisitor.java:804-806` carries a matching bare `throw new UnexpectedException(vertex)` on its own `else`.

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

`Map` is the standard way to accept a loosely typed payload in an `@AuraEnabled` method, and indexing a list pulled out of one is routine.

Costs three `@AuraEnabled` entry points in our codebase via two different routes — the map shape above, and a static initializer in a shared constants class that indexes a `String.split()` result. The second is the worse pattern: because it sits in a constants class, every entry point that touches it inherits the abort.

### Workaround

Assign through an intermediate typed local that sfge can resolve, or avoid indexing values pulled out of an `Object`-valued map on paths that reach DML. Neither is dependable.

### Urgency

Moderate

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Start with PathScopeVisitor.java around lines 804-806 and 874-902, then inspect ApexMapValue.java:183-191 and JSONDeserializeFactory.java:78-79 for other indeterminate values. Reproduce the issue with the provided sf code-analyzer command and Apex class. Done means the entry point completes analysis without InternalExecutionError when an indeterminate value is indexed, while preserving expected findings and coverage.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
java
Ambito
security, tooling
Tipo di issue
Bug
Difficoltà
3/5
Tempo stimato
1-2 giorni
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
72/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.