Extract a function or method definition.
(
&self,
node: &Node,
source: &str,
file_path: &str,
in_class: Option<&str>,
)
| 104 | |
| 105 | /// Extract a function or method definition. |
| 106 | fn extract_function( |
| 107 | &self, |
| 108 | node: &Node, |
| 109 | source: &str, |
| 110 | file_path: &str, |
| 111 | in_class: Option<&str>, |
| 112 | ) -> Option<Entity> { |
| 113 | let name_node = node.child_by_field_name("name")?; |
| 114 | let name = self.node_text(&name_node, source); |
| 115 | |
| 116 | // Skip dunder methods that are noise (__module__, __qualname__, etc.) |
| 117 | // but keep __init__, __str__, __repr__, __eq__, etc. |
| 118 | if name.starts_with("__") && name.ends_with("__") { |
| 119 | let keep = [ |
| 120 | "__init__", |
| 121 | "__new__", |
| 122 | "__del__", |
| 123 | "__str__", |
| 124 | "__repr__", |
| 125 | "__eq__", |
| 126 | "__ne__", |
| 127 | "__lt__", |
| 128 | "__le__", |
| 129 | "__gt__", |
| 130 | "__ge__", |
| 131 | "__hash__", |
| 132 | "__bool__", |
| 133 | "__len__", |
| 134 | "__iter__", |
| 135 | "__next__", |
| 136 | "__contains__", |
| 137 | "__getitem__", |
| 138 | "__setitem__", |
| 139 | "__delitem__", |
| 140 | "__call__", |
| 141 | "__enter__", |
| 142 | "__exit__", |
| 143 | "__aenter__", |
| 144 | "__aexit__", |
| 145 | "__await__", |
| 146 | "__aiter__", |
| 147 | "__anext__", |
| 148 | ]; |
| 149 | if !keep.contains(&name.as_str()) { |
| 150 | return None; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | let kind = if in_class.is_some() { |
| 155 | EntityKind::Method |
| 156 | } else { |
| 157 | EntityKind::Function |
| 158 | }; |
| 159 | |
| 160 | let line = node.start_position().row as u32 + 1; |
| 161 | let end_line = node.end_position().row as u32 + 1; |
| 162 | |
| 163 | // Build signature |
no test coverage detected