# UNDF: UNDF-2026-000000598
# UNDF: (pending)
# eclipse-jdt-0002: TypeHierarchy.getAllSupertypes0 — missing Set.add() guard on superclass recursion

## CWE-407 — Algorithmic Complexity: Unconditional recursion into already-visited superclass

| Field        | Value |
|--------------|-------|
| ID           | eclipse-jdt-0002 |
| Severity     | MEDIUM |
| Ecosystem    | eclipse-jdt |
| Package      | org.eclipse.jdt.core |
| File         | `org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java` |
| Lines        | 483–498 |
| Complexity   | Unnecessary superclass subtree re-traversal when superclass already visited via interface path |
| Hot path     | Called during type hierarchy computation for IDE features (Open Type Hierarchy, completion, etc.) |

## Defect

`TypeHierarchy.getAllSupertypes0` recurses through both superinterfaces AND the superclass chain.
For superinterfaces it correctly guards with `if (supers.add(superinterface))` — if the interface
is already in the set, recursion is skipped. But for the superclass, `supers.add(superclass)` is
called without checking the return value:

```java
// TypeHierarchy.java:483-498 (DEFECT)
private Set<IType> getAllSupertypes0(IType type, Set<IType> supers) {
    IType[] superinterfaces = this.typeToSuperInterfaces.get(type);
    if (superinterfaces == null) {
        return supers;
    }
    for (IType superinterface : superinterfaces) {
        if (supers.add(superinterface)) {              // CORRECT: guard on interface recursion
            supers = getAllSuperInterfaces0(superinterface, supers);
        }
    }
    IType superclass = this.classToSuperclass.get(type);
    if (superclass != null) {
        supers.add(superclass);                        // DEFECT: ignores return value
        supers = getAllSupertypes0(superclass, supers); // recurses unconditionally
    }
    return supers;
}
```

When a class's superclass was already added to `supers` via an interface path (e.g., in a hierarchy
where a mixin interface records the concrete class as its supertype in the model), this method recurses
into `getAllSupertypes0(superclass, supers)` even though `superclass` is already fully traversed.
The redundant traversal re-processes superclass's interfaces and its own superclass chain before the
`supers.add()` guards short-circuit each branch.

Contrast with the CORRECT guard pattern used for interfaces on line 489.

## Fix

Apply the same guard pattern to the superclass recursion:

```java
// AFTER — O(N+E) where N=types, E=hierarchy edges
private Set<IType> getAllSupertypes0(IType type, Set<IType> supers) {
    IType[] superinterfaces = this.typeToSuperInterfaces.get(type);
    if (superinterfaces == null) {
        return supers;
    }
    for (IType superinterface : superinterfaces) {
        if (supers.add(superinterface)) {
            supers = getAllSuperInterfaces0(superinterface, supers);
        }
    }
    IType superclass = this.classToSuperclass.get(type);
    if (superclass != null) {
        if (supers.add(superclass)) {                  // FIX: guard matches interface pattern
            supers = getAllSupertypes0(superclass, supers);
        }
    }
    return supers;
}
```

## Speedup

The guard eliminates re-traversal of already-visited superclass subtrees. In deep hierarchies where
a superclass appears via both a class path and an interface model path, the entire subtree below
the superclass is traversed redundantly without the guard. With the guard, each type is traversed
at most once: O(N+E) instead of O((N+E) × revisit_count).
