Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gopbuild: RegisterPackagePatch #275

Merged
merged 2 commits into from
Aug 28, 2024
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
46 changes: 27 additions & 19 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
Lookup func(root, path string) (dir string, found bool) // lookup external import
evalCallFn func(interp *Interp, call *ssa.Call, res ...interface{}) // internal eval func for repl
debugFunc func(*DebugInfo) // debug func
pkgs map[string]*sourcePackage // imports
pkgs map[string]*SourcePackage // imports
override map[string]reflect.Value // override function
evalInit map[string]bool // eval init check
nestedMap map[*types.Named]int // nested named index
Expand Down Expand Up @@ -107,22 +107,26 @@
return
}

type sourcePackage struct {
type SourcePackage struct {
Context *Context
Package *types.Package
Info *types.Info
Importer types.Importer
Files []*ast.File
Links []*load.LinkSym
Dir string
Register bool // register package
}

func (sp *sourcePackage) Load() (err error) {
func (sp *SourcePackage) Load() (err error) {
if sp.Info == nil {

Check warning on line 122 in context.go

View check run for this annotation

qiniu-x / golangci-lint

context.go#L122

`if sp.Info == nil` has complex nested blocks (complexity: 14) (nestif)
sp.Info = newTypesInfo()
if sp.Importer == nil {
sp.Importer = NewImporter(sp.Context)
}
conf := &types.Config{
Sizes: sp.Context.sizes,
Importer: NewImporter(sp.Context),
Importer: sp.Importer,
}
if sp.Context.evalMode {
conf.DisableUnusedImportCheck = true
Expand Down Expand Up @@ -161,7 +165,7 @@
Mode: mode,
BuilderMode: 0, //ssa.SanityCheckFunctions,
BuildContext: build.Default,
pkgs: make(map[string]*sourcePackage),
pkgs: make(map[string]*SourcePackage),
override: make(map[string]reflect.Value),
nestedMap: make(map[*types.Named]int),
callForPool: 64,
Expand Down Expand Up @@ -245,7 +249,7 @@
return nil, err
}
bp.ImportPath = importPath
var sp *sourcePackage
var sp *SourcePackage
if test {
sp, err = ctx.loadTestPackage(bp, importPath, dir)
} else {
Expand Down Expand Up @@ -293,7 +297,11 @@
return
}

func (ctx *Context) addImportFile(path string, filename string, src interface{}) (*sourcePackage, error) {
func (ctx *Context) SourcePackage(path string) *SourcePackage {
return ctx.pkgs[path]
}

func (ctx *Context) addImportFile(path string, filename string, src interface{}) (*SourcePackage, error) {
tp, err := ctx.loadPackageFile(path, filename, src)
if err != nil {
return nil, err
Expand All @@ -302,7 +310,7 @@
return tp, nil
}

func (ctx *Context) addImport(path string, dir string) (*sourcePackage, error) {
func (ctx *Context) addImport(path string, dir string) (*SourcePackage, error) {
bp, err := ctx.BuildContext.ImportDir(dir, 0)
if err != nil {
return nil, err
Expand All @@ -316,13 +324,13 @@
return tp, nil
}

func (ctx *Context) loadPackageFile(path string, filename string, src interface{}) (*sourcePackage, error) {
func (ctx *Context) loadPackageFile(path string, filename string, src interface{}) (*SourcePackage, error) {
file, err := ctx.ParseFile(filename, src)
if err != nil {
return nil, err
}
pkg := types.NewPackage(path, file.Name.Name)
tp := &sourcePackage{
tp := &SourcePackage{
Context: ctx,
Package: pkg,
Files: []*ast.File{file},
Expand All @@ -331,7 +339,7 @@
return tp, nil
}

func (ctx *Context) loadPackage(bp *build.Package, path string, dir string) (*sourcePackage, error) {
func (ctx *Context) loadPackage(bp *build.Package, path string, dir string) (*SourcePackage, error) {
files, err := ctx.parseGoFiles(dir, append(bp.GoFiles, bp.CgoFiles...))
if err != nil {
return nil, err
Expand All @@ -343,10 +351,10 @@
if embed != nil {
files = append(files, embed)
}
if bp.Name == "main" {

Check warning on line 354 in context.go

View check run for this annotation

qiniu-x / golangci-lint

context.go#L354

string `main` has 5 occurrences, make it a constant (goconst)
path = "main"
}
tp := &sourcePackage{
tp := &SourcePackage{
Package: types.NewPackage(path, bp.Name),
Files: files,
Dir: dir,
Expand All @@ -356,7 +364,7 @@
return tp, nil
}

func (ctx *Context) loadTestPackage(bp *build.Package, path string, dir string) (*sourcePackage, error) {
func (ctx *Context) loadTestPackage(bp *build.Package, path string, dir string) (*SourcePackage, error) {
if len(bp.TestGoFiles) == 0 && len(bp.XTestGoFiles) == 0 {
return nil, ErrNoTestFiles
}
Expand All @@ -371,7 +379,7 @@
if embed != nil {
files = append(files, embed)
}
tp := &sourcePackage{
tp := &SourcePackage{
Package: types.NewPackage(path, bp.Name),
Files: files,
Dir: dir,
Expand All @@ -390,7 +398,7 @@
if embed != nil {
files = append(files, embed)
}
tp := &sourcePackage{
tp := &SourcePackage{
Package: types.NewPackage(path+"_test", bp.Name+"_test"),
Files: files,
Dir: dir,
Expand All @@ -406,7 +414,7 @@
if err != nil {
return nil, err
}
return &sourcePackage{
return &SourcePackage{
Package: types.NewPackage(path+".test", "main"),
Files: []*ast.File{f},
Dir: dir,
Expand Down Expand Up @@ -485,7 +493,7 @@
if embed != nil {
files = append(files, embed)
}
sp := &sourcePackage{
sp := &SourcePackage{
Context: ctx,
Package: types.NewPackage(path, file.Name.Name),
Files: files,
Expand All @@ -507,7 +515,7 @@
files = append([]*ast.File{f}, files...)
}
}
sp := &sourcePackage{
sp := &SourcePackage{
Context: ctx,
Package: types.NewPackage(path, apkg.Name),
Files: files,
Expand Down Expand Up @@ -668,7 +676,7 @@
return ctx.TestPkg(pkg, dir, args)
}

func (ctx *Context) buildPackage(sp *sourcePackage) (pkg *ssa.Package, err error) {
func (ctx *Context) buildPackage(sp *SourcePackage) (pkg *ssa.Package, err error) {

Check warning on line 679 in context.go

View check run for this annotation

qiniu-x / golangci-lint

context.go#L679

cognitive complexity 50 of func `(*Context).buildPackage` is high (> 30) (gocognit)
if ctx.Mode&DisableRecover == 0 {
defer func() {
if e := recover(); e != nil {
Expand Down
65 changes: 61 additions & 4 deletions gopbuild/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
FileSet *token.FileSet
Importer *igop.Importer
Loader igop.Loader
pkgs map[string]*types.Package
}

func ClassKind(fname string) (isProj, ok bool) {
Expand Down Expand Up @@ -186,7 +187,17 @@
ctx = igop.NewContext(0)
}
ctx.Mode |= igop.CheckGopOverloadFunc
return &Context{Context: ctx, Importer: igop.NewImporter(ctx), FileSet: token.NewFileSet(), Loader: igop.NewTypesLoader(ctx, 0)}
c := &Context{Context: ctx, Importer: igop.NewImporter(ctx), FileSet: token.NewFileSet(),
Loader: igop.NewTypesLoader(ctx, 0), pkgs: make(map[string]*types.Package)}
return c
}

func RegisterPackagePatch(ctx *igop.Context, path string, src interface{}) error {
err := ctx.AddImportFile(path+"@patch", "src.go", src)
if err != nil {
return err
}
return ctx.AddImportFile(path+"@patch.gop", "src.go", src)
}

func isGopPackage(path string) bool {
Expand All @@ -198,11 +209,57 @@
return false
}

func (c *Context) Import(path string) (*types.Package, error) {
func (c *Context) importPath(path string) (gop bool, pkg *types.Package, err error) {
if isGopPackage(path) {
return c.Loader.Import(path)
gop = true
pkg, err = c.Loader.Import(path)
} else {
pkg, err = c.Importer.Import(path)
}
return
}

func (c *Context) Import(path string) (*types.Package, error) {
if pkg, ok := c.pkgs[path]; ok {
return pkg, nil
}
gop, pkg, err := c.importPath(path)
if err != nil {
return pkg, err
}
c.pkgs[path] = pkg
if gop {

Check warning on line 231 in gopbuild/build.go

View check run for this annotation

qiniu-x / golangci-lint

gopbuild/build.go#L231

`if gop` has complex nested blocks (complexity: 5) (nestif)
if sp := c.Context.SourcePackage(path + "@patch.gop"); sp != nil {
sp.Importer = c
err := sp.Load()
if err != nil {
return nil, err
}
patch := types.NewPackage(path+"@patch", pkg.Name())
for _, name := range sp.Package.Scope().Names() {
obj := sp.Package.Scope().Lookup(name)
switch obj.(type) {

Check warning on line 241 in gopbuild/build.go

View check run for this annotation

qiniu-x / golangci-lint

gopbuild/build.go#L241

typeSwitchVar: 1 case can benefit from type switch with assignment (gocritic)
case *types.Func:
obj = types.NewFunc(obj.Pos(), patch, obj.Name(), obj.Type().(*types.Signature))
case *types.TypeName:
named := obj.Type().(*types.Named)
var methods []*types.Func
if n := named.NumMethods(); n > 0 {
methods = make([]*types.Func, n)
for i := 0; i < n; i++ {
methods[i] = named.Method(i)
}
}
obj = types.NewTypeName(obj.Pos(), patch, obj.Name(), nil)
types.NewNamed(obj.(*types.TypeName), named.Underlying(), methods)
default:
continue
}
pkg.Scope().Insert(obj)
}
}
}
return c.Importer.Import(path)
return pkg, nil
}

func (c *Context) ParseDir(dir string) (*Package, error) {
Expand Down
74 changes: 74 additions & 0 deletions gopbuild/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,3 +427,77 @@ 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"

type Point struct {
X int
Y int
}

func (p *Point) Info() {
println(p.X, p.Y)
}

type Info interface {
Info()
}

func Dump(i Info) {
i.Info()
}

func Gopt_App_Gopx_GetWidget[T any](app any, name string) {
var _ gsh.App
println(app, name)
}
`)
src := `
getWidget(int,"info")
pt := &Point{100,200}
pt.Info()
println(pt.X)
dump(pt)
`
expected := `package main

import (
"fmt"
"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")
//line main.gsh:3:1
pt := &gsh1.Point{100, 200}
//line main.gsh:4:1
pt.Info()
//line main.gsh:5:1
fmt.Println(pt.X)
//line main.gsh:6:1
gsh1.Dump(pt)
}
func (this *App) Main() {
gsh.Gopt_App_Main(this)
}
func main() {
new(App).Main()
}
`
data, err := BuildFile(ctx, "main.gsh", src)
if err != nil {
t.Fatal(err)
}
if string(data) != expected {
t.Fatal("build error:\n", string(data))
}
}
Loading