Extract a function/method definition node. Returns True if the child was handled (function with a name found).
(
self,
child,
source: bytes,
language: str,
file_path: str,
nodes: list[NodeInfo],
edges: list[EdgeInfo],
enclosing_class: Optional[str],
import_map: Optional[dict[str, str]],
defined_names: Optional[set[str]],
_depth: int,
enclosing_func: Optional[str] = None,
)
| 4350 | return True |
| 4351 | |
| 4352 | def _extract_functions( |
| 4353 | self, |
| 4354 | child, |
| 4355 | source: bytes, |
| 4356 | language: str, |
| 4357 | file_path: str, |
| 4358 | nodes: list[NodeInfo], |
| 4359 | edges: list[EdgeInfo], |
| 4360 | enclosing_class: Optional[str], |
| 4361 | import_map: Optional[dict[str, str]], |
| 4362 | defined_names: Optional[set[str]], |
| 4363 | _depth: int, |
| 4364 | enclosing_func: Optional[str] = None, |
| 4365 | ) -> bool: |
| 4366 | """Extract a function/method definition node. |
| 4367 | |
| 4368 | Returns True if the child was handled (function with a name found). |
| 4369 | """ |
| 4370 | name = self._get_name(child, language, "function") |
| 4371 | if not name: |
| 4372 | return False |
| 4373 | |
| 4374 | # Go methods: attach to their receiver type as the enclosing class, |
| 4375 | # so `func (s *T) Foo()` becomes a member of T rather than a |
| 4376 | # top-level function. See: #190 |
| 4377 | if language == "go" and child.type == "method_declaration": |
| 4378 | receiver_type = self._get_go_receiver_type(child) |
| 4379 | if receiver_type: |
| 4380 | enclosing_class = receiver_type |
| 4381 | |
| 4382 | # Extract annotations/decorators for test detection |
| 4383 | decorators: tuple[str, ...] = () |
| 4384 | deco_list: list[str] = [] |
| 4385 | for sub in child.children: |
| 4386 | # Java/Kotlin/C#: annotations inside a modifiers child |
| 4387 | if sub.type == "modifiers": |
| 4388 | for mod in sub.children: |
| 4389 | if mod.type in ("annotation", "marker_annotation"): |
| 4390 | text = mod.text.decode("utf-8", errors="replace") |
| 4391 | deco_list.append(text.lstrip("@").strip()) |
| 4392 | # Python: check parent decorated_definition for decorator siblings |
| 4393 | if child.parent and child.parent.type == "decorated_definition": |
| 4394 | for sib in child.parent.children: |
| 4395 | if sib.type == "decorator": |
| 4396 | text = sib.text.decode("utf-8", errors="replace") |
| 4397 | deco_list.append(text.lstrip("@").strip()) |
| 4398 | # Rust: attributes are preceding siblings of function_item, not |
| 4399 | # children. Walk back through `attribute_item` nodes and strip the |
| 4400 | # `#[ ]` (or `#![ ]`) wrapper. |
| 4401 | if language == "rust": |
| 4402 | sib = child.prev_sibling |
| 4403 | while sib is not None and sib.type == "attribute_item": |
| 4404 | text = sib.text.decode("utf-8", errors="replace").strip() |
| 4405 | if text.startswith("#!["): |
| 4406 | inner = text[3:].rstrip() |
| 4407 | elif text.startswith("#["): |
| 4408 | inner = text[2:].rstrip() |
| 4409 | else: |
no test coverage detected