Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions _xtool/internal/libclang/_wrap/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
11 changes: 11 additions & 0 deletions _xtool/internal/libclang/clang.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
3 changes: 3 additions & 0 deletions _xtool/internal/parser/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
23 changes: 13 additions & 10 deletions _xtool/internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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)

if cursor.IsCursorDefinition() == 0 {
ct.logln("ProcessRecordType: forward declaration, no definition")
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
Expand Down
32 changes: 30 additions & 2 deletions _xtool/internal/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down Expand Up @@ -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 := 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:", cursor.IsCursorDefinition() != 0)
}
return clang.ChildVisit_Recurse
})
}
48 changes: 48 additions & 0 deletions _xtool/internal/parser/testdata/forward_vs_empty/expect.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"_Type": "File",
"decls": [
{
"Doc": null,
"Loc": {
"File": "testdata/forward_vs_empty/temp.h",
"_Type": "Location"
},
"Name": {
"Name": "ForwardOnly",
"_Type": "Ident"
},
"Parent": null,
"Type": {
"Fields": null,
"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
}
2 changes: 2 additions & 0 deletions _xtool/internal/parser/testdata/forward_vs_empty/temp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
struct ForwardOnly;
struct EmptyStruct {};
30 changes: 6 additions & 24 deletions _xtool/internal/parser/testdata/forwarddecl1/expect.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand Down Expand Up @@ -167,10 +164,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand All @@ -189,10 +183,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand Down Expand Up @@ -367,10 +358,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand Down Expand Up @@ -536,10 +524,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand All @@ -558,10 +543,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand Down
10 changes: 2 additions & 8 deletions _xtool/internal/parser/testdata/func/expect.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand All @@ -494,10 +491,7 @@
},
"Parent": null,
"Type": {
"Fields": {
"List": null,
"_Type": "FieldList"
},
"Fields": null,
"Methods": null,
"Tag": 0,
"_Type": "RecordType"
Expand Down
10 changes: 10 additions & 0 deletions cl/internal/convert/_testdata/forwarddecl/gogensig.expect
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions cl/internal/convert/_testdata/forwarddecl/hfile/temp.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,7 @@ struct _xmlParserCtxt;
typedef struct _xmlParserCtxt xmlParserCtxt;

typedef xmlParserCtxt htmlParserCtxt;

// https://github.com/goplus/llcppg/issues/526
struct ForwardOnly;
struct EmptyStruct {};
8 changes: 5 additions & 3 deletions cl/internal/convert/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ func TestStructDecl(t *testing.T) {
},
Type: &ast.RecordType{
Tag: ast.Struct,
Fields: nil,
Fields: &ast.FieldList{},
},
},
expected: `
Expand Down Expand Up @@ -1667,7 +1667,7 @@ func TestForwardDecl(t *testing.T) {
},
Type: &ast.RecordType{
Tag: ast.Struct,
Fields: &ast.FieldList{},
Fields: nil,
},
}
// forward decl
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion cl/internal/convert/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading