func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.Node, obj *types.Var, expKind string, wantAddr bool) { // The prefix of all assertions messages. prefix := fmt.Sprintf("VarValue(%s @ L%d)", obj, prog.Fset.Position(ref[0].Pos()).Line) v := prog.VarValue(obj, pkg, ref) // Kind is the concrete type of the ssa Value. gotKind := "nil" if v != nil { gotKind = fmt.Sprintf("%T", v)[len("*ssa."):] } // fmt.Printf("%s = %v (kind %q; expect %q) addr=%t\n", prefix, v, gotKind, expKind, wantAddr) // debugging // Check the kinds match. // "nil" indicates expected failure (e.g. optimized away). if expKind != gotKind { t.Errorf("%s concrete type == %s, want %s", prefix, gotKind, expKind) } // Check the types match. // If wantAddr, the expected type is the object's address. if v != nil { expType := obj.Type() if wantAddr { expType = types.NewPointer(expType) } if !types.IsIdentical(v.Type(), expType) { t.Errorf("%s.Type() == %s, want %s", prefix, v.Type(), expType) } } }
// ssaValueForExpr returns the ssa.Value of the non-ast.Ident // expression whose path to the root of the AST is path. It may // return a nil Value without an error to indicate the pointer // analysis is not appropriate. // func ssaValueForExpr(prog *ssa.Program, qinfo *importer.PackageInfo, path []ast.Node) (ssa.Value, error) { pkg := prog.Package(qinfo.Pkg) pkg.SetDebugMode(true) pkg.Build() fn := ssa.EnclosingFunction(pkg, path) if fn == nil { return nil, fmt.Errorf("no SSA function built for this location (dead code?)") } if v := fn.ValueForExpr(path[0].(ast.Expr)); v != nil { return v, nil } return nil, fmt.Errorf("can't locate SSA Value for expression in %s", fn) }
func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) { fn := prog.FuncValue(obj) // fmt.Printf("FuncValue(%s) = %s\n", obj, fn) // debugging if fn == nil { t.Errorf("FuncValue(%s) == nil", obj) return } if fnobj := fn.Object(); fnobj != obj { t.Errorf("FuncValue(%s).Object() == %s; value was %s", obj, fnobj, fn.Name()) return } if !types.IsIdentical(fn.Type(), obj.Type()) { t.Errorf("FuncValue(%s).Type() == %s", obj, fn.Type()) return } }
// ssaValueForIdent returns the ssa.Value for the ast.Ident whose path // to the root of the AST is path. It may return a nil Value without // an error to indicate the pointer analysis is not appropriate. // func ssaValueForIdent(prog *ssa.Program, qinfo *importer.PackageInfo, obj types.Object, path []ast.Node) (ssa.Value, error) { if obj, ok := obj.(*types.Var); ok { pkg := prog.Package(qinfo.Pkg) pkg.Build() if v := prog.VarValue(obj, pkg, path); v != nil { // Don't run pointer analysis on a ref to a const expression. if _, ok := v.(*ssa.Const); ok { v = nil } return v, nil } return nil, fmt.Errorf("can't locate SSA Value for var %s", obj.Name()) } // Don't run pointer analysis on const/func objects. return nil, nil }
func checkConstValue(t *testing.T, prog *ssa.Program, obj *types.Const) { c := prog.ConstValue(obj) // fmt.Printf("ConstValue(%s) = %s\n", obj, c) // debugging if c == nil { t.Errorf("ConstValue(%s) == nil", obj) return } if !types.IsIdentical(c.Type(), obj.Type()) { t.Errorf("ConstValue(%s).Type() == %s", obj, c.Type()) return } if obj.Name() != "nil" { if !exact.Compare(c.Value, token.EQL, obj.Val()) { t.Errorf("ConstValue(%s).Value (%s) != %s", obj, c.Value, obj.Val()) return } } }
// ssaValueForIdent returns the ssa.Value for the ast.Ident whose path // to the root of the AST is path. isAddr reports whether the // ssa.Value is the address denoted by the ast.Ident, not its value. // func ssaValueForIdent(prog *ssa.Program, qinfo *importer.PackageInfo, obj types.Object, path []ast.Node) (value ssa.Value, isAddr bool, err error) { switch obj := obj.(type) { case *types.Var: pkg := prog.Package(qinfo.Pkg) pkg.Build() if v, addr := prog.VarValue(obj, pkg, path); v != nil { return v, addr, nil } return nil, false, fmt.Errorf("can't locate SSA Value for var %s", obj.Name()) case *types.Func: return prog.FuncValue(obj), false, nil } panic(obj) }