diff --git a/chore/_xtool/llcppsigfetch/parse/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt.go index d59485c3..14757cba 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -208,7 +208,9 @@ func visitTop(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.Chil case clang.CursorUnionDecl: unionDecl := ct.ProcessUnionDecl(cursor) curFile.Decls = append(curFile.Decls, unionDecl) - case clang.CursorFunctionDecl: + case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor: + // Handle functions and class methods (including out-of-class method) + // Example: void MyClass::myMethod() { ... } out-of-class method curFile.Decls = append(curFile.Decls, ct.ProcessFuncDecl(cursor)) case clang.CursorTypedefDecl: curFile.Decls = append(curFile.Decls, ct.ProcessTypeDefDecl(cursor)) @@ -276,6 +278,7 @@ func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl { } } +// converts functions, methods, constructors, destructors (including out-of-class decl) to ast.FuncDecl nodes. func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { name := cursor.String() defer name.Dispose() @@ -301,6 +304,11 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { } if isMethod(cursor) { + + if parent := cursor.SemanticParent(); parent.Equal(cursor.LexicalParent()) != 1 { + fn.DeclBase.Parent = qualifiedExpr(buildQualifiedName(cursor)) + } + if cursor.Kind == clang.CursorDestructor { fn.IsDestructor = true } @@ -657,6 +665,22 @@ func isMethod(cursor clang.Cursor) bool { return cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor } +func buildQualifiedName(cursor clang.Cursor) string { + var parts []string + cursor = cursor.SemanticParent() + + // Traverse up the semantic parents + for cursor.IsNull() != 1 && cursor.Kind != clang.CursorTranslationUnit { + name := cursor.String() + qualified := c.GoString(name.CStr()) + parts = append([]string{qualified}, parts...) + cursor = cursor.SemanticParent() + name.Dispose() + } + + return strings.Join(parts, "::") +} + func qualifiedExpr(name string) ast.Expr { parts := strings.Split(name, "::") var expr ast.Expr = &ast.Ident{Name: parts[0]} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go index 65f4ca5f..3997016b 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/class.go @@ -41,6 +41,11 @@ func TestClassDecl() { void foo() override; }; `, + `namespace A{ + class Foo{} + } + void A::Foo::bar(); + `, } test.RunTest("TestClassDecl", testCases) } diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect index f116cbd2..a613664f 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/class_test/llgo.expect @@ -539,6 +539,70 @@ TestClassDecl Case 4: } } +TestClassDecl Case 5: +{ + "temp.h": { + "decls": [{ + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "Name": "A" + }, + "Name": { + "Name": "Foo" + }, + "Type": { + "Tag": 3, + "Fields": { + "List": [] + }, + "Methods": [] + } + }, { + "Loc": { + "File": "temp.h" + }, + "Doc": { + "List": [] + }, + "Parent": { + "X": { + "Name": "Foo" + }, + "Parent": { + "Name": "A" + } + }, + "Name": { + "Name": "bar" + }, + "Type": { + "Params": { + "List": [] + }, + "Ret": { + "Kind": 0, + "Flags": 0 + } + }, + "IsInline": false, + "IsStatic": false, + "IsConst": false, + "IsExplicit": false, + "IsConstructor": false, + "IsDestructor": false, + "IsVirtual": false, + "IsOverride": false + }], + "includes": [], + "macros": [] + } +} + #stderr