// Suggest returns a list of suggestion candidates and the length of // the text that should be replaced, if any. func (c *Suggester) Suggest(importer types.Importer, filename string, data []byte, cursor int) ([]Candidate, int) { if cursor < 0 { return nil, 0 } fset, pos, pkg := c.analyzePackage(importer, filename, data, cursor) scope := pkg.Scope().Innermost(pos) ctx, expr, partial := deduceCursorContext(data, cursor) b := candidateCollector{ localpkg: pkg, partial: partial, filter: objectFilters[partial], } switch ctx { case selectContext: tv, _ := types.Eval(fset, pkg, pos, expr) if lookdot.Walk(&tv, b.appendObject) { break } _, obj := scope.LookupParent(expr, pos) if pkgName, isPkg := obj.(*types.PkgName); isPkg { c.packageCandidates(pkgName.Imported(), &b) break } return nil, 0 case compositeLiteralContext: tv, _ := types.Eval(fset, pkg, pos, expr) if tv.IsType() { if _, isStruct := tv.Type.Underlying().(*types.Struct); isStruct { c.fieldNameCandidates(tv.Type, &b) break } } fallthrough default: c.scopeCandidates(scope, pos, &b) } res := b.getCandidates() if len(res) == 0 { return nil, 0 } return res, len(partial) }
func (p *Package) Eval(name string) (Type, error) { var result Type t, err := types.Eval(p.fset, p.Package, token.NoPos, name) if err != nil { return result, err } result = Type{ Pointer: isPointer(t.Type), Name: strings.TrimLeft(name, Pointer(true).String()), // trims the * if it exists Comparable: isComparable(t.Type), FullyComparable: isFullyComparable(t.Type), Numeric: isNumeric(t.Type), Ordered: isOrdered(t.Type), Type: t.Type, } if isInvalid(t.Type) { err := fmt.Errorf("invalid type: %s", name) return result, &TypeCheckError{err, false} } return result, nil }
func calc(expr string) constant.Value { fs := token.NewFileSet() // tr, _ := parser.ParseExpr(expr) tv, err := types.Eval(fs, nil, token.NoPos, expr) log.Println(tv.Value, err) if err == nil { return tv.Value } ZERO := new(constant.Value) return *ZERO }
// isUntypedConst reports whether expr is an untyped constant, // and indicates what its default type is. // scope may be nil. func (f *file) isUntypedConst(expr ast.Expr) (defType string, ok bool) { // Re-evaluate expr outside of its context to see if it's untyped. // (An expr evaluated within, for example, an assignment context will get the type of the LHS.) exprStr := f.render(expr) tv, err := types.Eval(f.fset, f.pkg.typesPkg, expr.Pos(), exprStr) if err != nil { return "", false } if b, ok := tv.Type.(*types.Basic); ok { if dt, ok := basicTypeKinds[b.Kind()]; ok { return dt, true } } return "", false }
func TestIntuitiveMethodSet(t *testing.T) { const source = ` package P type A int func (A) f() func (*A) g() ` fset := token.NewFileSet() f, err := parser.ParseFile(fset, "hello.go", source, 0) if err != nil { t.Fatal(err) } var conf types.Config pkg, err := conf.Check("P", fset, []*ast.File{f}, nil) if err != nil { t.Fatal(err) } qual := types.RelativeTo(pkg) for _, test := range []struct { expr string // type expression want string // intuitive method set }{ {"A", "(A).f (*A).g"}, {"*A", "(*A).f (*A).g"}, {"error", "(error).Error"}, {"*error", ""}, {"struct{A}", "(struct{A}).f (*struct{A}).g"}, {"*struct{A}", "(*struct{A}).f (*struct{A}).g"}, } { tv, err := types.Eval(fset, pkg, 0, test.expr) if err != nil { t.Errorf("Eval(%s) failed: %v", test.expr, err) } var names []string for _, m := range typeutil.IntuitiveMethodSet(tv.Type, nil) { name := fmt.Sprintf("(%s).%s", types.TypeString(m.Recv(), qual), m.Obj().Name()) names = append(names, name) } got := strings.Join(names, " ") if got != test.want { t.Errorf("IntuitiveMethodSet(%s) = %q, want %q", test.expr, got, test.want) } } }
func (filter *ScenarioFilterBasedOnTags) evaluateExp(tagExpression string) (bool, error) { tre := regexp.MustCompile("true") fre := regexp.MustCompile("false") s := fre.ReplaceAllString(tre.ReplaceAllString(tagExpression, "1"), "0") val, err := types.Eval(token.NewFileSet(), nil, 0, s) if err != nil { return false, errors.New("Invalid Expression.\n" + err.Error()) } res, _ := constant.Uint64Val(val.Value) var final bool if res == 1 { final = true } else { final = false } return final, nil }
func cmp_any(obj1, obj2 interface{}, op string) (bool, error) { switch op { case "<", "<=", "==", ">=", ">": default: return false, fmt.Errorf("op should only be <, <=, ==, >= and >") } fmt.Println("cmp_any: ", obj1, obj2) exp := fmt.Sprintf("%v %s %v", obj1, op, obj2) fmt.Println("exp: ", exp) fset := token.NewFileSet() res, err := types.Eval(fset, nil, 0, exp) if err != nil { return false, err } if res.IsValue() == false || (res.Value.String() != "false" && res.Value.String() != "true") { return false, fmt.Errorf("result should only be true or false") } if res.Value.String() == "true" { return true, nil } return false, nil }
func TestExportedType(t *testing.T) { tests := []struct { typString string exp bool }{ {"int", true}, {"string", false}, // references the shadowed builtin "string" {"T", true}, {"t", false}, {"*T", true}, {"*t", false}, {"map[int]complex128", true}, } for _, test := range tests { src := `package foo; type T int; type t int; type string struct{}` fset := token.NewFileSet() file, err := parser.ParseFile(fset, "foo.go", src, 0) if err != nil { t.Fatalf("Parsing %q: %v", src, err) } // use the package name as package path config := &types.Config{} pkg, err := config.Check(file.Name.Name, fset, []*ast.File{file}, nil) if err != nil { t.Fatalf("Type checking %q: %v", src, err) } tv, err := types.Eval(fset, pkg, token.NoPos, test.typString) if err != nil { t.Errorf("types.Eval(%q): %v", test.typString, err) continue } if got := exportedType(tv.Type); got != test.exp { t.Errorf("exportedType(%v) = %t, want %t", tv.Type, got, test.exp) } } }
func doOneInput(input, filename string) bool { var conf loader.Config // Parsing. f, err := conf.ParseFile(filename, input) if err != nil { fmt.Println(err) return false } // Create single-file main package and import its dependencies. conf.CreateFromFiles("main", f) iprog, err := conf.Load() if err != nil { fmt.Println(err) return false } mainPkgInfo := iprog.Created[0].Pkg // SSA creation + building. prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions) prog.Build() mainpkg := prog.Package(mainPkgInfo) ptrmain := mainpkg // main package for the pointer analysis if mainpkg.Func("main") == nil { // No main function; assume it's a test. ptrmain = prog.CreateTestMainPackage(mainpkg) } // Find all calls to the built-in print(x). Analytically, // print is a no-op, but it's a convenient hook for testing // the PTS of an expression, so our tests use it. probes := make(map[*ssa.CallCommon]bool) for fn := range ssautil.AllFunctions(prog) { if fn.Pkg == mainpkg { for _, b := range fn.Blocks { for _, instr := range b.Instrs { if instr, ok := instr.(ssa.CallInstruction); ok { call := instr.Common() if b, ok := call.Value.(*ssa.Builtin); ok && b.Name() == "print" && len(call.Args) == 1 { probes[instr.Common()] = true } } } } } } ok := true lineMapping := make(map[string]string) // maps "file:line" to @line tag // Parse expectations in this input. var exps []*expectation re := regexp.MustCompile("// *@([a-z]*) *(.*)$") lines := strings.Split(input, "\n") for linenum, line := range lines { linenum++ // make it 1-based if matches := re.FindAllStringSubmatch(line, -1); matches != nil { match := matches[0] kind, rest := match[1], match[2] e := &expectation{kind: kind, filename: filename, linenum: linenum} if kind == "line" { if rest == "" { ok = false e.errorf("@%s expectation requires identifier", kind) } else { lineMapping[fmt.Sprintf("%s:%d", filename, linenum)] = rest } continue } if e.needsProbe() && !strings.Contains(line, "print(") { ok = false e.errorf("@%s expectation must follow call to print(x)", kind) continue } switch kind { case "pointsto": e.args = split(rest, "|") case "types": for _, typstr := range split(rest, "|") { var t types.Type = types.Typ[types.Invalid] // means "..." if typstr != "..." { tv, err := types.Eval(prog.Fset, mainpkg.Pkg, f.Pos(), typstr) if err != nil { ok = false // Don't print err since its location is bad. e.errorf("'%s' is not a valid type: %s", typstr, err) continue } t = tv.Type } e.types = append(e.types, t) } case "calls": e.args = split(rest, "->") // TODO(adonovan): eagerly reject the // expectation if fn doesn't denote // existing function, rather than fail // the expectation after analysis. if len(e.args) != 2 { ok = false e.errorf("@calls expectation wants 'caller -> callee' arguments") continue } case "warning": lit, err := strconv.Unquote(strings.TrimSpace(rest)) if err != nil { ok = false e.errorf("couldn't parse @warning operand: %s", err.Error()) continue } e.args = append(e.args, lit) default: ok = false e.errorf("unknown expectation kind: %s", e) continue } exps = append(exps, e) } } var log bytes.Buffer fmt.Fprintf(&log, "Input: %s\n", filename) // Run the analysis. config := &pointer.Config{ Reflection: true, BuildCallGraph: true, Mains: []*ssa.Package{ptrmain}, Log: &log, } for probe := range probes { v := probe.Args[0] if pointer.CanPoint(v.Type()) { config.AddQuery(v) } } // Print the log is there was an error or a panic. complete := false defer func() { if !complete || !ok { log.WriteTo(os.Stderr) } }() result, err := pointer.Analyze(config) if err != nil { panic(err) // internal error in pointer analysis } // Check the expectations. for _, e := range exps { var call *ssa.CallCommon var pts pointer.PointsToSet var tProbe types.Type if e.needsProbe() { if call, pts = findProbe(prog, probes, result.Queries, e); call == nil { ok = false e.errorf("unreachable print() statement has expectation %s", e) continue } tProbe = call.Args[0].Type() if !pointer.CanPoint(tProbe) { ok = false e.errorf("expectation on non-pointerlike operand: %s", tProbe) continue } } switch e.kind { case "pointsto": if !checkPointsToExpectation(e, pts, lineMapping, prog) { ok = false } case "types": if !checkTypesExpectation(e, pts, tProbe) { ok = false } case "calls": if !checkCallsExpectation(prog, e, result.CallGraph) { ok = false } case "warning": if !checkWarningExpectation(prog, e, result.Warnings) { ok = false } } } complete = true // ok = false // debugging: uncomment to always see log return ok }
func Test_jsonpath_types_eval(t *testing.T) { fset := token.NewFileSet() res, err := types.Eval(fset, nil, 0, "1 < 2") fmt.Println(err, res, res.Type, res.Value, res.IsValue()) }