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
31 changes: 23 additions & 8 deletions cl/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func newTypeParams(ctx *pkgCtx, pkg *types.Package, cls clang.Cursor) (ret []*ty
clang.VisitChildren(cls, func(decl, parent clang.Cursor) clang.ChildVisitResult {
switch decl.Kind {
case lc.Cursor_TemplateTypeParameter:
if isParameterPack(decl) {
quietIgnore = true
return clang.Break
}
idx++
name := clang.String(decl)
if name == "" {
Expand All @@ -105,6 +109,19 @@ func newTypeParams(ctx *pkgCtx, pkg *types.Package, cls clang.Cursor) (ret []*ty
return
}

func isParameterPack(decl clang.Cursor) bool { // <class... T>
tu := clang.TranslationUnit{TranslationUnit: decl.TranslationUnit()}
extent := decl.Extent()
tokens, dispose := tu.Tokenize(extent)
defer dispose()
for _, token := range tokens {
if token.Kind() == lc.Token_Punctuation && tu.TokenSpelling(token) == "..." {
return true
}
}
return false
}

func loadTemplateClass(ctx *pkgCtx, cls clang.Cursor, parent *scopeCtx) {
if obj, ok := ctx.addTemplateClass(ctx, cls); ok {
ctx.addCompileUnit(func(ctx *pkgCtx) {
Expand All @@ -125,9 +142,8 @@ func compileTemplateClass(ctx *pkgCtx, obj *templateClass, parent *scopeCtx) {
pkgTypes := pkg.Types
tparams, quietIgnore := newTypeParams(ctx, pkgTypes, cls)
if quietIgnore || order >= 0 {
if debugQuietIgnore {
ctx.logf(cls, "class %s: unsupported template params, ignored", cName)
}
ctx.ignoref(featQuietIgnore, cls, "class %s: unsupported template params, ignored", cName)
ctx.ignoreType(cName, featQuietIgnore)
return
}

Expand Down Expand Up @@ -474,13 +490,12 @@ func baseClass(ctx *pkgCtx, decl clang.Cursor, feats *int) *types.TypeName {
t = t.Named()
}
switch t.Kind {
case lc.Type_Record:
case lc.Type_Record, lc.Type_Typedef:
cName := cTypeName(t)
if t, ok := ctx.typeObj(cName); ok {
return t
if o, ok := ctx.getTypeObj(cName, feats); ok {
return o
}
case lc.Type_Unexposed:
ctx.logf(decl, "baseClass %s: with unexposed type, skipped", clang.String(decl))
*feats |= featExplicitIgnore
return nil
}
Expand All @@ -493,7 +508,7 @@ func loadOutsideMethod(ctx *pkgCtx, outsideDecl clang.Cursor) {
if m, ok := ctx.fns[fnUSR]; ok {
m.decl = outsideDecl
} else {
ctx.logf(outsideDecl, "[WARN] method undeclared - %s", cNameOf(outsideDecl))
ctx.ignoref(featExplicitIgnore, outsideDecl, "[WARN] method undeclared - %s", cNameOf(outsideDecl))
}
}

Expand Down
6 changes: 5 additions & 1 deletion cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ type Config struct {
// for all header files.
GoFileOf func(headerFile string) (string, bool)

// FailFast specifies whether to fail fast on errors (optional). If FailFast is non-zero,
// llcppg will stop after printing errors `FailFast` times.
Comment thread
xushiwei marked this conversation as resolved.
FailFast int

// LoadLibcPubFile specifies whether to load the pubFile for libc package (optional).
LoadLibcPubFile bool

Expand Down Expand Up @@ -233,7 +237,7 @@ func NewPackage(pkgPath, pkgName string, files []Source, conf *Config) (ret Pack
typdecls := make(map[string]typDecl)
ctx := &pkgCtx{
overloads: make(map[string]*overloads), pkg: pkg, cb: pkg.CB(),
llgo: llgo, fset: pkg.Fset, lang: conf.Language,
llgo: llgo, fset: pkg.Fset, lang: conf.Language, failFast: conf.FailFast,
keepDoc: !conf.DontKeepDoc, stdRecvName: conf.UseStdRecvName,
cflags: conf.CFlags, wrapFileHeader: conf.WrapFileHeader,
typeAbbr: conf.TypeAbbr, typeAbbrSuffix: conf.TypeAbbrSuffix,
Expand Down
39 changes: 27 additions & 12 deletions cl/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"go/token"
"go/types"
"log"
"os"
"sort"

"github.com/goplus/gogen"
Expand Down Expand Up @@ -153,7 +154,8 @@ type pkgCtx struct {
compiles []compileUnit
pubs []Entry

anonSeq int
failFast int
anonSeq int

stdRecvName bool
keepDoc bool
Expand All @@ -162,6 +164,10 @@ type pkgCtx struct {
func (p *pkgCtx) ignoref(feats int, decl clang.Cursor, format string, args ...any) {
if feats&featQuietIgnore == 0 || debugQuietIgnore {
p.logf(decl, format, args...)
p.failFast--
if p.failFast == 0 {
os.Exit(1)
}
Comment thread
xushiwei marked this conversation as resolved.
}
}

Expand Down Expand Up @@ -253,27 +259,36 @@ func (p *pkgCtx) addType(cName string, decl clang.Cursor, typNamed *types.Named)
}

func (p *pkgCtx) ignoreType(cName string, feats int) {
if _, ok := p.types[cName]; !ok {
p.types[cName] = typeObj{nil, feats}
if o, ok := p.types[cName]; ok {
if o.TypeName != nil && o.Pkg() == p.pkg.Types { // don't ignore external type
o.feats |= feats
p.types[cName] = o
}
return
}
Comment thread
xushiwei marked this conversation as resolved.
p.types[cName] = typeObj{nil, feats}
}

func (p *pkgCtx) isTypeIgnored(cName string) bool {
func (p *pkgCtx) isConfTypeIgnored(cName string) bool {
return contains(cName, p.typeIgnores)
}

func (p *pkgCtx) typeObj(cName string) (*types.TypeName, bool) {
if o, ok := p.types[cName]; ok && o.feats&featQuietIgnore == 0 {
return o.TypeName, true
func (p *pkgCtx) nsFeats(ns string) int {
if ns != "" {
if o, ok := p.types[ns]; ok {
return o.feats
}
}
return nil, false
return 0
}

func (p *pkgCtx) typeOf(cName string) (types.Type, bool) {
if o, ok := p.types[cName]; ok && o.feats&featQuietIgnore == 0 {
return o.Type(), true
func (p *pkgCtx) getTypeObj(cName string, feats *int) (ret *types.TypeName, ok bool) {
o, ok := p.types[cName]
if ok {
ret, ok = o.TypeName, o.feats&featAllIgnore == 0
*feats |= o.feats
}
return nil, false
return
}

func (p *pkgCtx) isMacroIgnored(cName string) bool {
Expand Down
4 changes: 2 additions & 2 deletions cl/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *funcObj, this *classCtx) {

manglingName := clang.Mangling(fn)
if manglingName == "" {
ctx.logf(fn, "func %s: no mangled symbol, skipped", cName)
ctx.ignoref(featExplicitIgnore, fn, "func %s: no mangled symbol, ignored", cName)
return
}

Expand All @@ -100,7 +100,7 @@ func compileFuncOrMethod(ctx *pkgCtx, obj *funcObj, this *classCtx) {
}
manglingName = wrapInlineFunc(ctx, manglingName, fn, this)
} else if _, ok := ctx.nameLookup(manglingName); !ok {
ctx.logf(fn, "func %s: symbol not found in lib files, skipped", cName)
ctx.ignoref(featExplicitIgnore, fn, "func %s: symbol not found in lib files, ignored", cName)
return
}

Expand Down
2 changes: 1 addition & 1 deletion cl/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func cNameOf(decl clang.Cursor) string {
cName := cBaseName(decl)
for {
decl = decl.SemanticParent()
if decl.Kind == lc.Cursor_TranslationUnit {
if decl.IsNull() != 0 || decl.Kind == lc.Cursor_TranslationUnit {
break
}
cName = cBaseName(decl) + "::" + cName
Expand Down
25 changes: 6 additions & 19 deletions cl/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,15 @@ func toTypeEx(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, feats *in
case lc.Type_FunctionProto:
*feats |= featHasCallback
return toFuncType(ctx, pkg, typ, feats)
case lc.Type_Enum:
case lc.Type_Enum, lc.Type_Record, lc.Type_Typedef:
cName := cTypeName(typ)
if t, ok := ctx.typeOf(cName); ok {
return t
}
case lc.Type_Record, lc.Type_Typedef:
cName := cTypeName(typ)
if o, ok := ctx.types[cName]; ok {
if o.feats != 0 {
*feats |= o.feats
if o.feats&featAllIgnore != 0 {
return types.Typ[types.Invalid] // ignored type
}
}
if o, ok := ctx.getTypeObj(cName, feats); ok {
return o.Type()
}
case lc.Type_Elaborated:
cName := cTypeName(typ.Named())
if t, ok := ctx.typeOf(cName); ok {
return t
if o, ok := ctx.getTypeObj(cName, feats); ok {
return o.Type()
}
case lc.Type_IncompleteArray, lc.Type_VariableArray:
// T[] (and VLAs) have no known extent, so they behave like T*. Clear
Expand All @@ -170,7 +159,7 @@ func toTypeEx(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, feats *in
}
return types.NewArray(elem, int64(typ.ArraySize()))
case lc.Type_Unexposed:
name := clang.String(typ)
name := clang.String(typ) // maybe typeParams
if t, ok := scope.lookupType(name); ok {
return t
}
Expand All @@ -179,10 +168,8 @@ func toTypeEx(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, feats *in
case lc.Type_BlockPointer:
*feats |= featQuietIgnore // will always be ignored
return types.Typ[types.Invalid]
default:
ctx.logtf(typ, "toType: unknown kind - %v", typ.Kind)
}
ctx.logtf(typ, "toType: unsupported type - %s", clang.String(typ))
ctx.logtf(typ, "toType: unsupported type - %s (%d: %s)", cTypeName(typ), typ.Kind, clang.String(typ))
*feats |= featExplicitIgnore
return types.Typ[types.Invalid]
}
Expand Down
14 changes: 8 additions & 6 deletions cl/typedef.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,24 @@ func loadTypedef(ctx *pkgCtx, decl clang.Cursor, scope *scopeCtx) {
var cName = cNameOf(decl)
var goName = ctx.typeName(cName, true)
if cNewName, ok := ctx.typeAlias[cName]; ok {
if t, ok := ctx.typeOf(cNewName); ok {
tunder = t
if o, ok := ctx.getTypeObj(cNewName, &feats); ok {
tunder = o.Type()
goto lzFind
}
ctx.logf(decl, "typedef %s: alias to %s but not found, skipped", cName, cNewName)
ctx.ignoref(featExplicitIgnore, decl, "typedef %s: alias to %s but not found, ignored", cName, cNewName)
ctx.ignoreType(cName, featExplicitIgnore)
return
}

if ctx.isTypeIgnored(cName) {
if ctx.isConfTypeIgnored(cName) {
ctx.ignoref(featQuietIgnore, decl, "typedef %s: ignored by config", cName)
ctx.ignoreType(cName, featQuietIgnore)
return
}

if decl.Kind == lc.Cursor_TypeAliasTemplateDecl {
ctx.logf(decl, "typedef %s: template type alias, skipped", cName)
ctx.ignoref(featExplicitIgnore, decl, "typedef %s: template type alias, ignored", cName)
ctx.ignoreType(cName, featExplicitIgnore)
return
}

Expand All @@ -66,7 +68,7 @@ func loadTypedef(ctx *pkgCtx, decl clang.Cursor, scope *scopeCtx) {
return
}
if feats&featExplicitIgnore != 0 {
ctx.logf(decl, "typedef %s: unsupported underlying type, skipped", cName)
ctx.ignoref(featExplicitIgnore, decl, "typedef %s: unsupported underlying type, ignored", cName)
ctx.ignoreType(cName, featExplicitIgnore)
return
}
Expand Down
19 changes: 13 additions & 6 deletions cl/var.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,20 @@ func loadVar(ctx *pkgCtx, decl clang.Cursor) {
}

func compileVar(ctx *pkgCtx, decl clang.Cursor) {
cName := cNameOf(decl)
ns := cNS(decl)
cName := cNameWithNS(clang.String(decl), ns)
if feats := ctx.nsFeats(ns); feats&featAllIgnore != 0 {
ctx.ignoref(feats, decl, "var %s: parent is ignored", cName)
return
}
if varHasInitExpr(ctx, decl) {
ctx.logf(decl, "var %s: has initialized expression, skipped", cName)
ctx.ignoref(featQuietIgnore, decl, "var %s: has initialized expression, ignored", cName)
return
}

manglingName := clang.Mangling(decl)
if _, ok := ctx.nameLookup(manglingName); !ok {
ctx.logf(decl, "var %s: symbol not found in lib files, skipped", cName)
ctx.ignoref(featExplicitIgnore, decl, "var %s: symbol not found in lib files, ignored", cName)
return
}

Expand All @@ -63,14 +68,16 @@ func compileVar(ctx *pkgCtx, decl clang.Cursor) {
defs.New(goNodePos(ctx, decl), typ, goName)
}

func varHasInitExpr(_ *pkgCtx, v clang.Cursor) (hasInitExpr bool) {
func varHasInitExpr(ctx *pkgCtx, v clang.Cursor) (hasInitExpr bool) {
clang.VisitChildren(v, func(decl, parent clang.Cursor) clang.ChildVisitResult {
switch decl.Kind {
case lc.Cursor_InitListExpr, lc.Cursor_CallExpr:
case lc.Cursor_InitListExpr, lc.Cursor_CallExpr, lc.Cursor_DeclRefExpr,
lc.Cursor_UnaryOperator, lc.Cursor_UnexposedExpr:
hasInitExpr = true
return clang.Break
case lc.Cursor_TypeRef, lc.Cursor_UnaryExpr:
default:
// ctx.panicf(decl, "varHasInitExpr: unknown kind - %v", decl.Kind)
ctx.panicf(decl, "varHasInitExpr: unknown kind - %v", decl.Kind)
Comment thread
xushiwei marked this conversation as resolved.
}
return clang.Continue
})
Expand Down
4 changes: 2 additions & 2 deletions cmd/llcppg/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
// Gen generates Go files from the C/C++ header files and llcppg.cfg in the specified
// source directory and writes them to the destination directory. It uses the provided
// clang index for parsing.
func Gen(destDir, srcDir string, index clang.Index) (err error) {
func Gen(destDir, srcDir string, index clang.Index, verbose bool) (err error) {
Comment thread
xushiwei marked this conversation as resolved.
cfg, err := tool.LoadConf(filepath.Join(srcDir, "llcppg.cfg"))
if err != nil {
return
Expand All @@ -45,7 +45,7 @@ func Gen(destDir, srcDir string, index clang.Index) (err error) {
}
mainPkgName := cfg.Name

if cfg.IgnoreInline {
if !verbose && cfg.IgnoreInline {
cl.InlineFuncIgnore = cl.QuietIgnoreInline // quiet ignore inline functions
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/llcppg/llcppg.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func main() {

idx := clang.CreateIndex(1, 1)
defer idx.Dispose()
err := Gen(destDir, srcDir, idx)
err := Gen(destDir, srcDir, idx, *verbose || *debug)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
Expand Down
Loading
Loading