* Extract a class
(node: SyntaxNode, kind: NodeKind = 'class')
| 1550 | * Extract a class |
| 1551 | */ |
| 1552 | private extractClass(node: SyntaxNode, kind: NodeKind = 'class'): void { |
| 1553 | if (!this.extractor) return; |
| 1554 | |
| 1555 | // Skip forward declarations / elaborated type references (`class Foo;`) in |
| 1556 | // languages that opt in — bodiless there means "not a definition", so it |
| 1557 | // would otherwise mint a phantom node competing with the real definition |
| 1558 | // (#1093). Languages where a bodiless class is complete (Kotlin, Scala) |
| 1559 | // leave the flag unset. Resolved once here and reused for the body walk. |
| 1560 | const resolvedBody = this.extractor.resolveBody?.(node, this.extractor.bodyField) |
| 1561 | ?? getChildByField(node, this.extractor.bodyField); |
| 1562 | if (this.extractor.skipBodilessClass && !resolvedBody) return; |
| 1563 | |
| 1564 | const name = extractName(node, this.source, this.extractor); |
| 1565 | const docstring = getPrecedingDocstring(node, this.source); |
| 1566 | const visibility = this.extractor.getVisibility?.(node); |
| 1567 | const isExported = this.extractor.isExported?.(node, this.source); |
| 1568 | |
| 1569 | const classNode = this.createNode(kind, name, node, { |
| 1570 | docstring, |
| 1571 | visibility, |
| 1572 | isExported, |
| 1573 | }); |
| 1574 | if (!classNode) return; |
| 1575 | |
| 1576 | // Extract extends/implements |
| 1577 | this.extractInheritance(node, classNode.id); |
| 1578 | |
| 1579 | // C# primary-constructor parameter dependencies (`class Svc(IRepo r, …)`). |
| 1580 | this.extractCsharpPrimaryCtorParamRefs(node, classNode.id); |
| 1581 | |
| 1582 | // Extract decorators applied to the class (`@Foo class X {}`). |
| 1583 | this.extractDecoratorsFor(node, classNode.id); |
| 1584 | |
| 1585 | // Push to stack and visit body |
| 1586 | this.nodeStack.push(classNode.id); |
| 1587 | const body = resolvedBody ?? node; |
| 1588 | |
| 1589 | // Visit all children for methods and properties |
| 1590 | for (let i = 0; i < body.namedChildCount; i++) { |
| 1591 | const child = body.namedChild(i); |
| 1592 | if (child) { |
| 1593 | this.visitNode(child); |
| 1594 | } |
| 1595 | } |
| 1596 | |
| 1597 | // Synthesize compile-time-generated members (Lombok accessors, #912). Runs |
| 1598 | // after the body so the hook can dedup against hand-written members, and |
| 1599 | // while the class is still on the stack so containment/QNs attach. |
| 1600 | if (this.extractor.synthesizeMembers) { |
| 1601 | this.extractor.synthesizeMembers(node, this.makeExtractorContext()); |
| 1602 | } |
| 1603 | |
| 1604 | this.nodeStack.pop(); |
| 1605 | } |
| 1606 | |
| 1607 | /** |
| 1608 | * Extract a method |
no test coverage detected