diff --git a/gopbuild/build.go b/gopbuild/build.go index 15a18580..d4ac2a15 100644 --- a/gopbuild/build.go +++ b/gopbuild/build.go @@ -156,6 +156,7 @@ type Context struct { FileSet *token.FileSet Importer *igop.Importer Loader igop.Loader + pkgs map[string]*types.Package } func ClassKind(fname string) (isProj, ok bool) { @@ -186,7 +187,12 @@ func NewContext(ctx *igop.Context) *Context { ctx = igop.NewContext(0) } ctx.Mode |= igop.CheckGopOverloadFunc - return &Context{Context: ctx, Importer: igop.NewImporter(ctx), FileSet: token.NewFileSet(), Loader: igop.NewTypesLoader(ctx, 0)} + return &Context{Context: ctx, Importer: igop.NewImporter(ctx), FileSet: token.NewFileSet(), + Loader: igop.NewTypesLoader(ctx, 0), pkgs: make(map[string]*types.Package)} +} + +func RegisterPackagePatch(ctx *igop.Context, path string, src string) error { + return ctx.AddImportFile(path+"@patch", "src.go", src) } func isGopPackage(path string) bool { @@ -198,13 +204,30 @@ func isGopPackage(path string) bool { return false } -func (c *Context) Import(path string) (*types.Package, error) { +func (c *Context) importPath(path string) (*types.Package, error) { if isGopPackage(path) { return c.Loader.Import(path) } return c.Importer.Import(path) } +func (c *Context) Import(path string) (*types.Package, error) { + if pkg, ok := c.pkgs[path]; ok { + return pkg, nil + } + pkg, err := c.importPath(path) + if err != nil { + return nil, err + } + if patch, err := c.Context.Loader.Import(path + "@patch"); err == nil { + for _, name := range patch.Scope().Names() { + pkg.Scope().Insert(patch.Scope().Lookup(name)) + } + } + c.pkgs[path] = pkg + return pkg, nil +} + func (c *Context) ParseDir(dir string) (*Package, error) { pkgs, err := parser.ParseDirEx(c.FileSet, dir, parser.Config{ ClassKind: ClassKind, diff --git a/gopbuild/build_test.go b/gopbuild/build_test.go index 0c9575f9..b835ada2 100644 --- a/gopbuild/build_test.go +++ b/gopbuild/build_test.go @@ -427,3 +427,46 @@ func main() { } `) } + +func TestPackagePatch(t *testing.T) { + ctx := igop.NewContext(0) + RegisterPackagePatch(ctx, "github.com/qiniu/x/gsh", `package gsh +import "github.com/qiniu/x/gsh" + +func Gopt_App_Gopx_GetWidget[T any](app any, name string) { + var _ gsh.App + println(app, name) +} +`) + expected := `package main + +import ( + "github.com/qiniu/x/gsh" + gsh1 "github.com/qiniu/x/gsh@patch" +) + +type App struct { + gsh.App +} +//line main.gsh:2 +func (this *App) MainEntry() { +//line main.gsh:2:1 + gsh1.Gopt_App_Gopx_GetWidget[int](this, "info") +} +func (this *App) Main() { + gsh.Gopt_App_Main(this) +} +func main() { + new(App).Main() +} +` + data, err := BuildFile(ctx, "main.gsh", ` +getWidget(int,"info") +`) + if err != nil { + t.Fatal(err) + } + if string(data) != expected { + t.Fatal("build error", string(data)) + } +}