feat: Improve C/C++ name extraction and skip forward declarations in struct/enum processing

Addresses C/C++ pointer declarator unwrapping where pointer_declarator nodes need to be resolved to find the actual function/variable name. Adds forward declaration filtering by checking for body field presence before processing struct and enum definitions, preventing extraction of incomplete type declarations.
This commit is contained in:
Colby McHenry
2026-04-06 22:49:09 -05:00
parent e848e6f22f
commit da248f9a8e
+21 -9
View File
@@ -33,12 +33,19 @@ function extractName(node: SyntaxNode, source: string, extractor: LanguageExtrac
// Try field name first
const nameNode = getChildByField(node, extractor.nameField);
if (nameNode) {
// Handle complex declarators (C/C++)
if (nameNode.type === 'function_declarator' || nameNode.type === 'declarator') {
const innerName = getChildByField(nameNode, 'declarator') || nameNode.namedChild(0);
return innerName ? getNodeText(innerName, source) : getNodeText(nameNode, source);
// Unwrap pointer_declarator(s) for C/C++ pointer return types
let resolved = nameNode;
while (resolved.type === 'pointer_declarator') {
const inner = getChildByField(resolved, 'declarator') || resolved.namedChild(0);
if (!inner) break;
resolved = inner;
}
return getNodeText(nameNode, source);
// Handle complex declarators (C/C++)
if (resolved.type === 'function_declarator' || resolved.type === 'declarator') {
const innerName = getChildByField(resolved, 'declarator') || resolved.namedChild(0);
return innerName ? getNodeText(innerName, source) : getNodeText(resolved, source);
}
return getNodeText(resolved, source);
}
// For Dart method_signature, look inside inner signature types
@@ -601,6 +608,10 @@ export class TreeSitterExtractor {
private extractStruct(node: SyntaxNode): void {
if (!this.extractor) return;
// Skip forward declarations and type references (no body = not a definition)
const body = getChildByField(node, this.extractor.bodyField);
if (!body) return;
const name = extractName(node, this.source, this.extractor);
const docstring = getPrecedingDocstring(node, this.source);
const visibility = this.extractor.getVisibility?.(node);
@@ -618,7 +629,6 @@ export class TreeSitterExtractor {
// Push to stack for field extraction
this.nodeStack.push(structNode.id);
const body = getChildByField(node, this.extractor.bodyField) || node;
for (let i = 0; i < body.namedChildCount; i++) {
const child = body.namedChild(i);
if (child) {
@@ -634,6 +644,11 @@ export class TreeSitterExtractor {
private extractEnum(node: SyntaxNode): void {
if (!this.extractor) return;
// Skip forward declarations and type references (no body = not a definition)
const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
?? getChildByField(node, this.extractor.bodyField);
if (!body) return;
const name = extractName(node, this.source, this.extractor);
const docstring = getPrecedingDocstring(node, this.source);
const visibility = this.extractor.getVisibility?.(node);
@@ -651,9 +666,6 @@ export class TreeSitterExtractor {
// Push to stack and visit body children (enum members, nested types, methods)
this.nodeStack.push(enumNode.id);
const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
?? getChildByField(node, this.extractor.bodyField)
?? node;
const memberTypes = this.extractor.enumMemberTypes;
for (let i = 0; i < body.namedChildCount; i++) {