Reusing an existing tree-sitter Tree
A common pain point is that callers who already drive
tree-sitter for syntax highlighting, code folding, or queries
end up parsing every file twice: once for their own tree, once
inside get_function_spaces. The parse seam (issue #251) lets you
hand big-code-analysis an already-parsed tree_sitter::Tree and
get the same FuncSpace back without re-parsing.
Prefer
Ast::from_tree_sitterif you also want to run the metric walker more than once against the same parse (differentMetricsOptions::with_onlyselections, custom tree-sitter walks interleaved with metrics, etc.). See Parse once, run metrics many times. Themetrics_from_treefunction shown below is a single-shot equivalent that constructs anAstinternally and discards it after one call.
When to use this
Use the parse seam if you:
- Already keep a
tree_sitter::Treeper open buffer (editor, LSP, language server, custom static-analysis pipeline) and want to reuse that parse for metrics rather than paying the byte-based cost again. - Want to run multiple passes (metrics + AST dump + custom analysis) against one parse result.
- Intend to pin
tree-sitteron your side without taking a separate dependency from this library. The re-exportedbig_code_analysis::tree_sittermodule is the same crate we link against, so the types agree by definition.
Use the byte-based entry points
(get_function_spaces / metrics_with_options) if
you do not already have a tree — they construct the parser
internally and own the parse end to end.
Working example
use std::path::PathBuf; use big_code_analysis::{ get_function_spaces, metrics_from_tree, tree_sitter, LANG, MetricsOptions, }; let source_code = "fn main() { if true { 1 } else { 2 }; }"; let path = PathBuf::from("foo.rs"); let source = source_code.as_bytes().to_vec(); // Step 1: build a tree with the *re-exported* tree-sitter crate. // Using `big_code_analysis::tree_sitter` (rather than a direct // `tree-sitter` dependency on your side) guarantees the version // matches the one the metric walker was compiled against. let mut parser = tree_sitter::Parser::new(); parser .set_language(&LANG::Rust.get_tree_sitter_language()) .expect("rust grammar pinned to a compatible version"); let tree = parser .parse(&source, None) .expect("parser has a language set"); // Step 2: feed the tree into metrics_from_tree. let from_tree = metrics_from_tree( &LANG::Rust, tree, source.clone(), &path, None, MetricsOptions::default(), ) .expect("non-empty input"); // Step 3 (optional): confirm the values match the byte-based path. let from_bytes = get_function_spaces(&LANG::Rust, source, &path, None) .expect("non-empty input"); assert_eq!( from_tree.metrics.cyclomatic.cyclomatic_sum(), from_bytes.metrics.cyclomatic.cyclomatic_sum(), );
The same shape works for any LANG variant — pass the
matching grammar to tree_sitter::Parser::set_language (via
LANG::get_tree_sitter_language) and the metric
walker will produce the same FuncSpace it would have produced
from bytes.
Lower-level: Parser::from_tree (internal)
metrics_from_tree is the documented entry point for tree reuse —
it dispatches on a &LANG and hides the generic parser plumbing
entirely. The lower-level path goes through Parser<T> /
ParserTrait, which are now #[doc(hidden)] (see issue #256). They
remain pub so the in-tree macros (mk_action!, action::<T>,
the Callback dispatch shared with the REST API) can refer to
them, but they are not part of the documented surface and treating
them as a stable extension point is at your own risk.
The per-language *Parser aliases (RustParser, PythonParser,
…) emitted by mk_langs! are doc-hidden for the same reason —
see STABILITY.md for the escape-hatch caveat. For library
consumers, the higher-level metrics_from_tree shown above is the
right entry point because it dispatches on a &LANG at runtime
and does not expose any of the per-language tag types or trait
bounds.
Out of scope
- Incremental re-computation. Applying a
tree_sitter::InputEditand re-querying only the changed spans is not supported yet — the metric walker still walks the entire tree on every call. The parse seam is the first step; making the walker itself incremental is a follow-up. - Promoting all of
Node'spub(crate)traversal methods.Nodestill exposes its innertree_sitter::Nodethrough the public.0field for ad-hoc traversal; the wrapper helpers remain crate-private and are tracked under thepub usecuration issue.