Skip to content

Core concepts

CLDK analyzes a project and exposes structured, queryable program facts through a single analysis object. Structural questions (such as which methods call a given method) are answered directly from the call graph rather than by reading individual source files.

This page describes the two kinds of facts CLDK produces (symbol tables and call graphs) and the analysis levels that determine how much work CLDK performs to build them. Every example uses the sample project Apache Commons CLI (project_path="commons-cli"), the same checkout used in Quickstart and cocoa.

A symbol table is the structured inventory of a project: every file, class, method, field, and signature, resolved and ready to query. It is produced by default and requires no call-graph analysis.

Use it to enumerate or look up code structure: for example, to list a project’s classes, retrieve a method’s source body, or inspect fields and signatures.

from cldk import CLDK
analysis = CLDK.java(project_path="commons-cli")
# Whole-project inventory: file path -> JCompilationUnit
symbol_table = analysis.get_symbol_table()
# All classes: qualified name -> JType
classes = analysis.get_classes()
print(len(classes))
# -> 60 (number of types in Commons CLI)
# One method by qualified class + signature -> JCallable
# Parameter types in the signature are fully qualified.
method = analysis.get_method(
"org.apache.commons.cli.Options", "addOption(org.apache.commons.cli.Option)"
)
print(method.code)
# -> "public Options addOption(Option opt) { ... }" (the source body)

C is more limited: it exposes the symbol table through get_c_application() and get_functions() (function name -> CFunction), but has no call graph: see the note under Analysis levels.

A call graph records the caller/callee relationships in a project: each node is a method, and each directed edge points from a caller to a callee it invokes. It represents how the code is connected as a graph that can be traversed.

flowchart LR
    A["CLI.main"] --> B["DefaultParser.parse"]
    B --> C["Options.addOption"]
    B --> D["CommandLine.addOption"]

CLDK exposes the graph as a networkx.DiGraph (edges point from caller to callee), along with direct neighbor queries. Call graphs support impact analysis, dependency tracing, and other questions about how methods are connected.

from cldk import CLDK
from cldk.analysis import AnalysisLevel
analysis = CLDK.java(
project_path="commons-cli",
analysis_level=AnalysisLevel.call_graph, # required for call edges
)
cg = analysis.get_call_graph() # networkx.DiGraph, caller -> callee
print(cg.number_of_edges())
# -> 412 (call edges in Commons CLI)
# Callers of this method (impact analysis)
callers = analysis.get_callers(
"org.apache.commons.cli.Options", "addOption(org.apache.commons.cli.Option)"
)
# Methods invoked by this method
callees = analysis.get_callees(
"org.apache.commons.cli.DefaultParser",
"parse(org.apache.commons.cli.Options, java.lang.String[])",
)

The analysis level controls how much work CLDK does when it builds the analysis object. There are two:

  • AnalysisLevel.symbol_table: the default. Resolves structure (classes, methods, fields, signatures). Fast, and enough for symbol-table queries.
  • AnalysisLevel.call_graph: additionally computes call edges. Required for get_call_graph, get_callers, and get_callees.
from cldk import CLDK
from cldk.analysis import AnalysisLevel
# Default: symbol table only (call edges are NOT populated)
st = CLDK.java(project_path="commons-cli")
# Opt in to call-graph depth when you need call relationships
cg = CLDK.java(
project_path="commons-cli",
analysis_level=AnalysisLevel.call_graph,
)

Java supports a single-file mode via CLDK.java(source_code="...") for quick syntactic work, though it is deprecated; prefer project_path. Python requires project_path. Both expose the same symbol-table and call-graph methods through analysis.