diff --git a/cl/class.go b/cl/class.go index 86f8402f..1c9d85f8 100644 --- a/cl/class.go +++ b/cl/class.go @@ -113,15 +113,15 @@ func compileTemplateClass(ctx *pkgCtx, obj *templateObj, parent *scopeCtx) { origName := obj.name cls := obj.decl if debugCompileDecl { - log.Println("template class", origName) + log.Println("template class", origName, "order:", obj.order()) } pkg := ctx.pkg pkgTypes := pkg.Types feats := 0 tparams := newTemplateParams(ctx, pkgTypes, cls, &feats) - if feats&featIgnored != 0 { - log.Println("template class: unsupported template params, skipped -", origName) + if feats&featIgnored != 0 || obj.order() >= 0 { + ctx.logf(cls, "class %s: unsupported template params, skipped", clang.String(cls)) return } @@ -149,10 +149,8 @@ func loadClass(ctx *pkgCtx, cls clang.Cursor, ns string, kind typeTag, parent *s } if cls.NumTemplateArguments() > 0 { - if debugCompileDecl { - log.Println("class", origName, "- with template arguments, skipped") - } - return // temporarily skip class with template arguments, e.g. Foo + loadTemplateClass(ctx, cls, ns, parent) + return } var clsName string @@ -360,7 +358,7 @@ func loadClassMember(ctx *pkgCtx, pkg *types.Package, this *classCtx, clsName st // noop default: - log.Panicln("loadClassMember: unknown kind =", decl.Kind) + ctx.panicf(decl, "loadClassMember: unknown kind = %v", decl.Kind) } } diff --git a/cl/ctx.go b/cl/ctx.go index 49cce108..fc351b7e 100644 --- a/cl/ctx.go +++ b/cl/ctx.go @@ -17,6 +17,7 @@ package cl import ( + "fmt" "go/ast" "go/token" "go/types" @@ -153,6 +154,16 @@ type pkgCtx struct { keepDoc bool } +func (p *pkgCtx) logf(decl clang.Cursor, format string, args ...any) { + pos := p.fset.Position(goNodePos(p, decl)) + log.Printf("%s: %s", pos, fmt.Sprintf(format, args...)) +} + +func (p *pkgCtx) panicf(decl clang.Cursor, format string, args ...any) { + pos := p.fset.Position(goNodePos(p, decl)) + log.Panicf("%s: %s", pos, fmt.Sprintf(format, args...)) +} + const ( anonPrefix = "_llcppg_anon_" ) @@ -530,6 +541,9 @@ func (p *scopeCtx) lookupType(name string) (types.Type, bool) { } func (p *scopeCtx) addTemplate(_ *pkgCtx, name string, decl clang.Cursor, isClass bool) (*templateObj, bool) { + if debugCompileDecl { + log.Println("==> addTemplate", name, "-", clang.DisplayName(decl)) + } // TODO(xsw): check if the class is already added obj := &templateObj{ name: name, @@ -585,23 +599,11 @@ func (p *scopeCtx) reorder() { } func funcUSR(decl clang.Cursor) string { - return clang.GoStringAndDispose(decl.USR()) + return clang.USR(decl) } func funcDisplayName(decl clang.Cursor) string { return clang.DisplayName(decl) } -/* -func substObj(pkg *types.Package, scope *types.Scope, origName string, real types.Object) { - old := scope.Insert(gogen.NewSubst(0, pkg, origName, real)) - if old != nil { - if t, ok := old.Type().(*gogen.TySubst); ok { - t.Real = real - } else { - log.Panicln(origName, "redefined") - } - } -} -*/ // ----------------------------------------------------------------------------- diff --git a/cl/func.go b/cl/func.go index 2bf7f796..a2823fbf 100644 --- a/cl/func.go +++ b/cl/func.go @@ -79,7 +79,7 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *funcObj, this *classCtx) { manglingName := clang.Mangling(fn) if manglingName == "" { - log.Println("func skipped: no mangling name for", origName) + ctx.logf(fn, "func %s: no mangled symbol, skipped", clang.String(fn)) return } @@ -91,24 +91,18 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *funcObj, this *classCtx) { params, variadic := newParams(ctx, pkgTypes, fn, &feats, scope) results := toFuncResults(ctx, pkgTypes, fn.ResultType(), &feats, scope) if feats&featIgnored != 0 { - if debugCompileDecl { - log.Println("func", origName, "- ignored") - } + ctx.logf(fn, "func %s: function with unsupported features, skipped", clang.String(fn)) return } if fn.IsFunctionInlined() != 0 { if ctx.cflags == "" { - if debugCompileDecl { - log.Println("inline func", origName, "- skipped") - } + ctx.logf(fn, "func %s: inline function but no CFlags in config, skipped", clang.String(fn)) return } manglingName = wrapInlineFunc(ctx, manglingName, fn, this) } else if _, ok := ctx.nameLookup(manglingName); !ok { - if debugCompileDecl { - log.Println("func", origName, "- skipped") - } + ctx.logf(fn, "func %s: symbol not found in lib files, skipped", clang.String(fn)) return } diff --git a/cl/var.go b/cl/var.go index 8b4dedd0..7e865633 100644 --- a/cl/var.go +++ b/cl/var.go @@ -54,9 +54,7 @@ func compileVar(ctx *pkgCtx, decl clang.Cursor, ns string) { origName := nameWithNS(clang.String(decl), ns) manglingName := clang.Mangling(decl) if _, ok := ctx.nameLookup(manglingName); !ok { - if debugCompileDecl { - log.Println("var", origName, "- skipped") - } + ctx.logf(decl, "var %s: symbol not found in lib files, skipped", clang.String(decl)) return } diff --git a/clang/clang.go b/clang/clang.go index b739e25f..9d70ffa0 100644 --- a/clang/clang.go +++ b/clang/clang.go @@ -43,53 +43,45 @@ func String[T stringer](v T) string { // ----------------------------------------------------------------------------- -/** - * An "index" that consists of a set of translation units that would - * typically be linked together into an executable or library. - */ +// An "index" that consists of a set of translation units that would +// typically be linked together into an executable or library. type Index struct { clang.Index } -/** - * Provides a shared context for creating translation units. - * - * It provides two options: - * - * - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" - * declarations (when loading any new translation units). A "local" declaration - * is one that belongs in the translation unit itself and not in a precompiled - * header that was used by the translation unit. If zero, all declarations - * will be enumerated. - * - * This process of creating the 'pch', loading it separately, and using it (via - * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks - * (which gives the indexer the same performance benefit as the compiler). - */ +// Provides a shared context for creating translation units. +// +// It provides two options: +// +// - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" +// declarations (when loading any new translation units). A "local" declaration +// is one that belongs in the translation unit itself and not in a precompiled +// header that was used by the translation unit. If zero, all declarations +// will be enumerated. +// +// This process of creating the 'pch', loading it separately, and using it (via +// -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks +// (which gives the indexer the same performance benefit as the compiler). func CreateIndex(excludeDeclarationsFromPCH, displayDiagnostics int) Index { return Index{ Index: clang.CreateIndex(c.Int(excludeDeclarationsFromPCH), c.Int(displayDiagnostics)), } } -/** - * Flags that control the creation of translation units. - * - * The enumerators in this enumeration type are meant to be bitwise - * ORed together to specify which options should be used when - * constructing the translation unit. - */ +// Flags that control the creation of translation units. +// +// The enumerators in this enumeration type are meant to be bitwise +// ORed together to specify which options should be used when +// constructing the translation unit. const ( - /** - * Used to indicate that the parser should construct a "detailed" - * preprocessing record, including all macro definitions and instantiations. - * - * Constructing a detailed preprocessing record requires more memory - * and time to parse, since the information contained in the record - * is usually not retained. However, it can be useful for - * applications that require more detailed information about the - * behavior of the preprocessor. - */ + // Used to indicate that the parser should construct a "detailed" + // preprocessing record, including all macro definitions and instantiations. + // + // Constructing a detailed preprocessing record requires more memory + // and time to parse, since the information contained in the record + // is usually not retained. However, it can be useful for + // applications that require more detailed information about the + // behavior of the preprocessor. DetailedPreprocessingRecord = clang.TranslationUnit_DetailedPreprocessingRecord ) @@ -120,9 +112,7 @@ var errMsgs = [...]string{ // ----------------------------------------------------------------------------- -/** - * A particular source file that is part of a translation unit. - */ +// A particular source file that is part of a translation unit. type File = clang.File const ( @@ -130,9 +120,7 @@ const ( InvalidFile = File(0) ) -/** - * Retrieve the name of a particular source file. - */ +// Retrieve the complete file and path name of the given file. func FileName(f clang.File) string { return GoStringAndDispose(f.Name()) } @@ -144,23 +132,17 @@ type Diagnostic struct { clang.Diagnostic } -/** - * Returns a string that describes the diagnostic. - */ +// Retrieve the text of the given diagnostic. func (e Diagnostic) String() string { return GoStringAndDispose(e.Diagnostic.Spelling()) } -/** - * Returns the category text for the given diagnostic. - */ +// Retrieve the diagnostic category text for a given diagnostic. func (e Diagnostic) CategoryText() string { return GoStringAndDispose(e.Diagnostic.CategoryText()) } -/** - * Format the given diagnostic according to the specified display options. - */ +// Format the given diagnostic in a manner that is suitable for display. func (e Diagnostic) Format(options clang.DiagnosticDisplayOptions) string { return GoStringAndDispose(e.Diagnostic.Format(c.Uint(options))) } @@ -170,9 +152,7 @@ func DefaultDiagnosticDisplayOptions() clang.DiagnosticDisplayOptions // ----------------------------------------------------------------------------- -/** - * A single translation unit, which resides in an index. - */ +// A single translation unit, which resides in an index. type TranslationUnit struct { clang.TranslationUnit } @@ -203,19 +183,15 @@ func (u TranslationUnit) Tokenize(extent clang.SourceRange) (ret []clang.Token, return } -/** - * Determine the spelling of the given token. - * - * The spelling of a token is the textual representation of that token, e.g., - * the text of an identifier or keyword. - */ +// Determine the spelling of the given token. +// +// The spelling of a token is the textual representation of that token, e.g., +// the text of an identifier or keyword. func (u TranslationUnit) TokenSpelling(tok clang.Token) string { return GoStringAndDispose(u.TranslationUnit.TokenSpelling(tok)) } -/** - * Retrieve the diagnostic associated with the given index in the translation unit. - */ +// Retrieve a diagnostic associated with the given translation unit. func (u TranslationUnit) Diagnostic(index c.Uint) (ret Diagnostic) { return Diagnostic{u.TranslationUnit.Diagnostic(index)} } @@ -233,33 +209,29 @@ func (u TranslationUnit) VisitDiagnostics(fn func(diag Diagnostic)) { // ----------------------------------------------------------------------------- -/** - * A cursor representing some element in the abstract syntax tree for - * a translation unit. - * - * The cursor abstraction unifies the different kinds of entities in a - * program--declaration, statements, expressions, references to declarations, - * etc.--under a single "cursor" abstraction with a common set of operations. - * Common operation for a cursor include: getting the physical location in - * a source file where the cursor points, getting the name associated with a - * cursor, and retrieving cursors for any child nodes of a particular cursor. - * - * Cursors can be produced in two specific ways. - * clang_getTranslationUnitCursor() produces a cursor for a translation unit, - * from which one can use clang_visitChildren() to explore the rest of the - * translation unit. clang_getCursor() maps from a physical source location - * to the entity that resides at that location, allowing one to map from the - * source code into the AST. - */ +// A cursor representing some element in the abstract syntax tree for +// a translation unit. +// +// The cursor abstraction unifies the different kinds of entities in a +// program--declaration, statements, expressions, references to declarations, +// etc.--under a single "cursor" abstraction with a common set of operations. +// Common operation for a cursor include: getting the physical location in +// a source file where the cursor points, getting the name associated with a +// cursor, and retrieving cursors for any child nodes of a particular cursor. +// +// Cursors can be produced in two specific ways. +// clang_getTranslationUnitCursor() produces a cursor for a translation unit, +// from which one can use clang_visitChildren() to explore the rest of the +// translation unit. clang_getCursor() maps from a physical source location +// to the entity that resides at that location, allowing one to map from the +// source code into the AST. type Cursor = clang.Cursor -/** - * Identifies a specific source location within a translation - * unit. - * - * Use clang_getExpansionLocation() or clang_getSpellingLocation() - * to map a source location to a particular file, line, and column. - */ +// Identifies a specific source location within a translation +// unit. +// +// Use clang_getExpansionLocation() or clang_getSpellingLocation() +// to map a source location to a particular file, line, and column. type SourceLocation = clang.SourceLocation // PresumedFile returns the presumed file name for the given source location. @@ -269,13 +241,22 @@ func PresumedFile(loc SourceLocation) string { return GoStringAndDispose(filename) } -/** - * Retrieve the display name for the entity referenced by this cursor. - * - * The display name contains extra information that helps identify the cursor, - * such as the parameters of a function or template or the arguments of a - * class template specialization. - */ +// Retrieve a Unified Symbol Resolution (USR) for the entity referenced +// by the given cursor. +// +// A Unified Symbol Resolution (USR) is a string that identifies a particular +// entity (function, class, variable, etc.) within a program. USRs can be +// compared across translation units to determine, e.g., when references in +// one translation refer to an entity defined in another translation unit. +func USR(decl clang.Cursor) string { + return GoStringAndDispose(decl.USR()) +} + +// Retrieve the display name for the entity referenced by this cursor. +// +// The display name contains extra information that helps identify the cursor, +// such as the parameters of a function or template or the arguments of a +// class template specialization. func DisplayName(entity clang.Cursor) string { return GoStringAndDispose(entity.DisplayName()) } @@ -287,35 +268,28 @@ func RawComment(entity clang.Cursor) string { return GoStringAndDispose(entity.RawCommentText()) } -/** - * Retrieve the translation unit that a cursor originated from. - */ +// Returns the translation unit that a cursor originated from. func TU(c Cursor) (ret TranslationUnit) { return TranslationUnit{TranslationUnit: c.TranslationUnit()} } -/** - * Describes how the traversal of the children of a particular - * cursor should proceed after visiting a particular child cursor. - */ +// Describes how the traversal of the children of a particular +// cursor should proceed after visiting a particular child cursor. +// +// A value of this enumeration type should be returned by each +// \c CXCursorVisitor to indicate how clang_visitChildren() proceed. type ChildVisitResult = clang.ChildVisitResult const ( - /** - * Terminates the cursor traversal. - */ + // Terminates the cursor traversal. Break ChildVisitResult = clang.ChildVisit_Break - /** - * Continues the cursor traversal with the next sibling of - * the cursor just visited, without visiting its children. - */ + // Continues the cursor traversal with the next sibling of + // the cursor just visited, without visiting its children. Continue ChildVisitResult = clang.ChildVisit_Continue - /** - * Recursively traverse the children of this cursor, using - * the same visitor and client data. - */ + // Recursively traverse the children of this cursor, using + // the same visitor and client data. Recurse ChildVisitResult = clang.ChildVisit_Recurse ) diff --git a/tool/gen_test.go b/tool/gen_test.go index 21b517b8..88cd0d94 100644 --- a/tool/gen_test.go +++ b/tool/gen_test.go @@ -70,7 +70,7 @@ func testGenGo(t *testing.T, pkg *gogen.Package, dir, fname string, exp any) { func testSingleFile(t *testing.T, idx clang.Index, pkgDir, headerDir, headerFile string, conf *tool.Config) { myPkgName := headerFile[len(headerDir) : len(headerFile)-2] - if myPkgName == "Index" && runtime.GOOS != "darwin" { + if myPkgName == "Index" || myPkgName == "DenseMapInfo" && runtime.GOOS != "darwin" { log.Println("==> only test Index on macOS") return } @@ -284,7 +284,7 @@ func TestLLVM_Compiler(t *testing.T) { testFromDir(t, "Compiler", "./_testcpp", true, "system") } -func _TestLLVM_DenseMapInfo(t *testing.T) { +func TestLLVM_DenseMapInfo(t *testing.T) { testFromDir(t, "DenseMapInfo", "./_testcpp", true, "adt") }