Class CallGraph

java.lang.Object
org.ek9lang.compiler.phase5.callgraph.CallGraph

public final class CallGraph extends Object
Call graph for EK9 programs with bidirectional edges. Used for reachability analysis, dead code detection, and test validation.

This call graph is built during Phase 5 (PRE_IR_CHECKS) using RTA (Rapid Type Analysis). EK9's closed-world semantics (no reflection, no dynamic loading) means the call graph is 100% sound - all possible call targets are known at compile time.

Key Properties

  • Bidirectional: Query both callers and callees
  • RTA-based: Polymorphic calls filtered by allocated types
  • Thread-safe: Uses ConcurrentHashMap for parallel construction
  • Entry point aware: Distinguishes programs and @Test programs

Analyses Enabled

  • E81007: Empty @Test (no assertions reachable)
  • Orphan assertion detection: assert* not reachable from @Test
  • Assert in production: assert* reachable from non-@Test program
  • Dead code detection: Functions not reachable from any entry point
  • Purity validation: Pure calling impure detection
See Also:
  • Constructor Details

    • CallGraph

      public CallGraph()
  • Method Details

    • registerCallable

      public void registerCallable(CallableInfo info)
      Register a callable entity (function, method, program, etc.).
    • addEdge

      public void addEdge(CallEdge edge)
      Add a call edge from caller to callee.
    • recordAllocatedType

      public void recordAllocatedType(String fullyQualifiedTypeName)
      Record that a type is allocated (instantiated) in the program. Used by RTA to filter polymorphic call targets.
    • getOutgoingCalls

      public Set<CallEdge> getOutgoingCalls(String caller)
      Get all outgoing call edges from a callable.
    • getCallers

      public Set<String> getCallers(String callee)
      Get all callers of a callable.
    • getCallableInfo

      public Optional<CallableInfo> getCallableInfo(String name)
      Get metadata for a callable.
    • getAllCallables

      public Set<String> getAllCallables()
      Get all registered callables.
    • getProgramEntryPoints

      public Set<String> getProgramEntryPoints()
      Get all program entry points (excluding @Test programs).
    • getTestEntryPoints

      public Set<String> getTestEntryPoints()
      Get all @Test program entry points.
    • getAllEntryPoints

      public Set<String> getAllEntryPoints()
      Get all entry points (programs and @Test programs).
    • getAllocatedTypes

      public Set<String> getAllocatedTypes()
      Get all allocated types (used by RTA).
    • isTypeAllocated

      public boolean isTypeAllocated(String typeName)
      Check if a type is allocated (instantiated) in the program.
    • getCallablesWithAssertions

      public Set<String> getCallablesWithAssertions()
      Get all callables that directly contain assertions.
    • isReachableFrom

      public boolean isReachableFrom(String target, Set<String> entryPoints)
      Check if a callable is reachable from any of the given entry points. Uses iterative worklist algorithm for transitive reachability.
      Parameters:
      target - The callable to check reachability for
      entryPoints - Set of entry points to start from
      Returns:
      true if target is transitively reachable from any entry point
    • isReachableFromTests

      public boolean isReachableFromTests(String target)
      Check if a callable is reachable from any @Test entry point.
    • isReachableFromPrograms

      public boolean isReachableFromPrograms(String target)
      Check if a callable is reachable from any non-test program.
    • getReachableCallables

      public Set<String> getReachableCallables(Set<String> entryPoints)
      Get all callables reachable from the given entry points. Uses iterative worklist algorithm.
    • getUnreachableCallables

      public Set<String> getUnreachableCallables()
      Get all callables that are NOT reachable from any entry point (dead code).
    • hasReachableAssertions

      public boolean hasReachableAssertions(String testEntryPoint)
      Check if assertions are transitively reachable from a @Test program. Used for E81007 (empty test) detection.
      Parameters:
      testEntryPoint - The @Test program to check
      Returns:
      true if any assertion is reachable from this test
    • getTestsWithoutAssertions

      public Set<String> getTestsWithoutAssertions()
      Find @Test programs that have no reachable assertions (E81007 candidates). Note: These tests may still be valid if they have expected_output.txt files.
    • getOrphanAssertions

      public Set<String> getOrphanAssertions()
      Find assertion-containing callables that are NOT reachable from any @Test AND are also NOT reachable from production programs. These are "orphan assertions" that will never be executed.

      Note: Assertions reachable from production programs are NOT considered orphans - they have a more specific problem (PRODUCTION_ASSERTION) which is worse because they're actually running in production code using assert instead of require.

    • getAssertionsInProductionCode

      public Set<String> getAssertionsInProductionCode()
      Find assertion-containing callables that ARE reachable from production programs. These are assertions in production code (may or may not be intentional).
    • getEdgeCount

      public int getEdgeCount()
      Get total number of edges in the call graph.
    • getCallableCount

      public int getCallableCount()
      Get total number of registered callables.
    • toString

      public String toString()
      Overrides:
      toString in class Object