Skip to content

Cheat sheet

A single-page reference for the common CLDK calls. Build one analysis object with a per-language factory. Then query it. For background and walkthroughs, see What is CLDK?, Core concepts, and the Quickstart.

pip install cldk

Reachability queries use networkx. pip install cldk installs it as a dependency. If your own code imports networkx directly, install it explicitly too:

pip install cldk networkx

Use the per-language factory for the language you want: CLDK.java(...), CLDK.python(...), or CLDK.typescript(...). The analysis level controls how much CLDK computes.

from cldk import CLDK
from cldk.analysis import AnalysisLevel
# Default level is symbol_table. Use call_graph for callers/callees/reachability.
analysis = CLDK.java(
project_path="commons-cli",
analysis_level=AnalysisLevel.call_graph,
)
print(len(analysis.get_classes()), "classes") # -> 23 classes
ArgumentValueNotes
factoryCLDK.java / CLDK.python / CLDK.typescriptSelects the language facade.
project_pathpath to checkoutThe project to analyze.
analysis_levelsymbol_table (default) / call_graph / program_dependency_graph / system_dependency_graphCall graph, callers, and callees need call_graph. Dataflow and taint need level 3 or 4.
target_fileslist of paths (optional)Restrict analysis to these files.
eagerbool (default False)Force regeneration of cached analysis.
backendconfig object (optional)Selects the backend by type (see below). Omit for the default codeanalyzer backend.

The type of the backend= configuration object selects the backend. Import these types from cldk.analysis.commons.backend_config. Omit backend= for the default in-process codeanalyzer backend. cache_dir and use_ray live inside these configuration objects.

from cldk import CLDK
from cldk.analysis.commons.backend_config import (
CodeAnalyzerConfig,
PyCodeAnalyzerConfig,
Neo4jConnectionConfig,
)
# Default codeanalyzer backend, with an explicit cache root (optional).
analysis = CLDK.java(
project_path="commons-cli",
backend=CodeAnalyzerConfig(cache_dir="/tmp/cache"),
)
# Python codeanalyzer backend with call-graph knobs.
analysis = CLDK.python(
project_path="my_pkg",
backend=PyCodeAnalyzerConfig(use_ray=True),
)
# Read-only Neo4j backend (Java / Python / TypeScript); the graph is populated out of band.
analysis = CLDK.typescript(
backend=Neo4jConnectionConfig(uri="bolt://localhost:7687", username="neo4j", password="neo4j", application_name="my_project"),
)
Config typeBackendNotes
(omit) / CodeAnalyzerConfigIn-process codeanalyzerDefault for Java/TypeScript. cache_dir only.
PyCodeAnalyzerConfigIn-process codeanalyzer (Python)Default for Python. Adds use_ray.
Neo4jConnectionConfig(uri=...)Read-only Neo4j/CypherJava, Python, and TypeScript. project_path is optional. The graph is loaded out of band. See Analysis at scale.

The symbol table is available at every analysis level. It holds every class, method, and field, typed and queryable.

MethodReturnsDescription
get_symbol_table()Dict[str, JCompilationUnit | PyModule | TSModule]The entire project, indexed by file.
get_classes()Dict[str, JType | PyClass | TSClass]Every class or type, keyed by qualified name.
get_methods()Dict[str, Dict]Every method, keyed by class and then by method.
get_method(qualified_class_name, qualified_method_name)JCallable | PyCallable | TSCallable | NoneOne method. .code holds its source body.
m = analysis.get_method(
"org.apache.commons.cli.OptionBuilder", "create(java.lang.String)"
)
print(m.code) # -> source body of OptionBuilder.create(java.lang.String)

Java also gives you class-relationship queries: get_sub_classes(cls), get_extended_classes(cls), and get_implemented_interfaces(cls). It also gives you get_all_comments().

MethodReturnsNotes
get_call_graph()networkx.DiGraphEdges point caller → callee.
get_call_graph_json()strSame graph, serialized.
get_callers(target_class_name, target_method_declaration)DictMethods that call this method.
get_callees(source_class_name, source_method_declaration)DictMethods that this method calls.
get_class_call_graph(qualified_class_name, method_signature=None)List[Tuple]Call-graph edges reachable from one class or method.
cg = analysis.get_call_graph() # -> networkx.DiGraph
callers = analysis.get_callers(
"org.apache.commons.cli.Options", "addOption(org.apache.commons.cli.Option)"
) # -> Dict of call sites

Reachability is a networkx query over the call graph:

import networkx as nx
cg = analysis.get_call_graph()
print(nx.has_path(cg, src, sink)) # reachable? -> True / False
# nx.shortest_path(cg, src, sink) # one path
# list(nx.all_simple_paths(cg, src, sink)) # every path

Dataflow and taint New in 2.0

Section titled “Dataflow and taint ”

CLDK 2.0 adds levels 3 and 4, and the methods over them. Version 2.0 is a release candidate, so install it with pip install --pre cldk. Java, Python, and TypeScript all expose this surface.

MethodReturnsNotes
get_cfg(callable, ...)EdgePage[CfgEdge]Control-flow edges. Page with next_cursor.
get_cdg(callable, ...)EdgePage[CdgEdge]Control-dependence edges.
get_ddg(callable, ...)EdgePage[DdgEdge]Data-dependence edges.
resolve_callable(name, ...)SliceNodeAddress a callable by name.
resolve_value(name, *, within)SliceNodeAddress a value inside a callable.
locate(path, line)LocateResultGo from a file and a line into the graph.
get_source(node_id)strThe source text for a node.
slice_forward(src, *, within, ...)SliceWhere does this value go?
slice_backward(src, *, within, ...)SliceWhat determined this value?
backward_cone(sinks, ...)SliceWhat feeds any of these sinks?
reaches(src, dst, ...)boolDoes it reach it at all?
flows_to_call(src, callee, *, within, ...)boolDoes it reach a call to this callee?
flows_to_argument(src, callee, arg, *, within, ...)boolDoes it reach that argument?
paths_between(src, dst, *, src_within, dst_within, ...)FlowPathsThe routes it takes.
taint(sources, sinks, sanitizers, ...)TaintResultm sources against n sinks in one traversal.
r = analysis.taint(
sources=[("invoice_id", "PaymentPortal.invoice_transaction")],
sinks=[("query", "AccountMove._execute")],
sanitizers=["PaymentPortal._sanitize_id"], # str cuts a callable
) # (name, within) cuts a variable
r.paths # witnesses
r.exhausted # searched, nothing found (empty whenever depth is set)
r.unresolved # the ledger: read this before trusting exhausted

Provenance ranks ssa > reaching-defs > points-to. FlowPath.weakest is the hop that caps the claim. See Dataflow graphs and Taint analysis.

The typed objects that each language analysis API returns.

LanguageModels
JavaJType, JCallable, JCompilationUnit, JField, JComment
PythonPyModule, PyClass, PyCallable, PyImport, PyComment
TypeScriptTSModule, TSClass, TSCallable, TSInterface, TSEnum, TSTypeAlias, TSImport, TSComment