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.
Install
Section titled “Install”pip install cldkReachability 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 networkxConstruct
Section titled “Construct”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 CLDKfrom 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 classesfrom cldk import CLDKfrom cldk.analysis import AnalysisLevel
analysis = CLDK.python( project_path="my_pkg", analysis_level=AnalysisLevel.call_graph,)print(len(analysis.get_classes()), "classes")from cldk import CLDKfrom cldk.analysis import AnalysisLevel
analysis = CLDK.typescript( project_path="my_app", analysis_level=AnalysisLevel.call_graph,)print(len(analysis.get_classes()), "classes")| Argument | Value | Notes |
|---|---|---|
| factory | CLDK.java / CLDK.python / CLDK.typescript | Selects the language facade. |
project_path | path to checkout | The project to analyze. |
analysis_level | symbol_table (default) / call_graph / program_dependency_graph / system_dependency_graph | Call graph, callers, and callees need call_graph. Dataflow and taint need level 3 or 4. |
target_files | list of paths (optional) | Restrict analysis to these files. |
eager | bool (default False) | Force regeneration of cached analysis. |
backend | config object (optional) | Selects the backend by type (see below). Omit for the default codeanalyzer backend. |
Select a backend
Section titled “Select a 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 CLDKfrom 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 type | Backend | Notes |
|---|---|---|
(omit) / CodeAnalyzerConfig | In-process codeanalyzer | Default for Java/TypeScript. cache_dir only. |
PyCodeAnalyzerConfig | In-process codeanalyzer (Python) | Default for Python. Adds use_ray. |
Neo4jConnectionConfig(uri=...) | Read-only Neo4j/Cypher | Java, Python, and TypeScript. project_path is optional. The graph is loaded out of band. See Analysis at scale. |
Symbol table
Section titled “Symbol table”The symbol table is available at every analysis level. It holds every class, method, and field, typed and queryable.
| Method | Returns | Description |
|---|---|---|
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 | None | One 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().
Call graph and reachability
Section titled “Call graph and reachability”| Method | Returns | Notes |
|---|---|---|
get_call_graph() | networkx.DiGraph | Edges point caller → callee. |
get_call_graph_json() | str | Same graph, serialized. |
get_callers(target_class_name, target_method_declaration) | Dict | Methods that call this method. |
get_callees(source_class_name, source_method_declaration) | Dict | Methods 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.DiGraphcallers = analysis.get_callers( "org.apache.commons.cli.Options", "addOption(org.apache.commons.cli.Option)") # -> Dict of call sitesReachability 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 pathDataflow 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.
| Method | Returns | Notes |
|---|---|---|
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, ...) | SliceNode | Address a callable by name. |
resolve_value(name, *, within) | SliceNode | Address a value inside a callable. |
locate(path, line) | LocateResult | Go from a file and a line into the graph. |
get_source(node_id) | str | The source text for a node. |
slice_forward(src, *, within, ...) | Slice | Where does this value go? |
slice_backward(src, *, within, ...) | Slice | What determined this value? |
backward_cone(sinks, ...) | Slice | What feeds any of these sinks? |
reaches(src, dst, ...) | bool | Does it reach it at all? |
flows_to_call(src, callee, *, within, ...) | bool | Does it reach a call to this callee? |
flows_to_argument(src, callee, arg, *, within, ...) | bool | Does it reach that argument? |
paths_between(src, dst, *, src_within, dst_within, ...) | FlowPaths | The routes it takes. |
taint(sources, sinks, sanitizers, ...) | TaintResult | m 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 variabler.paths # witnessesr.exhausted # searched, nothing found (empty whenever depth is set)r.unresolved # the ledger: read this before trusting exhaustedProvenance ranks ssa > reaching-defs > points-to. FlowPath.weakest is the hop that caps the claim. See Dataflow graphs and Taint analysis.
Models
Section titled “Models”The typed objects that each language analysis API returns.
| Language | Models |
|---|---|
| Java | JType, JCallable, JCompilationUnit, JField, JComment |
| Python | PyModule, PyClass, PyCallable, PyImport, PyComment |
| TypeScript | TSModule, TSClass, TSCallable, TSInterface, TSEnum, TSTypeAlias, TSImport, TSComment |