From 8ee625f3ff5c04364965773d934d54cd31969f69 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 5 Aug 2025 10:45:16 +0800 Subject: [PATCH 1/8] parser:verify distinguish forwarddecl & empty decl --- _xtool/internal/parser/_wrap/wrap.cpp | 15 ++++++++++ _xtool/internal/parser/clang.go | 21 ++++++++++++++ _xtool/internal/parser/parser_test.go | 28 +++++++++++++++++++ .../parser/testdata/forward_vs_empty/temp.h | 2 ++ 4 files changed, 66 insertions(+) create mode 100644 _xtool/internal/parser/_wrap/wrap.cpp create mode 100644 _xtool/internal/parser/clang.go create mode 100644 _xtool/internal/parser/testdata/forward_vs_empty/temp.h diff --git a/_xtool/internal/parser/_wrap/wrap.cpp b/_xtool/internal/parser/_wrap/wrap.cpp new file mode 100644 index 00000000..f00678df --- /dev/null +++ b/_xtool/internal/parser/_wrap/wrap.cpp @@ -0,0 +1,15 @@ +#include +#include + +extern "C" { +// void wrap_clang_getCursorReferenced(CXCursor *cur, CXCursor *referenced) { +// *referenced = clang_getCursorReferenced(*cur); +// } + +// void wrap_clang_getCursorDefinition(CXCursor *C, CXCursor *def) { *def = clang_getCursorDefinition(*C); } + +// unsigned is_definition = clang_isCursorDefinition(cursor); +int wrap_clang_isCursorDefinition(CXCursor *cursor) { return clang_isCursorDefinition(*cursor); } + +// int wrap_clang_Cursor_isNull(CXCursor *cursor) { return clang_Cursor_isNull(*cursor); } +} \ No newline at end of file diff --git a/_xtool/internal/parser/clang.go b/_xtool/internal/parser/clang.go new file mode 100644 index 00000000..43022910 --- /dev/null +++ b/_xtool/internal/parser/clang.go @@ -0,0 +1,21 @@ +// NOTE(zzy):temp define in current directory, need to be removed when support libclang at llpkg +package parser + +import ( + _ "unsafe" + + "github.com/goplus/lib/c" + "github.com/goplus/lib/c/clang" +) + +const ( + LLGoFiles = "$(llvm-config --cflags): _wrap/wrap.cpp" + LLGoPackage = "link: -L$(llvm-config --libdir) -lclang; -lclang" +) + +//go:linkname wrapIsCursorDefinition C.wrap_clang_isCursorDefinition +func wrapIsCursorDefinition(c *clang.Cursor) c.Int + +func IsCursorDefinition(c clang.Cursor) c.Int { + return wrapIsCursorDefinition(&c) +} diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index 37eb7c8a..d834ed6b 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -666,3 +666,31 @@ func TestPostOrderVisitChildren(t *testing.T) { fmt.Println("Unexpected child order:", childStr) } } + +func TestEmptyDeclVsForwardDecl(t *testing.T) { + config := &clangutils.Config{ + File: "./testdata/forward_vs_empty/temp.h", + Temp: false, + IsCpp: false, + } + + type isDefinition = bool + var decl map[string]isDefinition = map[string]isDefinition{ + "ForwardOnly": false, + "EmptyStruct": true, + } + + visit(config, func(cursor, parent clang.Cursor) clang.ChildVisitResult { + if cursor.Kind == clang.CursorStructDecl { + sdecl := clang.GoString(cursor.String()) + if _, ok := decl[sdecl]; ok { + isDefine := parser.IsCursorDefinition(cursor) != 0 + if isDefine != decl[sdecl] { + t.Fatalf("StructDecl %s isDefinition expect %v, got %v", sdecl, decl[sdecl], isDefine) + } + } + fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", parser.IsCursorDefinition(cursor)) + } + return clang.ChildVisit_Recurse + }) +} diff --git a/_xtool/internal/parser/testdata/forward_vs_empty/temp.h b/_xtool/internal/parser/testdata/forward_vs_empty/temp.h new file mode 100644 index 00000000..ffd75842 --- /dev/null +++ b/_xtool/internal/parser/testdata/forward_vs_empty/temp.h @@ -0,0 +1,2 @@ +struct ForwardOnly; +struct EmptyStruct {}; From fd86fbf897793eea77f5c950eed6965012ae2c04 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 5 Aug 2025 11:02:50 +0800 Subject: [PATCH 2/8] parser use fn -> clang use fn --- _xtool/internal/clang/_wrap/wrap.cpp | 7 +++++++ .../{parser/clang.go => clang/libclang.go} | 2 +- _xtool/internal/parser/_wrap/wrap.cpp | 15 --------------- _xtool/internal/parser/parser_test.go | 4 ++-- 4 files changed, 10 insertions(+), 18 deletions(-) create mode 100644 _xtool/internal/clang/_wrap/wrap.cpp rename _xtool/internal/{parser/clang.go => clang/libclang.go} (97%) delete mode 100644 _xtool/internal/parser/_wrap/wrap.cpp diff --git a/_xtool/internal/clang/_wrap/wrap.cpp b/_xtool/internal/clang/_wrap/wrap.cpp new file mode 100644 index 00000000..10fb7f55 --- /dev/null +++ b/_xtool/internal/clang/_wrap/wrap.cpp @@ -0,0 +1,7 @@ +// NOTE(zzy):temp define in current directory, need to be removed when support libclang at llpkg +#include +#include + +extern "C" { +int wrap_clang_isCursorDefinition(CXCursor *cursor) { return clang_isCursorDefinition(*cursor); } +} diff --git a/_xtool/internal/parser/clang.go b/_xtool/internal/clang/libclang.go similarity index 97% rename from _xtool/internal/parser/clang.go rename to _xtool/internal/clang/libclang.go index 43022910..0e3f85d9 100644 --- a/_xtool/internal/parser/clang.go +++ b/_xtool/internal/clang/libclang.go @@ -1,5 +1,5 @@ // NOTE(zzy):temp define in current directory, need to be removed when support libclang at llpkg -package parser +package clang import ( _ "unsafe" diff --git a/_xtool/internal/parser/_wrap/wrap.cpp b/_xtool/internal/parser/_wrap/wrap.cpp deleted file mode 100644 index f00678df..00000000 --- a/_xtool/internal/parser/_wrap/wrap.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -extern "C" { -// void wrap_clang_getCursorReferenced(CXCursor *cur, CXCursor *referenced) { -// *referenced = clang_getCursorReferenced(*cur); -// } - -// void wrap_clang_getCursorDefinition(CXCursor *C, CXCursor *def) { *def = clang_getCursorDefinition(*C); } - -// unsigned is_definition = clang_isCursorDefinition(cursor); -int wrap_clang_isCursorDefinition(CXCursor *cursor) { return clang_isCursorDefinition(*cursor); } - -// int wrap_clang_Cursor_isNull(CXCursor *cursor) { return clang_Cursor_isNull(*cursor); } -} \ No newline at end of file diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index d834ed6b..d0f5d171 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -684,12 +684,12 @@ func TestEmptyDeclVsForwardDecl(t *testing.T) { if cursor.Kind == clang.CursorStructDecl { sdecl := clang.GoString(cursor.String()) if _, ok := decl[sdecl]; ok { - isDefine := parser.IsCursorDefinition(cursor) != 0 + isDefine := clangutils.IsCursorDefinition(cursor) != 0 if isDefine != decl[sdecl] { t.Fatalf("StructDecl %s isDefinition expect %v, got %v", sdecl, decl[sdecl], isDefine) } } - fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", parser.IsCursorDefinition(cursor)) + fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", clangutils.IsCursorDefinition(cursor)) } return clang.ChildVisit_Recurse }) From c1c90d33ddc59cc3f92dce410fe4cedc9c98d362 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 5 Aug 2025 11:31:20 +0800 Subject: [PATCH 3/8] clang use fn -> parser use fn --- _xtool/internal/{clang => parser}/_wrap/wrap.cpp | 0 _xtool/internal/{clang => parser}/libclang.go | 2 +- _xtool/internal/parser/parser_test.go | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename _xtool/internal/{clang => parser}/_wrap/wrap.cpp (100%) rename _xtool/internal/{clang => parser}/libclang.go (97%) diff --git a/_xtool/internal/clang/_wrap/wrap.cpp b/_xtool/internal/parser/_wrap/wrap.cpp similarity index 100% rename from _xtool/internal/clang/_wrap/wrap.cpp rename to _xtool/internal/parser/_wrap/wrap.cpp diff --git a/_xtool/internal/clang/libclang.go b/_xtool/internal/parser/libclang.go similarity index 97% rename from _xtool/internal/clang/libclang.go rename to _xtool/internal/parser/libclang.go index 0e3f85d9..43022910 100644 --- a/_xtool/internal/clang/libclang.go +++ b/_xtool/internal/parser/libclang.go @@ -1,5 +1,5 @@ // NOTE(zzy):temp define in current directory, need to be removed when support libclang at llpkg -package clang +package parser import ( _ "unsafe" diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index d0f5d171..d834ed6b 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -684,12 +684,12 @@ func TestEmptyDeclVsForwardDecl(t *testing.T) { if cursor.Kind == clang.CursorStructDecl { sdecl := clang.GoString(cursor.String()) if _, ok := decl[sdecl]; ok { - isDefine := clangutils.IsCursorDefinition(cursor) != 0 + isDefine := parser.IsCursorDefinition(cursor) != 0 if isDefine != decl[sdecl] { t.Fatalf("StructDecl %s isDefinition expect %v, got %v", sdecl, decl[sdecl], isDefine) } } - fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", clangutils.IsCursorDefinition(cursor)) + fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", parser.IsCursorDefinition(cursor)) } return clang.ChildVisit_Recurse }) From a190dec8889e8a100dede98cbddb71791eecaf98 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 5 Aug 2025 18:56:41 +0800 Subject: [PATCH 4/8] with libclang package to patch function map --- _xtool/internal/libclang/_wrap/cursor.cpp | 2 ++ _xtool/internal/libclang/clang.go | 11 +++++++++++ _xtool/internal/parser/_wrap/wrap.cpp | 7 ------- _xtool/internal/parser/libclang.go | 21 --------------------- _xtool/internal/parser/parser_test.go | 4 ++-- 5 files changed, 15 insertions(+), 30 deletions(-) delete mode 100644 _xtool/internal/parser/_wrap/wrap.cpp delete mode 100644 _xtool/internal/parser/libclang.go diff --git a/_xtool/internal/libclang/_wrap/cursor.cpp b/_xtool/internal/libclang/_wrap/cursor.cpp index 190fb874..5761db9a 100644 --- a/_xtool/internal/libclang/_wrap/cursor.cpp +++ b/_xtool/internal/libclang/_wrap/cursor.cpp @@ -37,6 +37,8 @@ void wrap_clang_getCursorSemanticParent(CXCursor *C, CXCursor *parent) { *parent void wrap_clang_getCursorDefinition(CXCursor *C, CXCursor *def) { *def = clang_getCursorDefinition(*C); } +int wrap_clang_isCursorDefinition(CXCursor *cursor) { return clang_isCursorDefinition(*cursor); } + void wrap_clang_getCursorLexicalParent(CXCursor *C, CXCursor *parent) { *parent = clang_getCursorLexicalParent(*C); } void wrap_clang_getOverriddenCursors(CXCursor *cursor, CXCursor **overridden, unsigned *num_overridden) { diff --git a/_xtool/internal/libclang/clang.go b/_xtool/internal/libclang/clang.go index d52abaa7..86d15ba3 100644 --- a/_xtool/internal/libclang/clang.go +++ b/_xtool/internal/libclang/clang.go @@ -1643,6 +1643,17 @@ func (c Cursor) Definition() (def Cursor) { return } +/** + * Determine whether the declaration pointed to by this cursor + * is also a definition of that entity. + */ +// llgo:link (*Cursor).wrapIsCursorDefinition C.wrap_clang_isCursorDefinition +func (c *Cursor) wrapIsCursorDefinition() c.Int { return 0 } + +func (c Cursor) IsCursorDefinition() c.Int { + return c.wrapIsCursorDefinition() +} + /** * Determine the lexical parent of the given cursor. * diff --git a/_xtool/internal/parser/_wrap/wrap.cpp b/_xtool/internal/parser/_wrap/wrap.cpp deleted file mode 100644 index 10fb7f55..00000000 --- a/_xtool/internal/parser/_wrap/wrap.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// NOTE(zzy):temp define in current directory, need to be removed when support libclang at llpkg -#include -#include - -extern "C" { -int wrap_clang_isCursorDefinition(CXCursor *cursor) { return clang_isCursorDefinition(*cursor); } -} diff --git a/_xtool/internal/parser/libclang.go b/_xtool/internal/parser/libclang.go deleted file mode 100644 index 43022910..00000000 --- a/_xtool/internal/parser/libclang.go +++ /dev/null @@ -1,21 +0,0 @@ -// NOTE(zzy):temp define in current directory, need to be removed when support libclang at llpkg -package parser - -import ( - _ "unsafe" - - "github.com/goplus/lib/c" - "github.com/goplus/lib/c/clang" -) - -const ( - LLGoFiles = "$(llvm-config --cflags): _wrap/wrap.cpp" - LLGoPackage = "link: -L$(llvm-config --libdir) -lclang; -lclang" -) - -//go:linkname wrapIsCursorDefinition C.wrap_clang_isCursorDefinition -func wrapIsCursorDefinition(c *clang.Cursor) c.Int - -func IsCursorDefinition(c clang.Cursor) c.Int { - return wrapIsCursorDefinition(&c) -} diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index d834ed6b..68ae06ae 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -684,12 +684,12 @@ func TestEmptyDeclVsForwardDecl(t *testing.T) { if cursor.Kind == clang.CursorStructDecl { sdecl := clang.GoString(cursor.String()) if _, ok := decl[sdecl]; ok { - isDefine := parser.IsCursorDefinition(cursor) != 0 + isDefine := cursor.IsCursorDefinition() != 0 if isDefine != decl[sdecl] { t.Fatalf("StructDecl %s isDefinition expect %v, got %v", sdecl, decl[sdecl], isDefine) } } - fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", parser.IsCursorDefinition(cursor)) + fmt.Println("StructDecl Name:", clang.GoString(cursor.String()), "isDefinition:", cursor.IsCursorDefinition() != 0) } return clang.ChildVisit_Recurse }) From eeb1484a163f3c3e7e52bebd3097690d6d1ffb35 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Tue, 5 Aug 2025 21:39:10 +0800 Subject: [PATCH 5/8] test:with before case --- _xtool/internal/parser/parser.go | 21 ++++---- _xtool/internal/parser/parser_test.go | 2 +- .../testdata/forward_vs_empty/expect.json | 51 +++++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) create mode 100755 _xtool/internal/parser/testdata/forward_vs_empty/expect.json diff --git a/_xtool/internal/parser/parser.go b/_xtool/internal/parser/parser.go index e01f974f..a72f49ab 100644 --- a/_xtool/internal/parser/parser.go +++ b/_xtool/internal/parser/parser.go @@ -826,23 +826,26 @@ func (ct *Converter) ProcessRecordType(cursor clang.Cursor) *ast.RecordType { ct.incIndent() defer ct.decIndent() + typ := &ast.RecordType{} + cursorName, cursorKind := getCursorDesc(cursor) ct.logln("ProcessRecordType: CursorName:", cursorName, "CursorKind:", cursorKind) - tag := toTag(cursor.Kind) - ct.logln("ProcessRecordType: toTag", tag) + typ.Tag = toTag(cursor.Kind) + ct.logln("ProcessRecordType: toTag", typ.Tag) + + // will cause exit -1 + // if cursor.IsCursorDefinition() == 0 { + // return typ + // } ct.logln("ProcessRecordType: ProcessFieldList") - fields := ct.ProcessFieldList(cursor) + typ.Fields = ct.ProcessFieldList(cursor) ct.logln("ProcessRecordType: ProcessMethods") - methods := ct.ProcessMethods(cursor) + typ.Methods = ct.ProcessMethods(cursor) - return &ast.RecordType{ - Tag: tag, - Fields: fields, - Methods: methods, - } + return typ } // process ElaboratedType Reference diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index 68ae06ae..759ca36b 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -31,7 +31,7 @@ func TestParserCppMode(t *testing.T) { } func TestParserCMode(t *testing.T) { - cases := []string{"enum", "struct", "union", "macro", "include", "typeof", "named_nested_struct"} + cases := []string{"enum", "struct", "union", "macro", "include", "typeof", "named_nested_struct", "forward_vs_empty"} for _, folder := range cases { t.Run(folder, func(t *testing.T) { testFrom(t, filepath.Join("testdata", folder), "temp.h", false, false) diff --git a/_xtool/internal/parser/testdata/forward_vs_empty/expect.json b/_xtool/internal/parser/testdata/forward_vs_empty/expect.json new file mode 100755 index 00000000..60ccaf0b --- /dev/null +++ b/_xtool/internal/parser/testdata/forward_vs_empty/expect.json @@ -0,0 +1,51 @@ +{ + "_Type": "File", + "decls": [ + { + "Doc": null, + "Loc": { + "File": "testdata/forward_vs_empty/temp.h", + "_Type": "Location" + }, + "Name": { + "Name": "ForwardOnly", + "_Type": "Ident" + }, + "Parent": null, + "Type": { + "Fields": { + "List": null, + "_Type": "FieldList" + }, + "Methods": null, + "Tag": 0, + "_Type": "RecordType" + }, + "_Type": "TypeDecl" + }, + { + "Doc": null, + "Loc": { + "File": "testdata/forward_vs_empty/temp.h", + "_Type": "Location" + }, + "Name": { + "Name": "EmptyStruct", + "_Type": "Ident" + }, + "Parent": null, + "Type": { + "Fields": { + "List": null, + "_Type": "FieldList" + }, + "Methods": null, + "Tag": 0, + "_Type": "RecordType" + }, + "_Type": "TypeDecl" + } + ], + "includes": null, + "macros": null +} \ No newline at end of file From 1c6348fae63dbe035cbc1def5cacc505af4b3c5e Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Wed, 6 Aug 2025 16:00:38 +0800 Subject: [PATCH 6/8] parser:forward decl return nil --- _xtool/internal/parser/marshal.go | 3 ++ _xtool/internal/parser/parser.go | 10 +++---- _xtool/internal/parser/parser_test.go | 2 +- .../testdata/forward_vs_empty/expect.json | 5 +--- .../parser/testdata/forwarddecl1/expect.json | 30 ++++--------------- .../internal/parser/testdata/func/expect.json | 10 ++----- 6 files changed, 18 insertions(+), 42 deletions(-) diff --git a/_xtool/internal/parser/marshal.go b/_xtool/internal/parser/marshal.go index 86a19a88..5c773e3d 100644 --- a/_xtool/internal/parser/marshal.go +++ b/_xtool/internal/parser/marshal.go @@ -176,6 +176,9 @@ func XMarshalASTExpr(t ast.Expr) map[string]any { root["Ret"] = XMarshalASTExpr(d.Ret) case *ast.FieldList: root["_Type"] = "FieldList" + if d == nil { + return nil + } root["List"] = XMarshalFieldList(d.List) case *ast.Field: root["_Type"] = "Field" diff --git a/_xtool/internal/parser/parser.go b/_xtool/internal/parser/parser.go index a72f49ab..0e533ad4 100644 --- a/_xtool/internal/parser/parser.go +++ b/_xtool/internal/parser/parser.go @@ -768,7 +768,7 @@ func (ct *Converter) ProcessRecordDecl(cursor clang.Cursor) []ast.Decl { typ := ct.ProcessRecordType(child) // note(zzy):use len(typ.Fields.List) to ensure it has fields not a forward declaration // but maybe make the forward decl in to AST is also good. - if child.IsAnonymous() == 0 && len(typ.Fields.List) > 0 { + if child.IsAnonymous() == 0 && typ.Fields != nil { childName := clang.GoString(child.String()) ct.logln("ProcessRecordDecl: Found named nested struct:", childName) decls = append(decls, &ast.TypeDecl{ @@ -834,10 +834,10 @@ func (ct *Converter) ProcessRecordType(cursor clang.Cursor) *ast.RecordType { typ.Tag = toTag(cursor.Kind) ct.logln("ProcessRecordType: toTag", typ.Tag) - // will cause exit -1 - // if cursor.IsCursorDefinition() == 0 { - // return typ - // } + if cursor.IsCursorDefinition() == 0 { + ct.logln("ProcessRecordType: forward declaration, no definition") + return typ + } ct.logln("ProcessRecordType: ProcessFieldList") typ.Fields = ct.ProcessFieldList(cursor) diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index 759ca36b..2837baea 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -20,7 +20,7 @@ import ( ) func TestParserCppMode(t *testing.T) { - cases := []string{"class", "comment", "enum", "func", "scope", "struct", "typedef", "union", "macro", "forwarddecl1", "forwarddecl2", "include", "typeof"} + cases := []string{"class", "comment", "enum", "func", "scope", "struct", "typedef", "union", "macro", "forwarddecl1", "forwarddecl2", "include", "typeof", "forward_vs_empty"} // https://github.com/goplus/llgo/issues/1114 // todo(zzy):use os.ReadDir for _, folder := range cases { diff --git a/_xtool/internal/parser/testdata/forward_vs_empty/expect.json b/_xtool/internal/parser/testdata/forward_vs_empty/expect.json index 60ccaf0b..3196f715 100755 --- a/_xtool/internal/parser/testdata/forward_vs_empty/expect.json +++ b/_xtool/internal/parser/testdata/forward_vs_empty/expect.json @@ -13,10 +13,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" diff --git a/_xtool/internal/parser/testdata/forwarddecl1/expect.json b/_xtool/internal/parser/testdata/forwarddecl1/expect.json index 25fff7bc..ed56af94 100755 --- a/_xtool/internal/parser/testdata/forwarddecl1/expect.json +++ b/_xtool/internal/parser/testdata/forwarddecl1/expect.json @@ -101,10 +101,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" @@ -167,10 +164,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" @@ -189,10 +183,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" @@ -367,10 +358,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" @@ -536,10 +524,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" @@ -558,10 +543,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" diff --git a/_xtool/internal/parser/testdata/func/expect.json b/_xtool/internal/parser/testdata/func/expect.json index b849eeb4..4523c263 100755 --- a/_xtool/internal/parser/testdata/func/expect.json +++ b/_xtool/internal/parser/testdata/func/expect.json @@ -472,10 +472,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" @@ -494,10 +491,7 @@ }, "Parent": null, "Type": { - "Fields": { - "List": null, - "_Type": "FieldList" - }, + "Fields": null, "Methods": null, "Tag": 0, "_Type": "RecordType" From 1f3d3a508aa25c05c7229a0b25527928cece3cc7 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Wed, 6 Aug 2025 16:11:38 +0800 Subject: [PATCH 7/8] cl:use field == nil to determine forward decl --- cl/internal/convert/package_test.go | 8 +++++--- cl/internal/convert/type.go | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cl/internal/convert/package_test.go b/cl/internal/convert/package_test.go index 8a996da2..a2890552 100644 --- a/cl/internal/convert/package_test.go +++ b/cl/internal/convert/package_test.go @@ -719,7 +719,7 @@ func TestStructDecl(t *testing.T) { }, Type: &ast.RecordType{ Tag: ast.Struct, - Fields: nil, + Fields: &ast.FieldList{}, }, }, expected: ` @@ -1667,7 +1667,7 @@ func TestForwardDecl(t *testing.T) { }, Type: &ast.RecordType{ Tag: ast.Struct, - Fields: &ast.FieldList{}, + Fields: nil, }, } // forward decl @@ -1871,7 +1871,9 @@ func TestTypeClean(t *testing.T) { Object: ast.Object{ Name: &ast.Ident{Name: "Foo1"}, }, - Type: &ast.RecordType{Tag: ast.Struct}, + Type: &ast.RecordType{ + Tag: ast.Struct, + Fields: &ast.FieldList{}}, }, nc) }, headerFile: "/path/to/file1.h", diff --git a/cl/internal/convert/type.go b/cl/internal/convert/type.go index 7bd86c11..b1530ff2 100644 --- a/cl/internal/convert/type.go +++ b/cl/internal/convert/type.go @@ -334,7 +334,7 @@ func (p *TypeConv) ToDefaultEnumType() types.Type { // by only checking if Fields.List is empty // Should use recordType == nil to identify forward declarations, which requires llcppsigfetch support func (p *TypeConv) inComplete(recordType *ast.RecordType) bool { - return recordType.Fields != nil && len(recordType.Fields.List) == 0 + return recordType.Fields == nil } // The field name should be public if it's a record field From 863f3dee2684d1931d59572c8b942f038e839be2 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Wed, 6 Aug 2025 16:35:00 +0800 Subject: [PATCH 8/8] cl:patch test --- .../convert/_testdata/forwarddecl/gogensig.expect | 10 ++++++++++ cl/internal/convert/_testdata/forwarddecl/hfile/temp.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/cl/internal/convert/_testdata/forwarddecl/gogensig.expect b/cl/internal/convert/_testdata/forwarddecl/gogensig.expect index ab6678ba..cc79f975 100644 --- a/cl/internal/convert/_testdata/forwarddecl/gogensig.expect +++ b/cl/internal/convert/_testdata/forwarddecl/gogensig.expect @@ -129,7 +129,17 @@ type X_xmlParserCtxt struct { type XmlParserCtxt X_xmlParserCtxt type HtmlParserCtxt XmlParserCtxt +// https://github.com/goplus/llcppg/issues/526 +type ForwardOnly struct { + Unused [8]uint8 +} + +type EmptyStruct struct { +} + ===== llcppg.pub ===== +EmptyStruct +ForwardOnly Fts5Context Fts5ExtensionApi Fts5PhraseIter diff --git a/cl/internal/convert/_testdata/forwarddecl/hfile/temp.h b/cl/internal/convert/_testdata/forwarddecl/hfile/temp.h index 9e4709f9..c52f48ff 100644 --- a/cl/internal/convert/_testdata/forwarddecl/hfile/temp.h +++ b/cl/internal/convert/_testdata/forwarddecl/hfile/temp.h @@ -94,3 +94,7 @@ struct _xmlParserCtxt; typedef struct _xmlParserCtxt xmlParserCtxt; typedef xmlParserCtxt htmlParserCtxt; + +// https://github.com/goplus/llcppg/issues/526 +struct ForwardOnly; +struct EmptyStruct {}; \ No newline at end of file