code_analyze_core/languages/
java.rs1pub const ELEMENT_QUERY: &str = r"
5(method_declaration
6 name: (identifier) @method_name) @function
7(class_declaration
8 name: (identifier) @class_name) @class
9(interface_declaration
10 name: (identifier) @interface_name) @class
11(enum_declaration
12 name: (identifier) @enum_name) @class
13";
14
15pub const CALL_QUERY: &str = r"
17(method_invocation
18 name: (identifier) @call)
19";
20
21pub const REFERENCE_QUERY: &str = r"
23(type_identifier) @type_ref
24";
25
26pub const IMPORT_QUERY: &str = r"
28(import_declaration) @import_path
29";
30
31pub const DEFUSE_QUERY: &str = r"
33(local_variable_declaration declarator: (variable_declarator name: (identifier) @write.local))
34(assignment_expression left: (identifier) @write.assign)
35(update_expression (identifier) @writeread.update)
36(identifier) @read.usage
37";
38
39use tree_sitter::Node;
40
41#[must_use]
43pub fn extract_inheritance(node: &Node, source: &str) -> Vec<String> {
44 let mut inherits = Vec::new();
45
46 if let Some(superclass) = node.child_by_field_name("superclass") {
48 for i in 0..superclass.named_child_count() {
49 if let Some(child) = superclass.named_child(u32::try_from(i).unwrap_or(u32::MAX))
50 && child.kind() == "type_identifier"
51 {
52 let text = &source[child.start_byte()..child.end_byte()];
53 inherits.push(format!("extends {text}"));
54 }
55 }
56 }
57
58 if let Some(interfaces) = node.child_by_field_name("interfaces") {
60 for i in 0..interfaces.named_child_count() {
61 if let Some(type_list) = interfaces.named_child(u32::try_from(i).unwrap_or(u32::MAX)) {
62 for j in 0..type_list.named_child_count() {
63 if let Some(type_node) =
64 type_list.named_child(u32::try_from(j).unwrap_or(u32::MAX))
65 && type_node.kind() == "type_identifier"
66 {
67 let text = &source[type_node.start_byte()..type_node.end_byte()];
68 inherits.push(format!("implements {text}"));
69 }
70 }
71 }
72 }
73 }
74
75 inherits
76}
77
78#[cfg(all(test, feature = "lang-java"))]
79mod tests {
80 use super::*;
81 use crate::DefUseKind;
82 use crate::parser::SemanticExtractor;
83 use tree_sitter::{Parser, StreamingIterator};
84
85 fn parse_java(src: &str) -> tree_sitter::Tree {
86 let mut parser = Parser::new();
87 parser
88 .set_language(&tree_sitter_java::LANGUAGE.into())
89 .expect("Error loading Java language");
90 parser.parse(src, None).expect("Failed to parse Java")
91 }
92
93 #[test]
94 fn test_java_element_query_happy_path() {
95 let src = "class Animal { void eat() {} }";
97 let tree = parse_java(src);
98 let root = tree.root_node();
99
100 let query = tree_sitter::Query::new(&tree_sitter_java::LANGUAGE.into(), ELEMENT_QUERY)
102 .expect("ELEMENT_QUERY must be valid");
103 let mut cursor = tree_sitter::QueryCursor::new();
104 let mut matches = cursor.matches(&query, root, src.as_bytes());
105
106 let mut captured_classes: Vec<String> = Vec::new();
107 let mut captured_functions: Vec<String> = Vec::new();
108 while let Some(mat) = matches.next() {
109 for capture in mat.captures {
110 let name = query.capture_names()[capture.index as usize];
111 let node = capture.node;
112 match name {
113 "class" => {
114 if let Some(n) = node.child_by_field_name("name") {
115 captured_classes.push(src[n.start_byte()..n.end_byte()].to_string());
116 }
117 }
118 "function" => {
119 if let Some(n) = node.child_by_field_name("name") {
120 captured_functions.push(src[n.start_byte()..n.end_byte()].to_string());
121 }
122 }
123 _ => {}
124 }
125 }
126 }
127
128 assert!(
130 captured_classes.contains(&"Animal".to_string()),
131 "expected Animal class, got {:?}",
132 captured_classes
133 );
134 assert!(
135 captured_functions.contains(&"eat".to_string()),
136 "expected eat function, got {:?}",
137 captured_functions
138 );
139 }
140
141 #[test]
142 fn test_java_extract_inheritance() {
143 let src = "class Dog extends Animal implements ICanRun, ICanSwim {}";
145 let tree = parse_java(src);
146 let root = tree.root_node();
147
148 let mut class_node: Option<tree_sitter::Node> = None;
150 let mut stack = vec![root];
151 while let Some(node) = stack.pop() {
152 if node.kind() == "class_declaration" {
153 class_node = Some(node);
154 break;
155 }
156 for i in 0..node.child_count() {
157 if let Some(child) = node.child(u32::try_from(i).unwrap_or(u32::MAX)) {
158 stack.push(child);
159 }
160 }
161 }
162 let class = class_node.expect("class_declaration not found");
163 let bases = extract_inheritance(&class, src);
164
165 assert!(
167 bases.iter().any(|b| b.contains("Animal")),
168 "expected extends Animal, got {:?}",
169 bases
170 );
171 assert!(
172 bases.iter().any(|b| b.contains("ICanRun")),
173 "expected implements ICanRun, got {:?}",
174 bases
175 );
176 assert!(
177 bases.iter().any(|b| b.contains("ICanSwim")),
178 "expected implements ICanSwim, got {:?}",
179 bases
180 );
181 }
182
183 #[test]
184 fn test_defuse_query_write_site() {
185 let src = "class C { void m() { int z = 5; } }\n";
187 let sites =
188 SemanticExtractor::extract_def_use_for_file(src, "java", "z", "test.java", None);
189 assert!(!sites.is_empty(), "defuse sites should not be empty");
190 let has_write = sites.iter().any(|s| matches!(s.kind, DefUseKind::Write));
191 assert!(has_write, "should contain a Write DefUseSite");
192 }
193}