Beispiel #1
0
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
}
Beispiel #2
0
func isInterface(t types.Type) bool { return types.IsInterface(t) }
Beispiel #3
0
func isInterface(T types.Type) bool { return types.IsInterface(T) }
Beispiel #4
0
// 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
}