github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/x/pkgx/pkgx.go (about)

     1  package pkgx
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  	"go/types"
     7  
     8  	. "golang.org/x/tools/go/packages"
     9  )
    10  
    11  // .
    12  // Package
    13  // Set
    14  // Load
    15  // Config
    16  // LoadMode
    17  
    18  type Pkg struct {
    19  	*Package
    20  	imports []*Package
    21  }
    22  
    23  type Pos interface{ Pos() token.Pos }
    24  
    25  type End interface{ End() token.Pos }
    26  
    27  func LoadFrom(pattern string) (*Pkg, error) {
    28  	lst, err := Load(
    29  		&Config{Mode: LoadMode(0b111111111111)},
    30  		pattern,
    31  	)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	return New(lst[0]), nil
    36  }
    37  
    38  func New(pkg *Package) *Pkg {
    39  	imports := &Set{}
    40  	imports.Append(pkg)
    41  	return &Pkg{
    42  		Package: pkg,
    43  		imports: imports.List(),
    44  	}
    45  }
    46  
    47  func (p *Pkg) Imports() []*Package { return p.imports }
    48  
    49  func (p *Pkg) Const(name string) *types.Const {
    50  	for ident, def := range p.TypesInfo.Defs {
    51  		if t, ok := def.(*types.Const); ok && ident.Name == name {
    52  			return t
    53  		}
    54  	}
    55  	return nil
    56  }
    57  
    58  func (p *Pkg) TypeName(name string) *types.TypeName {
    59  	for ident, def := range p.TypesInfo.Defs {
    60  		t, ok := def.(*types.TypeName)
    61  		if ok && ident.Name == name {
    62  			return t
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  func (p *Pkg) Var(name string) *types.Var {
    69  	for ident, def := range p.TypesInfo.Defs {
    70  		if t, ok := def.(*types.Var); ok && ident.Name == name {
    71  			return t
    72  		}
    73  	}
    74  	return nil
    75  }
    76  
    77  func (p *Pkg) Func(name string) *types.Func {
    78  	for ident, def := range p.TypesInfo.Defs {
    79  		if t, ok := def.(*types.Func); ok && ident.Name == name {
    80  			return t
    81  		}
    82  	}
    83  	return nil
    84  }
    85  
    86  func (p *Pkg) PkgByPath(path string) *Package {
    87  	for _, pkg := range p.imports {
    88  		if path == pkg.PkgPath {
    89  			return pkg
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  func (p *Pkg) PkgByPos(n Pos) *Package {
    96  	for _, pkg := range p.imports {
    97  		for _, file := range pkg.Syntax {
    98  			if file.Pos() <= n.Pos() && file.End() > n.Pos() {
    99  				return pkg
   100  			}
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  func (p *Pkg) PkgOf(n Pos) *types.Package {
   107  	pkg := p.PkgByPos(n)
   108  	if pkg != nil {
   109  		return pkg.Types
   110  	}
   111  	return nil
   112  }
   113  
   114  func (p *Pkg) PkgInfoOf(n Pos) *types.Info {
   115  	pkg := p.PkgByPos(n)
   116  	if pkg != nil {
   117  		return pkg.TypesInfo
   118  	}
   119  	return nil
   120  }
   121  
   122  func (p *Pkg) FileOf(n Pos) *ast.File {
   123  	for _, pkg := range p.imports {
   124  		for _, file := range pkg.Syntax {
   125  			if file.Pos() <= n.Pos() && file.End() > n.Pos() {
   126  				return file
   127  			}
   128  		}
   129  	}
   130  	return nil
   131  }
   132  
   133  func (p *Pkg) IdentOf(obj types.Object) *ast.Ident {
   134  	info := p.PkgByPath(obj.Pkg().Path())
   135  
   136  	for ident, def := range info.TypesInfo.Defs {
   137  		if def == obj {
   138  			return ident
   139  		}
   140  	}
   141  	return nil
   142  }
   143  
   144  func (p *Pkg) CommentsOf(n ast.Node) string {
   145  	if f := p.FileOf(n); f == nil {
   146  		return ""
   147  	} else {
   148  		return NewCommentScanner(p.Fset, f).CommentsOf(n)
   149  	}
   150  }
   151  
   152  func (p *Pkg) Eval(expr ast.Expr) (types.TypeAndValue, error) {
   153  	return types.Eval(
   154  		p.Fset, p.PkgOf(expr), expr.Pos(), StringifyNode(p.Fset, expr),
   155  	)
   156  }
   157  
   158  func (p *Pkg) FuncDeclOf(fn *types.Func) (decl *ast.FuncDecl) {
   159  	ast.Inspect(p.FileOf(fn), func(node ast.Node) bool {
   160  		fd, ok := node.(*ast.FuncDecl)
   161  		if !ok {
   162  			return true
   163  		}
   164  		if fd.Body != nil && fd.Pos() <= fn.Pos() && fn.Pos() < fd.Body.Pos() {
   165  			decl = fd
   166  			return false
   167  		}
   168  		return true
   169  	})
   170  	return
   171  }
   172  
   173  func (p *Pkg) ResultsOf(callee *ast.CallExpr) Results {
   174  	typ := p.PkgInfoOf(callee).TypeOf(callee)
   175  	res := Results{}
   176  
   177  	switch t := typ.(type) {
   178  	case *types.Tuple:
   179  		for i := 0; i < t.Len(); i++ {
   180  			p.AppendResult(res, i, TypeAndValueExpr{
   181  				TypeAndValue: types.TypeAndValue{Type: t.At(i).Type()},
   182  				Expr:         callee,
   183  			})
   184  		}
   185  	default:
   186  		p.AppendResult(res, 0, TypeAndValueExpr{
   187  			TypeAndValue: types.TypeAndValue{Type: t},
   188  			Expr:         callee,
   189  		})
   190  	}
   191  
   192  	return res
   193  }
   194  
   195  func (p *Pkg) AssignedValueOf(ident *ast.Ident, pos token.Pos) []TypeAndValueExpr {
   196  	var blk *ast.BlockStmt
   197  
   198  	ast.Inspect(p.FileOf(ident), func(node ast.Node) bool {
   199  		switch fn := node.(type) {
   200  		case *ast.FuncLit:
   201  			if fn.Pos() <= ident.Pos() && ident.Pos() <= fn.End() {
   202  				blk = fn.Body
   203  			}
   204  			return false
   205  		case *ast.FuncDecl:
   206  			if fn.Pos() <= ident.Pos() && ident.Pos() <= fn.End() {
   207  				blk = fn.Body
   208  			}
   209  			return false
   210  		}
   211  		return true
   212  	})
   213  
   214  	if blk == nil {
   215  		return nil
   216  	}
   217  
   218  	var (
   219  		ass *ast.AssignStmt
   220  		idx = 0
   221  	)
   222  	scan := func(n ast.Node) {
   223  		nodes := []ast.Node{n}
   224  		for len(nodes) > 0 {
   225  			n, nodes = nodes[0], nodes[1:]
   226  			ast.Inspect(n, func(node ast.Node) bool {
   227  				if node == nil || node.Pos() > pos {
   228  					return false
   229  				}
   230  				switch stmt := node.(type) {
   231  				case *ast.CaseClause:
   232  					return !IsBlockContainsReturn(stmt) ||
   233  						stmt.Pos() <= pos && pos < stmt.End()
   234  				case *ast.IfStmt:
   235  					if stmt.Else != nil {
   236  						nodes = append(nodes, stmt.Else)
   237  					}
   238  					return !IsBlockContainsReturn(stmt) ||
   239  						stmt.Body.Pos() <= pos && pos < stmt.Body.End()
   240  				case *ast.AssignStmt:
   241  					for i := range stmt.Lhs {
   242  						id, ok := stmt.Lhs[i].(*ast.Ident)
   243  						if ok && ident.Obj == id.Obj {
   244  							ass, idx = stmt, i
   245  						}
   246  					}
   247  				}
   248  				return true
   249  			})
   250  		}
   251  	}
   252  
   253  	if scan(blk); ass == nil {
   254  		return nil
   255  	}
   256  	res := Results{}
   257  	p.SetResultsByExpr(res, ass.Rhs...)
   258  	return res[idx]
   259  }
   260  
   261  func (p *Pkg) AppendResult(res Results, i int, tve TypeAndValueExpr) {
   262  	if _, ok := tve.Type.(*types.Interface); !ok {
   263  		res[i] = append(res[i], tve)
   264  		return
   265  	}
   266  	switch expr := tve.Expr.(type) {
   267  	case *ast.Ident:
   268  		res[i] = append(res[i], p.AssignedValueOf(expr, expr.Pos())...)
   269  	case *ast.SelectorExpr:
   270  		res[i] = append(res[i], p.AssignedValueOf(expr.Sel, expr.Sel.Pos())...)
   271  	default:
   272  		res[i] = append(res[i], tve)
   273  	}
   274  }
   275  
   276  func (p *Pkg) SetResultsByExpr(res Results, rhs ...ast.Expr) {
   277  	for i := range rhs {
   278  		switch e := rhs[i].(type) {
   279  		case *ast.CallExpr:
   280  			results := p.ResultsOf(e)
   281  			for j := 0; j < len(results); j++ {
   282  				if j > 0 {
   283  					i++
   284  				}
   285  				for _, tve := range results[j] {
   286  					res[i] = append(res[i], TypeAndValueExpr{
   287  						TypeAndValue: tve.TypeAndValue,
   288  						Expr:         tve.Expr,
   289  					})
   290  				}
   291  			}
   292  		default:
   293  			tv, _ := p.Eval(e)
   294  			p.AppendResult(res, i, TypeAndValueExpr{TypeAndValue: tv, Expr: e})
   295  		}
   296  	}
   297  }
   298  
   299  func (p *Pkg) FuncResultsOf(fn *types.Func) (Results, int) {
   300  	if fn == nil {
   301  		return nil, 0
   302  	}
   303  	decl := p.FuncDeclOf(fn)
   304  	if decl == nil {
   305  		return nil, 0
   306  	}
   307  	// TODO location interface?
   308  	return p.FuncResultsOfSignature(
   309  		fn.Type().(*types.Signature),
   310  		decl.Body,
   311  		decl.Type,
   312  	)
   313  }
   314  
   315  func (p *Pkg) FuncResultsOfSignature(sig *types.Signature, body *ast.BlockStmt, ft *ast.FuncType) (Results, int) {
   316  	tuple := sig.Results()
   317  	if tuple.Len() == 0 {
   318  		return nil, 0
   319  	}
   320  
   321  	idents := make([]*ast.Ident, 0) // return named idents
   322  
   323  	for _, field := range ft.Results.List {
   324  		for _, name := range field.Names {
   325  			idents = append(idents, name)
   326  		}
   327  	}
   328  
   329  	// all return statements
   330  	scan := func() []*ast.ReturnStmt {
   331  		stmts := make([]*ast.ReturnStmt, 0)
   332  		ast.Inspect(body, func(node ast.Node) bool {
   333  			switch stmt := node.(type) {
   334  			case *ast.FuncLit:
   335  				return false // inline declaration
   336  			case *ast.ReturnStmt:
   337  				stmts = append(stmts, stmt)
   338  			}
   339  			return true
   340  		})
   341  		return stmts
   342  	}
   343  
   344  	finals := Results{}
   345  	returns := scan() // return statements
   346  
   347  	for i := range returns {
   348  		if len(returns[i].Results) != 0 {
   349  			p.SetResultsByExpr(finals, returns[i].Results...)
   350  			continue
   351  		}
   352  		for j := 0; j < tuple.Len(); j++ {
   353  			// named returns
   354  			tves := p.AssignedValueOf(idents[j], returns[i].Pos())
   355  			if tves == nil {
   356  				_ = 0
   357  			}
   358  			for _, tve := range tves {
   359  				p.AppendResult(finals, j, tve)
   360  			}
   361  		}
   362  	}
   363  
   364  	for i := range finals {
   365  		for j := range finals[i] {
   366  			tve := finals[i][j]
   367  			switch t := tuple.At(i).Type().(type) {
   368  			case *types.Interface:
   369  				// nothing
   370  			case *types.Named:
   371  				if t.String() != "error" {
   372  					tve.Type = t
   373  				}
   374  			default:
   375  				tve.Type = t
   376  			}
   377  			finals[i][j] = tve
   378  		}
   379  	}
   380  
   381  	return finals, tuple.Len()
   382  }
   383  
   384  // Set package set, mapping imported package id and package info
   385  type Set map[string]*Package
   386  
   387  func (s Set) Append(pkg *Package) {
   388  	s[pkg.ID] = pkg
   389  	for i := range pkg.Imports {
   390  		if _, ok := s[i]; !ok {
   391  			s.Append(pkg.Imports[i])
   392  		}
   393  	}
   394  }
   395  
   396  func (s Set) List() (ret []*Package) {
   397  	for id := range s {
   398  		ret = append(ret, s[id])
   399  	}
   400  	return ret
   401  }