diff --git a/src-tauri/src/commands/ai/code_intel.rs b/src-tauri/src/commands/ai/code_intel.rs index a2206bf..60b70b0 100644 --- a/src-tauri/src/commands/ai/code_intel.rs +++ b/src-tauri/src/commands/ai/code_intel.rs @@ -39,7 +39,7 @@ const DEFINITION_KINDS: &[&str] = &[ "interface_declaration", "enum_declaration", "method_definition", - // TS/JS const/let/var 声明(如 const fn = () => {}) + // TS/JS const/let/var 声明,仅当初始化为函数/类值才算定义(收窄判定见 is_definition_node) "variable_declarator", // Go "method_declaration", // Go method(receiver func) @@ -124,9 +124,45 @@ pub(crate) fn contains_definition(source: &str, ext: &str) -> bool { tree_has_definition(&tree.root_node()) } -/// 递归遍历语法树,判断是否含任一 DEFINITION_KINDS 定义节点(contains_definition 的遍历内核)。 +/// JS/TS 函数/类值表达式 kind:variable_declarator 是否算定义据此判定 +const FUNCTION_VALUE_KINDS: &[&str] = &["arrow_function", "function", "generator_function", "class"]; + +/// 节点是否为可提取定义:kind 在表内,variable_declarator 需初始化为函数/类值。 +/// +/// variable_declarator 单看 kind 过宽:`let msg = "fn main() {}"` 这类普通声明也命中, +/// contains_definition 会对几乎任何 JS/TS 文件误报提示。收窄为 `const fn = () => {}` +/// 形态(初始化值是函数/类表达式)才算定义,contains_definition / read_symbol / +/// outline 三处共用同一判定。 +fn is_definition_node(node: &Node<'_>) -> bool { + if !DEFINITION_KINDS.contains(&node.kind()) { + return false; + } + if node.kind() != "variable_declarator" { + return true; + } + match node.child_by_field_name("value") { + Some(v) => subtree_contains_kind(v, FUNCTION_VALUE_KINDS), + None => false, + } +} + +/// 子树内是否含任一目标 kind 节点 +fn subtree_contains_kind(node: Node<'_>, kinds: &[&str]) -> bool { + if kinds.contains(&node.kind()) { + return true; + } + let mut cursor = node.walk(); + for child in node.children(&mut cursor) { + if subtree_contains_kind(child, kinds) { + return true; + } + } + false +} + +/// 递归遍历语法树,判断是否含任一定义节点(contains_definition 的遍历内核)。 fn tree_has_definition(node: &Node<'_>) -> bool { - if DEFINITION_KINDS.contains(&node.kind()) { + if is_definition_node(node) { return true; } let mut cursor = node.walk(); @@ -246,7 +282,7 @@ pub fn read_symbol( /// 递归遍历找匹配 symbol 名的定义节点。 /// -/// 命中条件:node.kind() 在 DEFINITION_KINDS 内 + name field 文本 == symbol + kind_hint(若传)匹配。 +/// 命中条件:node 为定义节点(is_definition_node)+ name field 文本 == symbol + kind_hint(若传)匹配。 /// 首个命中即返(find_definition 调用方短路)。 fn find_definition<'a>( node: &Node<'a>, @@ -258,7 +294,7 @@ fn find_definition<'a>( if found.is_some() { return; } - if DEFINITION_KINDS.contains(&node.kind()) { + if is_definition_node(node) { let kind_ok = kind_hint.map_or(true, |h| kind_matches(node.kind(), h)); if kind_ok { if let Some(name_node) = node.child_by_field_name("name") { @@ -452,7 +488,7 @@ fn collect_top_level_symbols( line_offset: usize, out: &mut Vec, ) { - if DEFINITION_KINDS.contains(&node.kind()) { + if is_definition_node(&node) { let name = symbol_name(node, source); let kind = node.kind().to_string(); let line = node.start_position().row + 1 + line_offset;