Skip to main content

code_repo_wiki/search/
ast.rs

1use std::collections::HashMap;
2use tree_sitter::{Language, Parser};
3use anyhow::{Result, anyhow};
4
5/// AST 查询器:统一的 tree-sitter 查询接口
6///
7/// 封装多种语言的 tree-sitter parser,提供符号定位和引用查询。
8pub struct AstQuery {
9    language: String,
10    parser: Parser,
11}
12
13/// 查询匹配结果
14#[derive(Debug, Clone)]
15pub struct QueryMatch {
16    /// 捕获名称 → 匹配文本
17    pub captures: HashMap<String, String>,
18    /// 捕获名称 → 起始行号(1-based)
19    pub capture_lines: HashMap<String, usize>,
20    /// 完整匹配的起始行
21    pub start_line: usize,
22    /// 完整匹配的结束行
23    pub end_line: usize,
24}
25
26impl AstQuery {
27    /// 创建新的 AST 查询器
28    pub fn new(language: &str) -> Result<Self> {
29        let lang = get_language(language)?;
30        let mut parser = Parser::new();
31        parser.set_language(&lang).map_err(|e| anyhow!("设置语言失败: {}", e))?;
32        Ok(Self { language: language.to_string(), parser })
33    }
34
35    /// 查找符号定义位置
36    ///
37    /// 手动遍历 AST,找到 name 与 symbol 匹配的顶层定义节点。
38    /// 不依赖 tree-sitter Query API,兼容所有 tree-sitter 版本。
39    pub fn find_definition(&mut self, source: &str, symbol: &str) -> Result<Option<QueryMatch>> {
40        let tree = self.parser.parse(source, None)
41            .ok_or_else(|| anyhow!("解析源码失败"))?;
42        let bytes = source.as_bytes();
43        let _root = tree.root_node();
44        let mut result = None;
45
46        // 定义节点类型列表:各语言中可能包含定义的节点类型
47        let def_types = match self.language.as_str() {
48            "rust" => &["function_item", "struct_item", "trait_item", "enum_item", "type_item", "const_item", "static_item", "impl_item", "mod_item"][..],
49            "python" => &["function_definition", "class_definition", "assignment"][..],
50            "javascript" | "typescript" => &["function_declaration", "class_declaration", "method_definition", "variable_declaration", "interface_declaration", "type_alias_declaration", "enum_declaration"][..],
51            "go" => &["function_declaration", "type_declaration", "type_spec", "const_declaration", "var_declaration"][..],
52            "csharp" => &["method_declaration", "class_declaration", "struct_declaration", "interface_declaration", "enum_declaration", "delegate_declaration", "property_declaration"][..],
53            _ => return Ok(None),
54        };
55
56        // 对顶层节点做 BFS 遍历
57        let mut cursor = tree.walk();
58        'outer: loop {
59            let node = cursor.node();
60            if def_types.contains(&node.kind()) && let Some(name_node) = node.child_by_field_name("name") && let Ok(name) = name_node.utf8_text(bytes) && name == symbol {
61                let mut captures = HashMap::new();
62                let mut capture_lines = HashMap::new();
63                if let Ok(text) = node.utf8_text(bytes) {
64                    captures.insert("name".to_string(), text.to_string());
65                }
66                capture_lines.insert("name".to_string(), name_node.start_position().row + 1);
67                result = Some(QueryMatch {
68                    captures,
69                    capture_lines,
70                    start_line: node.start_position().row + 1,
71                    end_line: node.end_position().row + 1,
72                });
73                break 'outer;
74            }
75
76            if cursor.goto_first_child() { continue; }
77            loop {
78                if cursor.goto_next_sibling() { continue 'outer; }
79                if !cursor.goto_parent() { break 'outer; }
80            }
81        }
82
83        Ok(result)
84    }
85
86    /// 获取解析结果中的顶层实体名列表
87    pub fn list_definitions(&mut self, source: &str) -> Result<Vec<String>> {
88        let tree = self.parser.parse(source, None)
89            .ok_or_else(|| anyhow!("解析源码失败"))?;
90        let bytes = source.as_bytes();
91        let mut defs = Vec::new();
92
93        let def_types = match self.language.as_str() {
94            "rust" => &["function_item", "struct_item", "trait_item", "enum_item", "type_item", "const_item", "impl_item"][..],
95            "python" => &["function_definition", "class_definition"][..],
96            "javascript" | "typescript" => &["function_declaration", "class_declaration", "method_definition", "interface_declaration"][..],
97            "go" => &["function_declaration", "type_spec"][..],
98            "csharp" => &["method_declaration", "class_declaration", "struct_declaration", "interface_declaration"][..],
99            _ => return Ok(defs),
100        };
101
102        let mut cursor = tree.walk();
103        'walk: loop {
104            let node = cursor.node();
105            if def_types.contains(&node.kind()) && let Some(name_node) = node.child_by_field_name("name") && let Ok(name) = name_node.utf8_text(bytes) {
106                defs.push(name.to_string());
107            }
108
109            if cursor.goto_first_child() { continue; }
110            loop {
111                if cursor.goto_next_sibling() { continue 'walk; }
112                if !cursor.goto_parent() { break 'walk; }
113            }
114        }
115
116        defs.sort();
117        defs.dedup();
118        Ok(defs)
119    }
120}
121
122/// 获取指定语言的 tree-sitter Language
123pub fn get_language(name: &str) -> Result<Language> {
124    match name {
125        "rust" => Ok(tree_sitter_rust::LANGUAGE.into()),
126        "python" => Ok(tree_sitter_python::LANGUAGE.into()),
127        "javascript" => Ok(tree_sitter_javascript::LANGUAGE.into()),
128        "typescript" | "tsx" => Ok(tree_sitter_typescript::LANGUAGE_TSX.into()),
129        "go" => Ok(tree_sitter_go::LANGUAGE.into()),
130        "csharp" => Ok(tree_sitter_c_sharp::LANGUAGE.into()),
131        _ => anyhow::bail!("不支持的语言: {}", name),
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn test_find_definition_rust() {
141        let mut q = AstQuery::new("rust").unwrap();
142        let source = "struct Point { x: i32, y: i32 }\nfn add(a: i32, b: i32) -> i32 { a + b }";
143        let found = q.find_definition(source, "add").unwrap();
144        assert!(found.is_some());
145        let m = found.unwrap();
146        assert!(m.captures.contains_key("name"));
147    }
148
149    #[test]
150    fn test_find_definition_not_found() {
151        let mut q = AstQuery::new("rust").unwrap();
152        let source = "fn foo() {}";
153        let found = q.find_definition(source, "bar").unwrap();
154        assert!(found.is_none());
155    }
156
157    #[test]
158    fn test_list_definitions() {
159        let mut q = AstQuery::new("rust").unwrap();
160        let source = "struct A;\nfn b() {}\ntrait C {}";
161        let defs = q.list_definitions(source).unwrap();
162        assert!(defs.contains(&"A".to_string()));
163        assert!(defs.contains(&"b".to_string()));
164        assert!(defs.contains(&"C".to_string()));
165    }
166
167    #[test]
168    fn test_python_definition() {
169        let mut q = AstQuery::new("python").unwrap();
170        let source = "def hello(): pass\nclass World: pass";
171        let defs = q.list_definitions(source).unwrap();
172        assert!(defs.contains(&"hello".to_string()));
173        assert!(defs.contains(&"World".to_string()));
174    }
175
176    #[test]
177    fn test_js_definition() {
178        let mut q = AstQuery::new("javascript").unwrap();
179        let source = "function add(a, b) { return a + b; }";
180        let found = q.find_definition(source, "add").unwrap();
181        assert!(found.is_some());
182    }
183
184    #[test]
185    fn test_list_definitions_empty() {
186        let mut q = AstQuery::new("rust").unwrap();
187        let defs = q.list_definitions("").unwrap();
188        assert!(defs.is_empty());
189    }
190}