forcedotcom / forcedotcom/code-analyzer

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

Abierto
#2,097 0 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
TypeScript
Estrellas
240
Forks
52
Merge medio
1 d 23 h
PR fusionados (30 d)
5

Descripción

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

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

Comienza con PathScopeVisitor.java alrededor de las líneas 804-806 y 874-902; después, inspecciona ApexMapValue.java:183-191 y JSONDeserializeFactory.java:78-79 en busca de otros valores indeterminados. Reproduce el problema con el comando sf code-analyzer y la clase Apex proporcionados. La tarea está terminada cuando el punto de entrada completa el análisis sin InternalExecutionError al indexar un valor indeterminado, conservando los hallazgos y la cobertura esperados.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
java
Área
security, tooling
Tipo de issue
Error
Dificultad
3/5
Tiempo estimado
1-2 días
Estado de actividad
Activo
Claridad
Bien especificado
Aptitud para principiantes
72/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.