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 }