#[cfg(feature = "tree-sitter")]
use tree_sitter::Node;
#[cfg(feature = "tree-sitter")]
use super::node_text;
use super::types::ExtMethodDef;
#[cfg(feature = "tree-sitter")]
pub(super) fn extract_ext_methods(root: Node, src: &str, ext: &str) -> Vec<ExtMethodDef> {
if ext != "cs" {
return Vec::new();
}
let mut out: Vec<ExtMethodDef> = Vec::new();
let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();
crate::core::ast_walk::for_each_descendant(root, |node| {
if node.kind() != "method_declaration" || !is_csharp_extension_method(node, src) {
return;
}
let Some(name_node) = node.child_by_field_name("name") else {
return;
};
let name = node_text(name_node, src).trim().to_string();
if name.is_empty() || !seen.insert(name.clone()) {
return;
}
out.push(ExtMethodDef {
name,
line: node.start_position().row + 1,
end_line: node.end_position().row + 1,
});
});
out
}
#[cfg(feature = "tree-sitter")]
fn is_csharp_extension_method(method: Node, src: &str) -> bool {
let Some(params) = method.child_by_field_name("parameters") else {
return false;
};
let mut cursor = params.walk();
let Some(first) = params
.children(&mut cursor)
.find(|c| c.kind() == "parameter")
else {
return false;
};
let mut pcursor = first.walk();
for child in first.children(&mut pcursor) {
if child.kind() == "modifier" && node_text(child, src).trim() == "this" {
return true;
}
}
node_text(first, src).trim_start().starts_with("this ")
}