sdivi_lang_java/lib.rs
1//! Java language adapter for sdivi-rust.
2//!
3//! Implements [`sdivi_parsing::adapter::LanguageAdapter`] for `.java` source files
4//! using the `tree-sitter-java` grammar.
5//!
6//! # Thread safety
7//!
8//! `tree_sitter::Parser` is not `Send`. Parsers are stored in `thread_local!`
9//! storage so that `JavaAdapter` itself can be `Send + Sync` and participate
10//! in rayon parallel parsing.
11
12mod extract;
13
14use std::cell::RefCell;
15use std::path::Path;
16
17use sdivi_parsing::adapter::LanguageAdapter;
18use sdivi_parsing::feature_record::FeatureRecord;
19
20use extract::{collect_hints, extract_exports, extract_imports, extract_signatures};
21
22thread_local! {
23 static PARSER: RefCell<tree_sitter::Parser> = RefCell::new({
24 let mut p = tree_sitter::Parser::new();
25 p.set_language(&tree_sitter_java::language())
26 .expect("tree-sitter-java grammar failed to load");
27 p
28 });
29}
30
31/// Language adapter for Java source files.
32///
33/// Parses `.java` files with the `tree-sitter-java` grammar and extracts:
34/// - `imports` from `import` declarations
35/// - `exports` from top-level `public` class and interface declarations
36/// - `signatures` from `public` method declarations
37/// - `pattern_hints` for the patterns stage
38///
39/// # Examples
40///
41/// ```rust
42/// use sdivi_lang_java::JavaAdapter;
43/// use sdivi_parsing::adapter::LanguageAdapter;
44///
45/// let adapter = JavaAdapter;
46/// assert_eq!(adapter.language_name(), "java");
47/// assert!(adapter.file_extensions().contains(&".java"));
48/// ```
49pub struct JavaAdapter;
50
51impl LanguageAdapter for JavaAdapter {
52 fn language_name(&self) -> &'static str {
53 "java"
54 }
55
56 fn file_extensions(&self) -> &[&'static str] {
57 &[".java"]
58 }
59
60 /// Parses `content` and returns a [`FeatureRecord`].
61 ///
62 /// The tree-sitter CST is created, traversed, and **dropped** before this
63 /// method returns. No tree-sitter type escapes into the returned record.
64 fn parse_file(&self, path: &Path, content: String) -> FeatureRecord {
65 let source = content.as_bytes();
66
67 let (imports, exports, signatures, pattern_hints) = PARSER.with(|cell| {
68 let mut parser = cell.borrow_mut();
69 let tree = parser
70 .parse(source, None)
71 .expect("tree-sitter-java failed to parse");
72 let root = tree.root_node();
73 let imports = extract_imports(root, source);
74 let exports = extract_exports(root, source);
75 let signatures = extract_signatures(root, source);
76 let hints = collect_hints(root, source);
77 (imports, exports, signatures, hints)
78 });
79
80 FeatureRecord {
81 path: path.to_path_buf(),
82 language: "java".to_string(),
83 imports,
84 exports,
85 signatures,
86 pattern_hints,
87 }
88 }
89}