func (u *Unexporter) isInterfaceMethod(e Export) map[string][]*types.Package { if _, ok := e.obj.(*types.Func); !ok { return nil } f := e.obj.(*types.Func) r := f.Type().(*types.Signature).Recv() if r == nil { return nil } if u.f == nil { calculateConstraints(u) } interfaces := make(map[string][]*types.Package) for constraint := range u.f { if constraint.RHS == r.Type() && types.IsInterface(constraint.LHS) { sure, _, _ := types.LookupFieldOrMethod(constraint.LHS, true, f.Pkg(), f.Name()) if sure != nil { interfaces[constraint.LHS.String()] = append(interfaces[constraint.LHS.String()], f.Pkg()) } } } return interfaces }
func isInterface(t types.Type) bool { return types.IsInterface(t) }
func isInterface(T types.Type) bool { return types.IsInterface(T) }
// Callees reports the possible callees of the function call site // identified by the specified source location. func callees(q *Query) error { lconf := loader.Config{Build: q.Build} if err := setPTAScope(&lconf, q.Scope); err != nil { return err } // Load/parse/type-check the program. lprog, err := lconf.Load() if err != nil { return err } q.Fset = lprog.Fset qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos if err != nil { return err } // Determine the enclosing call for the specified position. var e *ast.CallExpr for _, n := range qpos.path { if e, _ = n.(*ast.CallExpr); e != nil { break } } if e == nil { return fmt.Errorf("there is no function call here") } // TODO(adonovan): issue an error if the call is "too far // away" from the current selection, as this most likely is // not what the user intended. // Reject type conversions. if qpos.info.Types[e.Fun].IsType() { return fmt.Errorf("this is a type conversion, not a function call") } // Deal with obviously static calls before constructing SSA form. // Some static calls may yet require SSA construction, // e.g. f := func(){}; f(). switch funexpr := unparen(e.Fun).(type) { case *ast.Ident: switch obj := qpos.info.Uses[funexpr].(type) { case *types.Builtin: // Reject calls to built-ins. return fmt.Errorf("this is a call to the built-in '%s' operator", obj.Name()) case *types.Func: // This is a static function call q.result = &calleesTypesResult{ site: e, callee: obj, } return nil } case *ast.SelectorExpr: sel := qpos.info.Selections[funexpr] if sel == nil { // qualified identifier. // May refer to top level function variable // or to top level function. callee := qpos.info.Uses[funexpr.Sel] if obj, ok := callee.(*types.Func); ok { q.result = &calleesTypesResult{ site: e, callee: obj, } return nil } } else if sel.Kind() == types.MethodVal { recvtype := sel.Recv() if !types.IsInterface(recvtype) { // static method call q.result = &calleesTypesResult{ site: e, callee: sel.Obj().(*types.Func), } return nil } } } prog := ssautil.CreateProgram(lprog, ssa.GlobalDebug) ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection) if err != nil { return err } pkg := prog.Package(qpos.info.Pkg) if pkg == nil { return fmt.Errorf("no SSA package") } // Defer SSA construction till after errors are reported. prog.BuildAll() // Ascertain calling function and call site. callerFn := ssa.EnclosingFunction(pkg, qpos.path) if callerFn == nil { return fmt.Errorf("no SSA function built for this location (dead code?)") } // Find the call site. site, err := findCallSite(callerFn, e) if err != nil { return err } funcs, err := findCallees(ptaConfig, site) if err != nil { return err } q.result = &calleesSSAResult{ site: site, funcs: funcs, } return nil }