Skip to content

Commit

Permalink
gogensig:refine method name generate & check
Browse files Browse the repository at this point in the history
  • Loading branch information
luoliwoshang committed Dec 27, 2024
1 parent 5034299 commit d517aab
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 48 deletions.
37 changes: 20 additions & 17 deletions cmd/gogensig/convert/funcname.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
package convert

import "strings"
import (
"strings"
)

type GoFuncName struct {
goSymbolName string
recvName string
funcName string
ptrRecv bool // if the receiver is a pointer
// GoFuncSpec parses and stores components of a Go function name
// Input examples from llcppg.symb.json's "go" field:
// 1. Simple function: "AddPatchToArray"
// 2. Method with pointer receiver: "(*Sqlite3Stmt).Sqlite3BindParameterIndex"
// 3. Method with value receiver: "CJSONBool.CJSONCreateBool"
type GoFuncSpec struct {
GoSymbName string // original full name from input
FnName string // function name without receiver
IsMethod bool // if the function is a method
RecvName string // receiver name
PtrRecv bool // if the receiver is a pointer
}

func NewGoFuncName(name string) *GoFuncName {
// - "AddPatchToArray" -> {goSymbolName: "AddPatchToArray", funcName: "AddPatchToArray"}
// - "(*Sqlite3Stmt).Sqlite3BindParameterIndex" -> {goSymbolName: "...", recvName: "Sqlite3Stmt", funcName: "Sqlite3BindParameterIndex", ptrRecv: true}
// - "CJSONBool.CJSONCreateBool" -> {goSymbolName: "...", recvName: "CJSONBool", funcName: "CJSONCreateBool", ptrRecv: false}
func NewGoFuncSpec(name string) *GoFuncSpec {
l := strings.Split(name, ".")
if len(l) < 2 {
return &GoFuncName{goSymbolName: name, funcName: name}
return &GoFuncSpec{GoSymbName: name, FnName: name, IsMethod: false}
}
recvName := l[0]
ptrRecv := false
Expand All @@ -21,13 +32,5 @@ func NewGoFuncName(name string) *GoFuncName {
recvName = strings.TrimPrefix(recvName, "(*")
recvName = strings.TrimSuffix(recvName, ")")
}
return &GoFuncName{goSymbolName: name, recvName: recvName, funcName: l[1], ptrRecv: ptrRecv}
}

func (p *GoFuncName) HasReceiver() bool {
return len(p.recvName) > 0
}

func (p *GoFuncName) OriginGoSymbolName() string {
return p.goSymbolName
return &GoFuncSpec{GoSymbName: name, RecvName: recvName, FnName: l[1], PtrRecv: ptrRecv, IsMethod: true}
}
64 changes: 37 additions & 27 deletions cmd/gogensig/convert/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,11 @@ func (p *Package) newReceiver(typ *ast.FuncType) *types.Var {
return p.p.NewParam(token.NoPos, "recv_", recvType)
}

func (p *Package) ToSigSignature(goFuncName *GoFuncName, funcDecl *ast.FuncDecl) (*types.Signature, error) {
func (p *Package) ToSigSignature(fnSpec *GoFuncSpec, funcDecl *ast.FuncDecl) (*types.Signature, error) {
var sig *types.Signature
var recv *types.Var
var err error
if goFuncName.HasReceiver() &&
if fnSpec.IsMethod &&
funcDecl.Type.Params.List != nil &&
len(funcDecl.Type.Params.List) > 0 {
recv = p.newReceiver(funcDecl.Type)
Expand All @@ -174,40 +174,51 @@ func (p *Package) bodyStart(decl *gogen.Func, ret ast.Expr) error {
return nil
}

func (p *Package) newFuncDeclAndComment(goFuncName *GoFuncName, sig *types.Signature, funcDecl *ast.FuncDecl) error {
func (p *Package) handleFuncDecl(fnSpec *GoFuncSpec, sig *types.Signature, funcDecl *ast.FuncDecl) error {
var decl *gogen.Func
funcPubname := goFuncName.OriginGoSymbolName()
if goFuncName.HasReceiver() {
decl = p.p.NewFuncDecl(token.NoPos, goFuncName.funcName, sig)
fnPubName := fnSpec.GoSymbName
if fnSpec.IsMethod {
decl = p.p.NewFuncDecl(token.NoPos, fnSpec.FnName, sig)
err := p.bodyStart(decl, funcDecl.Type.Ret)
if err != nil {
return err
}

// we need to use the actual receiver name in link comment
// both for value receiver and pointer receiver

if t, ok := sig.Recv().Type().(*types.Pointer); ok {
elemType := t.Elem()
namedType := elemType.(*types.Named)
name := namedType.Obj().Name()
funcPubname = "(*" + name + ")." + goFuncName.funcName
}

if t, ok := sig.Recv().Type().(*types.Named); ok {
name := t.Obj().Name()
funcPubname = name + "." + goFuncName.funcName
}
fnPubName = pubMethodName(sig.Recv().Type(), fnSpec.FnName)
} else {
decl = p.p.NewFuncDecl(token.NoPos, funcPubname, sig)
decl = p.p.NewFuncDecl(token.NoPos, fnPubName, sig)
}

doc := CommentGroup(funcDecl.Doc)
doc.AddCommentGroup(NewFuncDocComments(funcDecl.Name.Name, funcPubname))
doc.AddCommentGroup(NewFuncDocComments(funcDecl.Name.Name, fnPubName))
decl.SetComments(p.p, doc.CommentGroup)
return nil
}

// pubMethodName generates a public method name based on the receiver type and function name.
// It handles both pointer and value receivers.
//
// Parameters:
// - recv: The receiver type from types.Signature
// - fnName: The base function name
//
// Returns:
// - For pointer receiver: "(*TypeName).FuncName"
// - For value receiver: "TypeName.FuncName"
// - For invalid/unknown receiver: just "FuncName"
func pubMethodName(recv types.Type, fnName string) string {
switch t := recv.(type) {
case *types.Pointer:
if named, ok := t.Elem().(*types.Named); ok {
return "(*" + named.Obj().Name() + ")." + fnName
}
case *types.Named:
return t.Obj().Name() + "." + fnName
}
return fnName
}

func (p *Package) NewFuncDecl(funcDecl *ast.FuncDecl) error {
skip, anony, err := p.cvt.handleSysType(funcDecl.Name, funcDecl.Loc, p.curFile.sysIncPath)
if skip {
Expand All @@ -223,20 +234,19 @@ func (p *Package) NewFuncDecl(funcDecl *ast.FuncDecl) error {
return errs.NewAnonymousFuncNotSupportError()
}

goSymbolName, err := p.cvt.LookupSymbol(funcDecl.MangledName)
fnSpec, err := p.cvt.LookupSymbol(funcDecl.MangledName)
if err != nil {
// not gen the function not in the symbolmap
return err
}
if obj := p.p.Types.Scope().Lookup(goSymbolName); obj != nil {
return errs.NewFuncAlreadyDefinedError(goSymbolName)
if obj := p.p.Types.Scope().Lookup(fnSpec.FnName); obj != nil {
return errs.NewFuncAlreadyDefinedError(fnSpec.GoSymbName)
}
goFuncName := NewGoFuncName(goSymbolName)
sig, err := p.ToSigSignature(goFuncName, funcDecl)
sig, err := p.ToSigSignature(fnSpec, funcDecl)
if err != nil {
return err
}
return p.newFuncDeclAndComment(goFuncName, sig, funcDecl)
return p.handleFuncDecl(fnSpec, sig, funcDecl)
}

// NewTypeDecl converts C/C++ type declarations to Go.
Expand Down
8 changes: 4 additions & 4 deletions cmd/gogensig/convert/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,15 +414,15 @@ func (p *TypeConv) referSysType(name string) (types.Object, error) {
return nil, nil
}

func (p *TypeConv) LookupSymbol(mangleName config.MangleNameType) (config.GoNameType, error) {
func (p *TypeConv) LookupSymbol(mangleName config.MangleNameType) (*GoFuncSpec, error) {
if p.symbolTable == nil {
return "", fmt.Errorf("symbol table not initialized")
return nil, fmt.Errorf("symbol table not initialized")
}
e, err := p.symbolTable.LookupSymbol(mangleName)
if err != nil {
return "", err
return nil, err
}
return e.GoName, nil
return NewGoFuncName(e.GoName), nil

Check failure on line 425 in cmd/gogensig/convert/type.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-24.04, 18)

undefined: NewGoFuncName
}

// The field name should be public if it's a record field
Expand Down

0 comments on commit d517aab

Please sign in to comment.