big_code_analysis_ast/lib.rs
1// Per-language modules deliberately consume the macro-generated
2// tree-sitter token enums via `use crate::*` and `use Foo::*` inside
3// match expressions — explicit imports would list dozens of variants per
4// arm and obscure the per-language token sets that are the point of
5// these files. Allowed at the module level rather than per function so
6// the per-language impl blocks stay readable.
7#![allow(clippy::doc_markdown, clippy::enum_glob_use, clippy::wildcard_imports)]
8// Per-language Cargo features let a downstream build only a subset of
9// grammars. In such a build the code for the disabled languages — their
10// macro-generated `*Code` / `*Parser` tags plus the getter / checker
11// helpers only those languages reach — is compiled but never
12// constructed, so `-D dead-code` fires on items that are all live in the
13// default `all-languages` build. Relax dead-code to a warning only when
14// the full language set is NOT enabled; the default build and
15// `--all-features` (and thus the primary CI gate and `make pre-commit`)
16// still hard-deny it, so genuine dead code is caught there.
17#![cfg_attr(not(feature = "all-languages"), allow(dead_code))]
18
19//! The parse and classification layer behind
20//! [`big-code-analysis`](https://crates.io/crates/big-code-analysis).
21//!
22//! This crate turns source bytes into a [`tree_sitter`] tree and
23//! answers structural questions about it: which [`LANG`] a file is in,
24//! what a [`Node`] is (`is_func`, `is_call`, `is_string`, … through
25//! [`Checker`]), what it is called and which Halstead class or
26//! [`SpaceKind`] it opens ([`Getter`]), and how it should be rendered
27//! as an [`AstNode`] ([`Alterator`]). It also owns the C-family
28//! preprocessor pass ([`preproc`]), comment stripping, node counting and
29//! finding, and language detection ([`guess_language`]). It computes no
30//! metric.
31//!
32//! # Stability
33//!
34//! **This crate is internal plumbing.** It exists so the metric walk in
35//! `big-code-analysis` and any future structural consumer (a linter, a
36//! call-graph builder, a language server) can share one classification
37//! layer without the metric machinery. `big-code-analysis` pins it at
38//! an exact `=X.Y.Z` version, the two are released together, and no
39//! item here carries a stability promise of its own: names, signatures
40//! and module paths may change in any release. Depend on
41//! `big-code-analysis` and reach what it re-exports; depend on this
42//! crate directly only when you accept re-pinning on every release.
43//!
44//! The one contract that does hold is the one `big-code-analysis`
45//! documents in its `STABILITY.md` for the items it re-exports from
46//! here (`LANG`, `Node`, `MetricsError`, `SpaceKind`, the AST dump
47//! types, the preprocessor types, the file readers). Those are stable
48//! *through that crate*.
49//!
50//! # Layout
51//!
52//! - [`languages`]: one generated enum per grammar, one variant per
53//! tree-sitter kind id.
54//! - [`langs`]: the [`LANG`] enum, extension / emacs-mode lookup, the
55//! per-language `*Code` tags and `*Parser` aliases, and [`AnyParser`],
56//! the runtime-dispatched parser every consumer matches on with
57//! [`with_any_parser!`].
58//! - [`node`], [`traits`], [`parser`]: the tree-sitter wrappers and the
59//! [`ParserTrait`] / [`Search`] / [`LanguageInfo`] contracts.
60//! - [`checker`], [`getter`], [`alterator`], [`lang_helpers`]: the
61//! per-language classifiers and the byte-level identity helpers they
62//! share with the metrics.
63//! - [`preproc`], `c_macro`, [`c_declarator`]: the C-family pipeline.
64//! - `comment_rm`, [`ast`], [`count`], `find`, [`tools`]: the
65//! per-file operations reached through `big_code_analysis::Ast`.
66//!
67//! The unlinked names above are crate-private modules, reached only
68//! through the `AnyParser` methods `mk_action!` generates.
69
70#![allow(clippy::upper_case_acronyms)]
71// Production-only `unwrap()` ban. See `[workspace.lints.clippy]` in the
72// root `Cargo.toml` for why this is a per-root attribute and not a
73// Cargo lint (#1227).
74#![cfg_attr(not(test), warn(clippy::unwrap_used))]
75// The `pub(crate)` entries below are named by nothing outside this
76// crate, so they stay narrow per AGENTS.md ("widen visibility only when
77// an item is re-exported from `lib.rs`"). `comment_rm` and `find` look
78// like exceptions and are not: they are reached through `$crate::` in
79// `mk_action!`, which expands here.
80
81// The import half of the `allow(dead_code)` carve-out above, and for
82// the same reason: per-language test gating (#1472) makes "is this
83// import live" a function of the enabled feature set, which no `cfg` on
84// the import itself can express. Partial builds only — `all-languages`
85// is on by default and under `--all-features`, so the build CI gates on
86// and the one a contributor runs still police every unused import. See
87// `.claude/rules/testing.md`, "Why the import lint is off on a partial
88// build".
89#![cfg_attr(not(feature = "all-languages"), allow(unused_imports))]
90pub mod alterator;
91pub mod ast;
92pub mod c_declarator;
93pub(crate) mod c_langs_macros;
94pub(crate) mod c_macro;
95pub(crate) mod cfg_predicate;
96pub mod checker;
97pub(crate) mod comment_rm;
98pub mod count;
99pub mod error;
100pub(crate) mod find;
101pub mod getter;
102pub mod lang_helpers;
103pub mod langs;
104pub mod languages;
105pub mod macros;
106pub mod node;
107pub mod observation;
108pub mod parser;
109pub mod preproc;
110pub mod recursion;
111pub mod space_kind;
112pub mod token_role;
113pub mod tools;
114pub mod traits;
115
116#[cfg(test)]
117mod language_enum_roundtrip;
118
119/// Parse-and-inspect helpers for tests, in this crate and in
120/// `big-code-analysis`'s metric tests (behind the `test-support`
121/// feature). Never part of a shipping build.
122#[cfg(any(test, feature = "test-support"))]
123#[doc(hidden)]
124pub mod test_support;
125
126// Flat re-exports. The per-language modules reach every token enum, tag
127// and classifier through `use crate::*`; `big-code-analysis` does the
128// same through one `pub use big_code_analysis_ast::*`, so the
129// names below are the crate's working vocabulary rather than a curated
130// public surface.
131pub use crate::alterator::Alterator;
132pub use crate::ast::{AstCfg, AstNode, AstPayload, AstResponse, MAX_AST_SERIALIZE_DEPTH, Span};
133pub use crate::checker::*;
134pub use crate::count::{Count, CountCollector};
135pub use crate::error::MetricsError;
136pub use crate::getter::Getter;
137pub use crate::langs::*;
138pub use crate::languages::*;
139pub use crate::macros::ParseLangError;
140pub use crate::node::{Ancestors, Node};
141pub use crate::parser::Parser;
142pub use crate::preproc::{
143 PreprocDiagnostic, PreprocFile, PreprocResults, fix_includes, get_macros, preprocess,
144};
145pub use crate::space_kind::SpaceKind;
146pub use crate::token_role::TokenRole;
147pub use crate::tools::{
148 SkipReason, get_language_for_file, guess_language, is_generated, normalize_eol, read_file,
149 read_file_with_eol, read_file_with_eol_classified, write_file,
150};
151pub use crate::traits::{LanguageInfo, ParserTrait, Search};
152
153/// Re-export of the underlying `tree-sitter` crate, so a consumer can
154/// build a [`tree_sitter::Tree`] against the exact grammar version this
155/// crate is pinned to.
156pub use ::tree_sitter;