diff --git a/chore/_xtool/llcppsigfetch/parse/cvt.go b/chore/_xtool/llcppsigfetch/parse/cvt.go index 069e2a71..57dec508 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt.go @@ -27,28 +27,7 @@ type Converter struct { index *clang.Index unit *clang.TranslationUnit - typeDecls map[string]ast.Decl // cursorUsr -> ast.Decl - - // anonyTypeMap stores mappings for unexpected named declarations in typedefs - // that actually represent anonymous types. - // - // Key: The USR (Unified Symbol Resolution) of the declaration cursor. - // Value: The generated name for the anonymous type. - // - // This map is necessary due to a limitation in libclang where anonymous - // structs, unions, or enums within typedefs are incorrectly reported as - // named declarations. We use this map to keep track of these cases and - // generate appropriate names for them. - // - // Additionally, for all nodes referencing these anonymous types, their - // name references are updated to use the corresponding anonyname from - // this map. This ensures consistent naming across the entire AST for - // these anonymous types. - // - // Example: - // typedef struct { int x; } MyStruct; - anonyTypeMap map[string]bool // cursorUsr - indent int // for verbose debug + indent int // for verbose debug } var tagMap = map[string]ast.Tag{ @@ -80,11 +59,9 @@ func NewConverter(config *clangutils.Config) (*Converter, error) { } return &Converter{ - Files: make([]*FileEntry, 0), - index: index, - unit: unit, - anonyTypeMap: make(map[string]bool), - typeDecls: make(map[string]ast.Decl), + Files: make([]*FileEntry, 0), + index: index, + unit: unit, }, nil } @@ -177,28 +154,6 @@ func (ct *Converter) GetCurFile() *ast.File { return newDoc } -func (ct *Converter) SetAnonyType(cursor clang.Cursor) { - usr := toStr(cursor.USR()) - ct.anonyTypeMap[usr] = true -} - -func (ct *Converter) GetAnonyType(cursor clang.Cursor) (bool, bool) { - usr := toStr(cursor.USR()) - isAnony, ok := ct.anonyTypeMap[usr] - return isAnony, ok -} - -func (ct *Converter) SetTypeDecl(cursor clang.Cursor, decl ast.Decl) { - usr := toStr(cursor.USR()) - ct.typeDecls[usr] = decl -} - -func (ct *Converter) GetTypeDecl(cursor clang.Cursor) (ast.Decl, bool) { - usr := toStr(cursor.USR()) - decl, ok := ct.typeDecls[usr] - return decl, ok -} - func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase { base := ast.DeclBase{ Loc: &ct.curLoc, @@ -315,6 +270,9 @@ func (ct *Converter) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResul ct.logln("visitTop: ProcessFuncDecl END", funcDecl.Name.Name, funcDecl.MangledName, "isStatic:", funcDecl.IsStatic, "isInline:", funcDecl.IsInline) case clang.CursorTypedefDecl: typedefDecl := ct.ProcessTypeDefDecl(cursor) + if typedefDecl == nil { + return clang.ChildVisit_Continue + } curFile.Decls = append(curFile.Decls, typedefDecl) ct.logln("visitTop: ProcessTypeDefDecl END", typedefDecl.Name.Name) case clang.CursorNamespace: @@ -444,15 +402,20 @@ func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl { ct.logln("ProcessTypeDefDecl: CursorName:", name, "CursorKind:", kind, "CursorTypeKind:", toStr(cursor.Type().Kind.String())) typ := ct.ProcessUnderlyingType(cursor) + // For cases like: typedef struct { int x; } Name; + // libclang incorrectly reports the anonymous structure as a named structure + // with the same name as the typedef. Since the anonymous structure definition + // has already been collected when processing its declaration cursor, + // we skip this redundant typedef declaration by returning nil. + if typ == nil { + return nil + } decl := &ast.TypedefDecl{ DeclBase: ct.CreateDeclBase(cursor), Name: &ast.Ident{Name: name}, Type: typ, } - - ct.SetTypeDecl(cursor, decl) - return decl } @@ -465,38 +428,9 @@ func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr { } referTypeCursor := underlyingTyp.TypeDeclaration() - - // If the type decl for the reference already exists in anonyTypeMap - // then the refer has been processed in ProcessElaboratedType - if _, ok := ct.GetAnonyType(referTypeCursor); !ok && isCursorChildOf(referTypeCursor, cursor) { - // Handle unexpected named structures generated from anonymous RecordTypes in Typedefs - // In this case, libclang incorrectly reports an anonymous struct as a named struct - sourceCode := ct.GetTokens(referTypeCursor) - if isAnonymousStructure(sourceCode) { - ct.logln("ProcessUnderlyingType: is anonymous structure") - ct.SetAnonyType(referTypeCursor) - typ, isValidType := ct.GetTypeDecl(referTypeCursor) - if isValidType { - // There will be no anonymous classes,here will execute enum,union,struct - // according to a normal anonymous decl - switch declType := typ.(type) { - case *ast.EnumTypeDecl: - ct.logln("ProcessUnderlyingType: is actually anonymous enum,remove name") - declType.Name = nil - case *ast.TypeDecl: - if declType.Type.Tag != ast.Class { - ct.logln("ProcessUnderlyingType: is actually anonymous struct,remove name") - declType.Name = nil - } else { - // Unreachable: There should be no anonymous classes in this context - fmt.Fprintln(os.Stderr, "unexpect typedef anonymous class %s", declType.Name.Name) - } - } - } else { - // Unreachable:When referencing an anonymous node, its collection must have been completed beforehand - fmt.Fprintln(os.Stderr, "anonymous node not collected before reference") - } - } + if toStr(cursor.String()) == toStr(referTypeCursor.String()) && isCursorChildOf(referTypeCursor, cursor) { + ct.logln("ProcessUnderlyingType: is self reference") + return nil } return ct.ProcessElaboratedType(underlyingTyp) @@ -546,7 +480,6 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl { } } - ct.SetTypeDecl(cursor, funcDecl) return funcDecl } @@ -631,7 +564,6 @@ func (ct *Converter) ProcessEnumDecl(cursor clang.Cursor) *ast.EnumTypeDecl { ct.logln("ProcessRecordDecl: is anonymous") } - ct.SetTypeDecl(cursor, decl) return decl } @@ -764,7 +696,6 @@ func (ct *Converter) ProcessRecordDecl(cursor clang.Cursor) *ast.TypeDecl { ct.logln("ProcessRecordDecl: is anonymous") } - ct.SetTypeDecl(cursor, decl) return decl } @@ -790,7 +721,6 @@ func (ct *Converter) ProcessClassDecl(cursor clang.Cursor) *ast.TypeDecl { Type: typ, } - ct.SetTypeDecl(cursor, decl) return decl } @@ -833,9 +763,8 @@ func (ct *Converter) ProcessElaboratedType(t clang.Type) ast.Expr { ct.logln("ProcessElaboratedType: TypeName:", typeName, "TypeKind:", typeKind) decl := t.TypeDeclaration() - isAnony, ok := ct.GetAnonyType(decl) - if decl.IsAnonymous() != 0 || isAnony && ok { + if decl.IsAnonymous() != 0 { // anonymous type refer (except anonymous RecordType&EnumType in TypedefDecl) if decl.Kind == clang.CursorEnumDecl { return ct.ProcessEnumType(decl) @@ -1026,15 +955,6 @@ func getOffset(location clang.SourceLocation) c.Uint { return offset } -// checks if the source code represents an actual anonymous structure -func isAnonymousStructure(sourceCode []*ast.Token) bool { - _, isValidTag := tagMap[sourceCode[0].Lit] - return sourceCode[0].Token == token.KEYWORD && - isValidTag && - sourceCode[1].Token == token.PUNCT && - sourceCode[1].Lit == "{" -} - func toStr(clangStr clang.String) (str string) { defer clangStr.Dispose() if clangStr.CStr() != nil { diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect index 43bb1f8e..76f40a5a 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/decl_test/typedef_test/llgo.expect @@ -484,39 +484,6 @@ TestTypeDefDecl Case 7: }, "Doc": null, "Parent": null, - "Name": null, - "Type": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] - }, - "Methods": [] - } - }, { - "_Type": "TypedefDecl", - "Loc": { - "_Type": "Location", - "File": "temp.h" - }, - "Doc": null, - "Parent": null, "Name": { "_Type": "Ident", "Name": "MyStruct" @@ -563,39 +530,6 @@ TestTypeDefDecl Case 8: }, "Doc": null, "Parent": null, - "Name": null, - "Type": { - "_Type": "RecordType", - "Tag": 1, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] - }, - "Methods": [] - } - }, { - "_Type": "TypedefDecl", - "Loc": { - "_Type": "Location", - "File": "temp.h" - }, - "Doc": null, - "Parent": null, "Name": { "_Type": "Ident", "Name": "MyUnion" @@ -642,52 +576,6 @@ TestTypeDefDecl Case 9: }, "Doc": null, "Parent": null, - "Name": null, - "Type": { - "_Type": "EnumType", - "Items": [{ - "_Type": "EnumItem", - "Name": { - "_Type": "Ident", - "Name": "RED" - }, - "Value": { - "_Type": "BasicLit", - "Kind": 0, - "Value": "0" - } - }, { - "_Type": "EnumItem", - "Name": { - "_Type": "Ident", - "Name": "GREEN" - }, - "Value": { - "_Type": "BasicLit", - "Kind": 0, - "Value": "1" - } - }, { - "_Type": "EnumItem", - "Name": { - "_Type": "Ident", - "Name": "BLUE" - }, - "Value": { - "_Type": "BasicLit", - "Kind": 0, - "Value": "2" - } - }] - } - }, { - "_Type": "TypedefDecl", - "Loc": { - "_Type": "Location", - "File": "temp.h" - }, - "Doc": null, - "Parent": null, "Name": { "_Type": "Ident", "Name": "MyEnum" @@ -747,39 +635,6 @@ TestTypeDefDecl Case 10: }, "Doc": null, "Parent": null, - "Name": null, - "Type": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] - }, - "Methods": [] - } - }, { - "_Type": "TypedefDecl", - "Loc": { - "_Type": "Location", - "File": "temp.h" - }, - "Doc": null, - "Parent": null, "Name": { "_Type": "Ident", "Name": "MyStruct" @@ -821,28 +676,12 @@ TestTypeDefDecl Case 10: "Name": "MyStruct2" }, "Type": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "MyStruct" }, - "Methods": [] + "Tag": 0 } }, { "_Type": "TypedefDecl", @@ -859,28 +698,12 @@ TestTypeDefDecl Case 10: "Type": { "_Type": "PointerType", "X": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "MyStruct" }, - "Methods": [] + "Tag": 0 } } }, { @@ -898,28 +721,12 @@ TestTypeDefDecl Case 10: "Type": { "_Type": "ArrayType", "Elt": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] + "_Type": "TagExpr", + "Name": { + "_Type": "Ident", + "Name": "MyStruct" }, - "Methods": [] + "Tag": 0 }, "Len": null } @@ -951,49 +758,6 @@ TestTypeDefDecl Case 11: "Name": "A" } }, - "Name": null, - "Type": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] - }, - "Methods": [] - } - }, { - "_Type": "TypedefDecl", - "Loc": { - "_Type": "Location", - "File": "temp.h" - }, - "Doc": null, - "Parent": { - "_Type": "ScopingExpr", - "X": { - "_Type": "Ident", - "Name": "B" - }, - "Parent": { - "_Type": "Ident", - "Name": "A" - } - }, "Name": { "_Type": "Ident", "Name": "MyStruct" @@ -1045,28 +809,26 @@ TestTypeDefDecl Case 11: "Name": "MyStruct2" }, "Type": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "MyStruct" + }, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + } }, - "Methods": [] + "Tag": 0 } }, { "_Type": "TypedefDecl", @@ -1093,28 +855,26 @@ TestTypeDefDecl Case 11: "Type": { "_Type": "PointerType", "X": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "MyStruct" + }, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + } }, - "Methods": [] + "Tag": 0 } } }, { @@ -1142,28 +902,26 @@ TestTypeDefDecl Case 11: "Type": { "_Type": "ArrayType", "Elt": { - "_Type": "RecordType", - "Tag": 0, - "Fields": { - "_Type": "FieldList", - "List": [{ - "_Type": "Field", - "Type": { - "_Type": "BuiltinType", - "Kind": 6, - "Flags": 0 - }, - "Doc": null, - "Comment": null, - "IsStatic": false, - "Access": 1, - "Names": [{ - "_Type": "Ident", - "Name": "x" - }] - }] + "_Type": "TagExpr", + "Name": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "MyStruct" + }, + "Parent": { + "_Type": "ScopingExpr", + "X": { + "_Type": "Ident", + "Name": "B" + }, + "Parent": { + "_Type": "Ident", + "Name": "A" + } + } }, - "Methods": [] + "Tag": 0 }, "Len": null } diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect index ac0d4605..bf071926 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/llgo.expect @@ -118,6 +118,113 @@ TestInclude Case 1: } } +TestMacroExpansionOtherFile: +{ + "./testdata/macroexpan/ref.h": { + "_Type": "File", + "decls": [{ + "_Type": "TypeDecl", + "Loc": { + "_Type": "Location", + "File": "./testdata/macroexpan/ref.h" + }, + "Doc": null, + "Parent": null, + "Name": { + "_Type": "Ident", + "Name": "NewType" + }, + "Type": { + "_Type": "RecordType", + "Tag": 0, + "Fields": { + "_Type": "FieldList", + "List": [{ + "_Type": "Field", + "Type": { + "_Type": "ArrayType", + "Elt": { + "_Type": "BuiltinType", + "Kind": 6, + "Flags": 0 + }, + "Len": { + "_Type": "BasicLit", + "Kind": 0, + "Value": "2" + } + }, + "Doc": null, + "Comment": null, + "IsStatic": false, + "Access": 1, + "Names": [{ + "_Type": "Ident", + "Name": "__val" + }] + }] + }, + "Methods": [] + } + }], + "includes": [{ + "_Type": "Include", + "Path": "def.h" + }], + "macros": [] + }, + "./testdata/macroexpan/def.h": { + "_Type": "File", + "decls": [], + "includes": [], + "macros": [{ + "_Type": "Macro", + "Name": "__FSID_T_TYPE", + "Tokens": [{ + "_Type": "Token", + "Token": 3, + "Lit": "__FSID_T_TYPE" + }, { + "_Type": "Token", + "Token": 2, + "Lit": "struct" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "{" + }, { + "_Type": "Token", + "Token": 2, + "Lit": "int" + }, { + "_Type": "Token", + "Token": 3, + "Lit": "__val" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "[" + }, { + "_Type": "Token", + "Token": 4, + "Lit": "2" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "]" + }, { + "_Type": "Token", + "Token": 1, + "Lit": ";" + }, { + "_Type": "Token", + "Token": 1, + "Lit": "}" + }] + }] + } +} + #stderr diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go index df41579b..f702b6a3 100644 --- a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/preprocess.go @@ -1,12 +1,15 @@ package main import ( + "github.com/goplus/llgo/c" test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils" ) func main() { TestDefine() TestInclude() + TestMacroExpansionOtherFile() } func TestDefine() { @@ -25,3 +28,12 @@ func TestInclude() { } test.RunTest("TestInclude", testCases) } + +func TestMacroExpansionOtherFile() { + c.Printf(c.Str("TestMacroExpansionOtherFile:\n")) + test.RunTestWithConfig(&clangutils.Config{ + File: "./testdata/macroexpan/ref.h", + Temp: false, + IsCpp: false, + }) +} diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/testdata/macroexpan/def.h b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/testdata/macroexpan/def.h new file mode 100644 index 00000000..81e2e905 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/testdata/macroexpan/def.h @@ -0,0 +1,4 @@ +#define __FSID_T_TYPE \ + struct { \ + int __val[2]; \ + } \ No newline at end of file diff --git a/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/testdata/macroexpan/ref.h b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/testdata/macroexpan/ref.h new file mode 100644 index 00000000..093d10a0 --- /dev/null +++ b/chore/_xtool/llcppsigfetch/parse/cvt_test/preprocess_test/testdata/macroexpan/ref.h @@ -0,0 +1,2 @@ +#include "def.h" +typedef __FSID_T_TYPE NewType; \ No newline at end of file