# Groovy Compiler — Diamond Recursion CWE-407 Scan: CLEAN

**Pattern:** Recursive O(2^D) traversal of interface/trait hierarchy without visited set
**Scan date:** 2026-03-29
**Scope:** `src/main/java/org/codehaus/groovy/`

## Method

Searched for recursive ClassNode hierarchy traversal without proper `if (set.add())` guards.
Traced all callers of `getInterfaces()`, `getSuperClass()`, `getAllInterfaces()`,
`getInterfacesAndSuperInterfaces()`, and `collectAllInterfacesReverseOrder()`.

## Key candidates reviewed

### `ClassNode.getAllInterfaces()` — private `getAllInterfaces(Set)`
`src/main/java/org/codehaus/groovy/ast/ClassNode.java` lines 441–452.

Fixed in GROOVY-11036: now uses `if (set.add(face)) face.getAllInterfaces(set)`.
The guard on `set.add()` return value prevents re-traversal of shared ancestors.
CLEAN (post-fix).

### `GeneralUtils.addAllInterfaces()` / `getInterfacesAndSuperInterfaces()`
`src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java` lines 491–518.

Uses `if (result.add(in)) { addAllInterfaces(result, in); }` for interface branches.
Superclass branch is linear (Java single-inheritance), so no diamond possible there.
CLEAN.

### `Traits.collectAllInterfacesReverseOrder()`
`src/main/java/org/codehaus/groovy/transform/trait/Traits.java` lines 307–316.

Uses `if (interfaces.add(iNode)) collectAllInterfacesReverseOrder(iNode, interfaces)`.
Correct guard. CLEAN.

### `ResolveVisitor` cycle detection
`src/main/java/org/codehaus/groovy/control/ResolveVisitor.java` lines 1363–1381.

Uses BFS with `done.add(next)` as the loop guard. CLEAN.

### `WideningCategories.lowestUpperBound()`
`src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java` lines 319–447.

Recursion on superclass chain (linear, no diamond). Interface sets pre-computed via
`getInterfacesAndSuperInterfaces()` which is guarded. CLEAN.

## Verdict

CLEAN for O(2^D) diamond recursion. Groovy uses `if (set.add(node))` guards on all
recursive interface hierarchy traversal. The two existing defects (groovy-0001,
groovy-0002) are O(N²) list-membership scans, not diamond recursion.
