作者:robfi
项目:errchec
// CheckPackages checks packages for errors.
// ignore is a map of package names to regular expressions. Identifiers from a package are
// checked against its regular expressions and if any of the expressions match the call
// is not checked.
// If blank is true then assignments to the blank identifier are also considered to be
// ignored errors.
func CheckPackages(pkgPaths []string, ignore map[string]*regexp.Regexp, blank bool) error {
var loadcfg = loader.Config{
SourceImports: true,
AllowErrors: false,
}
for _, p := range pkgPaths {
loadcfg.Import(p)
}
program, err := loadcfg.Load()
if err != nil {
return fmt.Errorf("could not type check: %s", err)
}
visitor := &checker{program, nil, ignore, blank, make(map[string][]string), []error{}}
for _, p := range pkgPaths {
if p == "unsafe" { // not a real package
continue
}
visitor.pkg = program.Imported[p]
for _, astFile := range visitor.pkg.Files {
ast.Walk(visitor, astFile)
}
}
if len(visitor.errors) > 0 {
return UncheckedErrors{visitor.errors}
}
return nil
}
作者:bryanx
项目:go-zh.tool
func TestTransitivelyErrorFreeFlag(t *testing.T) {
// Create an minimal custom build.Context
// that fakes the following packages:
//
// a --> b --> c! c has an error
// \ d and e are transitively error-free.
// e --> d
//
// Each package [a-e] consists of one file, x.go.
pkgs := map[string]string{
"a": `package a; import (_ "b"; _ "e")`,
"b": `package b; import _ "c"`,
"c": `package c; func f() { _ = int(false) }`, // type error within function body
"d": `package d;`,
"e": `package e; import _ "d"`,
}
conf := loader.Config{
AllowErrors: true,
SourceImports: true,
Build: fakeContext(pkgs),
}
conf.Import("a")
prog, err := conf.Load()
if err != nil {
t.Errorf("Load failed: %s", err)
}
if prog == nil {
t.Fatalf("Load returned nil *Program")
}
for pkg, info := range prog.AllPackages {
var wantErr, wantTEF bool
switch pkg.Path() {
case "a", "b":
case "c":
wantErr = true
case "d", "e":
wantTEF = true
default:
t.Errorf("unexpected package: %q", pkg.Path())
continue
}
if (info.Errors != nil) != wantErr {
if wantErr {
t.Errorf("Package %q.Error = nil, want error", pkg.Path())
} else {
t.Errorf("Package %q has unexpected Errors: %v",
pkg.Path(), info.Errors)
}
}
if info.TransitivelyErrorFree != wantTEF {
t.Errorf("Package %q.TransitivelyErrorFree=%t, want %t",
pkg.Path(), info.TransitivelyErrorFree, wantTEF)
}
}
}
作者:4hono
项目:obd
// Query runs a single oracle query.
//
// args specify the main package in (*loader.Config).FromArgs syntax.
// mode is the query mode ("callers", etc).
// ptalog is the (optional) pointer-analysis log file.
// buildContext is the go/build configuration for locating packages.
// reflection determines whether to model reflection soundly (currently slow).
//
// Clients that intend to perform multiple queries against the same
// analysis scope should use this pattern instead:
//
// conf := loader.Config{Build: buildContext, SourceImports: true}
// ... populate config, e.g. conf.FromArgs(args) ...
// iprog, err := conf.Load()
// if err != nil { ... }
// o, err := oracle.New(iprog, nil, false)
// if err != nil { ... }
// for ... {
// qpos, err := oracle.ParseQueryPos(imp, pos, needExact)
// if err != nil { ... }
//
// res, err := o.Query(mode, qpos)
// if err != nil { ... }
//
// // use res
// }
//
// TODO(adonovan): the ideal 'needsExact' parameter for ParseQueryPos
// depends on the query mode; how should we expose this?
//
func Query(args []string, mode, pos string, ptalog io.Writer, buildContext *build.Context, reflection bool) (*Result, error) {
if mode == "what" {
// Bypass package loading, type checking, SSA construction.
return what(pos, buildContext)
}
minfo := findMode(mode)
if minfo == nil {
return nil, fmt.Errorf("invalid mode type: %q", mode)
}
conf := loader.Config{Build: buildContext, SourceImports: true}
// Determine initial packages.
args, err := conf.FromArgs(args, true)
if err != nil {
return nil, err
}
if len(args) > 0 {
return nil, fmt.Errorf("surplus arguments: %q", args)
}
// For queries needing only a single typed package,
// reduce the analysis scope to that package.
if minfo.needs&(needSSA|needRetainTypeInfo) == 0 {
reduceScope(pos, &conf)
}
// TODO(adonovan): report type errors to the user via Serial
// types, not stderr?
// conf.TypeChecker.Error = func(err error) {
// E := err.(types.Error)
// fmt.Fprintf(os.Stderr, "%s: %s\n", E.Fset.Position(E.Pos), E.Msg)
// }
// Load/parse/type-check the program.
iprog, err := conf.Load()
if err != nil {
return nil, err
}
o, err := newOracle(iprog, ptalog, minfo.needs, reflection)
if err != nil {
return nil, err
}
qpos, err := ParseQueryPos(iprog, pos, minfo.needs&needExactPos != 0)
if err != nil && minfo.needs&(needPos|needExactPos) != 0 {
return nil, err
}
// SSA is built and we have the QueryPos.
// Release the other ASTs and type info to the GC.
iprog = nil
return o.query(minfo, qpos)
}
作者:bryanx
项目:go-zh.tool
// Test that both syntax (scan/parse) and type errors are both recorded
// (in PackageInfo.Errors) and reported (via Config.TypeChecker.Error).
func TestErrorReporting(t *testing.T) {
pkgs := map[string]string{
"a": `package a; import _ "b"; var x int = false`,
"b": `package b; 'syntax error!`,
}
conf := loader.Config{
AllowErrors: true,
SourceImports: true,
Build: fakeContext(pkgs),
}
var allErrors []error
conf.TypeChecker.Error = func(err error) {
allErrors = append(allErrors, err)
}
conf.Import("a")
prog, err := conf.Load()
if err != nil {
t.Errorf("Load failed: %s", err)
}
if prog == nil {
t.Fatalf("Load returned nil *Program")
}
hasError := func(errors []error, substr string) bool {
for _, err := range errors {
if strings.Contains(err.Error(), substr) {
return true
}
}
return false
}
// TODO(adonovan): test keys of ImportMap.
// Check errors recorded in each PackageInfo.
for pkg, info := range prog.AllPackages {
switch pkg.Path() {
case "a":
if !hasError(info.Errors, "cannot convert false") {
t.Errorf("a.Errors = %v, want bool conversion (type) error", info.Errors)
}
case "b":
if !hasError(info.Errors, "rune literal not terminated") {
t.Errorf("b.Errors = %v, want unterminated literal (syntax) error", info.Errors)
}
}
}
// Check errors reported via error handler.
if !hasError(allErrors, "cannot convert false") ||
!hasError(allErrors, "rune literal not terminated") {
t.Errorf("allErrors = %v, want both syntax and type errors", allErrors)
}
}
作者:Karthikv
项目:15640_project
func TestMultipleQueries(t *testing.T) {
// Loader
var buildContext = build.Default
buildContext.GOPATH = "testdata"
conf := loader.Config{Build: &buildContext, SourceImports: true}
filename := "testdata/src/main/multi.go"
conf.CreateFromFilenames("", filename)
iprog, err := conf.Load()
if err != nil {
t.Fatalf("Load failed: %s", err)
}
// Oracle
o, err := oracle.New(iprog, nil, true)
if err != nil {
t.Fatalf("oracle.New failed: %s", err)
}
// QueryPos
pos := filename + ":#54,#58"
qpos, err := oracle.ParseQueryPos(iprog, pos, true)
if err != nil {
t.Fatalf("oracle.ParseQueryPos(%q) failed: %s", pos, err)
}
// SSA is built and we have the QueryPos.
// Release the other ASTs and type info to the GC.
iprog = nil
// Run different query modes on same scope and selection.
out := new(bytes.Buffer)
for _, mode := range [...]string{"callers", "describe", "freevars"} {
res, err := o.Query(mode, qpos)
if err != nil {
t.Errorf("(*oracle.Oracle).Query(%q) failed: %s", pos, err)
}
WriteResult(out, res)
}
want := `multi.f is called from these 1 sites:
static function call from multi.main
function call (or conversion) of type ()
Free identifiers:
var x int
`
if got := out.String(); got != want {
t.Errorf("Query output differs; want <<%s>>, got <<%s>>\n", want, got)
}
}
作者:grmarti
项目:godoc2pum
// Oracle annotates `pkg` using go.tools/oracle interface implements detector.
// It uses `scopes` as analysis scope.
// If `scopes` is none of one of `scopes` is zero string, it uses unit tests as scope.
func Oracle(pkg *ast.Package, scopes ...string) error {
settings := build.Default
settings.BuildTags = []string{} // TODO
conf := loader.Config{Build: &settings, SourceImports: true}
withTests := false
if len(scopes) == 0 {
withTests = true
}
for _, scope := range scopes {
if scope == "" {
withTests = true
} else {
conf.Import(scope)
}
}
if withTests {
conf.ImportWithTests(pkg.Name)
} else {
conf.Import(pkg.Name)
}
iprog, err := conf.Load()
if err != nil {
return fmt.Errorf("oracle annotator: conf load error: %+v", err)
}
o, err := oracle.New(iprog, nil, false)
if err != nil {
return fmt.Errorf("oracle annotator: create error: %+v", err)
}
for _, class := range pkg.Classes {
qpos, err := oracle.ParseQueryPos(iprog, string(class.Pos), false)
if err != nil {
log.Printf("oracle annotator: parse query pos error: %+v, %+v", err, class.Pos)
continue
}
res, err := o.Query("implements", qpos)
if err != nil {
return fmt.Errorf("oracle annotator: query error: %+v, %v", err, class.Pos)
}
impls := res.Serial().Implements
for _, target := range impls.AssignableFromPtr {
addImplements(class, target)
}
for _, target := range impls.AssignableFrom {
addImplements(class, target)
}
}
return nil
}
作者:4hono
项目:obd
// reduceScope is called for one-shot queries that need only a single
// typed package. It attempts to guess the query package from pos and
// reduce the analysis scope (set of loaded packages) to just that one
// plus (the exported parts of) its dependencies. It leaves its
// arguments unchanged on failure.
//
// TODO(adonovan): this is a real mess... but it's fast.
//
func reduceScope(pos string, conf *loader.Config) {
fqpos, err := fastQueryPos(pos)
if err != nil {
return // bad query
}
// TODO(adonovan): fix: this gives the wrong results for files
// in non-importable packages such as tests and ad-hoc packages
// specified as a list of files (incl. the oracle's tests).
_, importPath, err := guessImportPath(fqpos.fset.File(fqpos.start).Name(), conf.Build)
if err != nil {
return // can't find GOPATH dir
}
if importPath == "" {
return
}
// Check that it's possible to load the queried package.
// (e.g. oracle tests contain different 'package' decls in same dir.)
// Keep consistent with logic in loader/util.go!
cfg2 := *conf.Build
cfg2.CgoEnabled = false
bp, err := cfg2.Import(importPath, "", 0)
if err != nil {
return // no files for package
}
// Check that the queried file appears in the package:
// it might be a '// +build ignore' from an ad-hoc main
// package, e.g. $GOROOT/src/pkg/net/http/triv.go.
if !pkgContainsFile(bp, fqpos.fset.File(fqpos.start).Name()) {
return // not found
}
conf.TypeCheckFuncBodies = func(p string) bool { return p == importPath }
// Ignore packages specified on command line.
conf.CreatePkgs = nil
conf.ImportPkgs = nil
// Instead load just the one containing the query position
// (and possibly its corresponding tests/production code).
// TODO(adonovan): set 'augment' based on which file list
// contains
_ = conf.ImportWithTests(importPath) // ignore error
}
作者:bryanx
项目:go-zh.tool
// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
var conf loader.Config
if err := conf.CreateFromFilenames("", "testdata/b_test.go"); err != nil {
t.Fatalf("ParseFile failed: %s", err)
}
iprog, err := conf.Load()
if err != nil {
t.Fatalf("CreatePackages failed: %s", err)
}
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
mainPkg := prog.Package(iprog.Created[0].Pkg)
if mainPkg.Func("main") != nil {
t.Fatalf("unexpected main function")
}
if prog.CreateTestMainPackage(mainPkg) != nil {
t.Fatalf("CreateTestMainPackage returned non-nil")
}
}
作者:bryanx
项目:go-zh.tool
func TestStdlib(t *testing.T) {
defer func(saved func(format string, args ...interface{})) {
logf = saved
}(logf)
logf = t.Errorf
ctxt := build.Default // copy
// Enumerate $GOROOT packages.
saved := ctxt.GOPATH
ctxt.GOPATH = "" // disable GOPATH during AllPackages
pkgs := buildutil.AllPackages(&ctxt)
ctxt.GOPATH = saved
// Throw in a number of go.tools packages too.
pkgs = append(pkgs,
"code.google.com/p/go.tools/cmd/godoc",
"code.google.com/p/go.tools/refactor/lexical")
// Load, parse and type-check the program.
conf := loader.Config{
Build: &ctxt,
SourceImports: true,
}
for _, path := range pkgs {
if err := conf.ImportWithTests(path); err != nil {
t.Error(err)
}
}
iprog, err := conf.Load()
if err != nil {
t.Fatalf("Load failed: %v", err)
}
// This test ensures that Structure doesn't panic and that
// its internal sanity-checks against go/types don't fail.
for pkg, info := range iprog.AllPackages {
_ = Structure(iprog.Fset, pkg, &info.Info, info.Files)
}
}
作者:bryanx
项目:go-zh.tool
// loadProgram loads the specified set of packages (plus their tests)
// and all their dependencies, from source, through the specified build
// context. Only packages in pkgs will have their functions bodies typechecked.
func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
conf := loader.Config{
Build: ctxt,
SourceImports: true,
ParserMode: parser.ParseComments,
// TODO(adonovan): enable this. Requires making a lot of code more robust!
AllowErrors: false,
}
// Optimization: don't type-check the bodies of functions in our
// dependencies, since we only need exported package members.
conf.TypeCheckFuncBodies = func(p string) bool {
return pkgs[p] || pkgs[strings.TrimSuffix(p, "_test")]
}
if Verbose {
var list []string
for pkg := range pkgs {
list = append(list, pkg)
}
sort.Strings(list)
for _, pkg := range list {
fmt.Fprintf(os.Stderr, "Loading package: %s\n", pkg)
}
}
for pkg := range pkgs {
if err := conf.ImportWithTests(pkg); err != nil {
return nil, err
}
}
return conf.Load()
}
作者:4hono
项目:obd
func TestSwitches(t *testing.T) {
conf := loader.Config{ParserMode: parser.ParseComments}
f, err := conf.ParseFile("testdata/switches.go", nil)
if err != nil {
t.Error(err)
return
}
conf.CreateFromFiles("main", f)
iprog, err := conf.Load()
if err != nil {
t.Error(err)
return
}
prog := ssa.Create(iprog, 0)
mainPkg := prog.Package(iprog.Created[0].Pkg)
mainPkg.Build()
for _, mem := range mainPkg.Members {
if fn, ok := mem.(*ssa.Function); ok {
if fn.Synthetic != "" {
continue // e.g. init()
}
// Each (multi-line) "switch" comment within
// this function must match the printed form
// of a ConstSwitch.
var wantSwitches []string
for _, c := range f.Comments {
if fn.Syntax().Pos() <= c.Pos() && c.Pos() < fn.Syntax().End() {
text := strings.TrimSpace(c.Text())
if strings.HasPrefix(text, "switch ") {
wantSwitches = append(wantSwitches, text)
}
}
}
switches := ssautil.Switches(fn)
if len(switches) != len(wantSwitches) {
t.Errorf("in %s, found %d switches, want %d", fn, len(switches), len(wantSwitches))
}
for i, sw := range switches {
got := sw.String()
if i >= len(wantSwitches) {
continue
}
want := wantSwitches[i]
if got != want {
t.Errorf("in %s, found switch %d: got <<%s>>, want <<%s>>", fn, i, got, want)
}
}
}
}
}
作者:4hono
项目:obd
func create(t *testing.T, content string) []*ssa.Package {
var conf loader.Config
f, err := conf.ParseFile("foo_test.go", content)
if err != nil {
t.Fatal(err)
}
conf.CreateFromFiles("foo", f)
iprog, err := conf.Load()
if err != nil {
t.Fatal(err)
}
// We needn't call Build.
return ssa.Create(iprog, ssa.SanityCheckFunctions).AllPackages()
}
作者:pombredann
项目:tardisg
func doTestable(args []string) error {
conf := loader.Config{
Build: &build.Default,
SourceImports: true,
}
// TODO(adonovan): make go/types choose its default Sizes from
// build.Default or a specified *build.Context.
var wordSize int64 = 8
switch conf.Build.GOARCH {
case "386", "arm":
wordSize = 4
}
wordSize = 4 // TARDIS Go addition to force default int size to 32 bits
//conf.Build.GOARCH = "tardisgo" // TARDIS Go addition to ensure no architecure-specific code will compile
//conf.Build.GOOS = "tardisgo" // TARDIS Go addition to ensure no OS-specific code will compile
conf.TypeChecker.Sizes = &types.StdSizes{
MaxAlign: 8,
WordSize: wordSize,
}
var mode ssa.BuilderMode
for _, c := range *buildFlag {
switch c {
case 'D':
mode |= ssa.GlobalDebug
case 'P':
mode |= ssa.LogPackages | ssa.BuildSerially
case 'F':
mode |= ssa.LogFunctions | ssa.BuildSerially
case 'S':
mode |= ssa.LogSource | ssa.BuildSerially
case 'C':
mode |= ssa.SanityCheckFunctions
case 'N':
mode |= ssa.NaiveForm
case 'G':
conf.SourceImports = false
case 'L':
mode |= ssa.BuildSerially
default:
log.Fatalf("Unknown -build option: '%c'.", c)
}
}
var interpMode interp.Mode
for _, c := range *interpFlag {
switch c {
case 'T':
interpMode |= interp.EnableTracing
case 'R':
interpMode |= interp.DisableRecover
default:
log.Fatalf("Unknown -interp option: '%c'.", c)
}
}
if len(args) == 0 {
//fmt.Fprint(os.Stderr, usage)
return fmt.Errorf("%v", usage)
}
// Profiling support.
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
return err
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
// TARDIS Go TEST
// Really need to find a way to replace entire packages, this experiment did not work...
/*
conf.Fset = token.NewFileSet()
f, err := parser.ParseFile(conf.Fset, conf.Build.GOPATH+"/src/github.com/tardisgo/tardisgo/golibruntime/runtime/runtime.go", nil, 0)
if err != nil {
fmt.Println(err)
return err
}
conf.CreateFromFiles("", f)
fmt.Printf("DEBUG %s %s\n", f.Name.Name, "") //, f.Name.Obj.Name)
*/
// end TARDIS Go TEST
// Use the initial packages from the command line.
args, err := conf.FromArgs(args, *testFlag)
if err != nil {
return err
}
// The interpreter needs the runtime package.
if *runFlag {
conf.Import("runtime")
conf.Import("github.com/tardisgo/tardisgo/golibruntime/runtime") // This required for TARDIS go to run runtime
}
//.........这里部分代码省略.........
作者:samuelyao31
项目:myg
// Run runs program analysis and computes the resulting markup,
// populating *result in a thread-safe manner, first with type
// information then later with pointer analysis information if
// enabled by the pta flag.
//
func Run(pta bool, result *Result) {
conf := loader.Config{
SourceImports: true,
AllowTypeErrors: true,
}
errors := make(map[token.Pos][]string)
conf.TypeChecker.Error = func(e error) {
err := e.(types.Error)
errors[err.Pos] = append(errors[err.Pos], err.Msg)
}
var roots, args []string // roots[i] ends with os.PathSeparator
// Enumerate packages in $GOROOT.
root := filepath.Join(runtime.GOROOT(), "src", "pkg") + string(os.PathSeparator)
roots = append(roots, root)
args = allPackages(root)
log.Printf("GOROOT=%s: %s\n", root, args)
// Enumerate packages in $GOPATH.
for i, dir := range filepath.SplitList(build.Default.GOPATH) {
root := filepath.Join(dir, "src") + string(os.PathSeparator)
roots = append(roots, root)
pkgs := allPackages(root)
log.Printf("GOPATH[%d]=%s: %s\n", i, root, pkgs)
args = append(args, pkgs...)
}
// Uncomment to make startup quicker during debugging.
//args = []string{"code.google.com/p/go.tools/cmd/godoc"}
//args = []string{"fmt"}
if _, err := conf.FromArgs(args, true); err != nil {
log.Print(err) // import error
return
}
log.Print("Loading and type-checking packages...")
iprog, err := conf.Load()
if iprog != nil {
log.Printf("Loaded %d packages.", len(iprog.AllPackages))
}
if err != nil {
// TODO(adonovan): loader: don't give up just because
// of one parse error.
log.Print(err) // parse error in some package
return
}
// Create SSA-form program representation.
// Only the transitively error-free packages are used.
prog := ssa.Create(iprog, ssa.GlobalDebug)
// Compute the set of main packages, including testmain.
allPackages := prog.AllPackages()
var mainPkgs []*ssa.Package
if testmain := prog.CreateTestMainPackage(allPackages...); testmain != nil {
mainPkgs = append(mainPkgs, testmain)
}
for _, pkg := range allPackages {
if pkg.Object.Name() == "main" && pkg.Func("main") != nil {
mainPkgs = append(mainPkgs, pkg)
}
}
log.Print("Main packages: ", mainPkgs)
// Build SSA code for bodies of all functions in the whole program.
log.Print("Building SSA...")
prog.BuildAll()
log.Print("SSA building complete")
a := analysis{
result: result,
prog: prog,
pcgs: make(map[*ssa.Package]*packageCallGraph),
}
// Build a mapping from openable filenames to godoc file URLs,
// i.e. "/src/pkg/" plus path relative to GOROOT/src/pkg or GOPATH[i]/src.
a.path2url = make(map[string]string)
for _, info := range iprog.AllPackages {
nextfile:
for _, f := range info.Files {
abs := iprog.Fset.File(f.Pos()).Name()
// Find the root to which this file belongs.
for _, root := range roots {
rel := strings.TrimPrefix(abs, root)
if len(rel) < len(abs) {
a.path2url[abs] = "/src/pkg/" + filepath.ToSlash(rel)
continue nextfile
}
}
log.Printf("Can't locate file %s (package %q) beneath any root",
//.........这里部分代码省略.........
作者:juanman
项目:dot-emac
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: errorpaths scope pkg-pattern\n")
fmt.Fprint(os.Stderr, loader.FromArgsUsage)
}
flag.Parse()
args := flag.Args()
if len(args) != 2 {
flag.Usage()
}
conf := loader.Config{
SourceImports: true,
}
_, err := conf.FromArgs(args[0:1])
if err != nil {
log.Fatalf("cannot initialise loader: %v", err)
}
pkgPat, err := regexp.Compile("^" + args[1] + "$")
if err != nil {
log.Fatalf("cann compile regexp %q: %s", args[1], err)
}
lprog, err := conf.Load()
if err != nil {
log.Fatalf("cannot load program: %v", err)
}
or, err := oracle.New(lprog, nil, false)
if err != nil {
log.Fatalf("cannot make oracle: %v", err)
}
ssaProg := ssa.Create(lprog, ssa.SanityCheckFunctions)
ctxt := &context{
lprog: lprog,
ssaProg: ssaProg,
oracle: or,
infos: make(map[*ssa.Function]*errorInfo),
locs: make(map[*ssa.Function]errorLocations),
}
var foundPkgs []*types.Package
log.Printf("searching %d packages", len(lprog.AllPackages))
for pkg, _ := range lprog.AllPackages {
if pkgPat.MatchString(pkg.Path()) {
foundPkgs = append(foundPkgs, pkg)
break
}
}
if len(foundPkgs) == 0 {
log.Fatalf("failed to find any matching packages")
}
for _, pkg := range foundPkgs {
log.Printf("package %s", pkg.Name())
ssaPkg := ssaProg.Package(pkg)
ssaPkg.Build()
for name, m := range ssaPkg.Members {
log.Printf("name %s", name)
if f, ok := m.(*ssa.Function); ok && returnsError(f) {
fmt.Printf("%s\n", f)
locs := ctxt.errorLocations(f)
ctxt.dumpErrorLocs(locs, os.Stdout, "\t")
}
}
}
}
作者:4hono
项目:obd
func doMain() error {
flag.Parse()
args := flag.Args()
if *helpFlag {
fmt.Fprint(os.Stderr, eg.Help)
os.Exit(2)
}
if *templateFlag == "" {
return fmt.Errorf("no -t template.go file specified")
}
conf := loader.Config{
Fset: token.NewFileSet(),
ParserMode: parser.ParseComments,
SourceImports: true,
}
// The first Created package is the template.
if err := conf.CreateFromFilenames("template", *templateFlag); err != nil {
return err // e.g. "foo.go:1: syntax error"
}
if len(args) == 0 {
fmt.Fprint(os.Stderr, usage)
os.Exit(1)
}
if _, err := conf.FromArgs(args, true); err != nil {
return err
}
// Load, parse and type-check the whole program.
iprog, err := conf.Load()
if err != nil {
return err
}
// Analyze the template.
template := iprog.Created[0]
xform, err := eg.NewTransformer(iprog.Fset, template, *verboseFlag)
if err != nil {
return err
}
// Apply it to the input packages.
var pkgs []*loader.PackageInfo
if *transitiveFlag {
for _, info := range iprog.AllPackages {
pkgs = append(pkgs, info)
}
} else {
pkgs = iprog.InitialPackages()
}
var hadErrors bool
for _, pkg := range pkgs {
if pkg == template {
continue
}
for _, file := range pkg.Files {
n := xform.Transform(&pkg.Info, pkg.Pkg, file)
if n == 0 {
continue
}
filename := iprog.Fset.File(file.Pos()).Name()
fmt.Fprintf(os.Stderr, "=== %s (%d matches):\n", filename, n)
if *writeFlag {
if err := eg.WriteAST(iprog.Fset, filename, file); err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
hadErrors = true
}
} else {
printer.Fprint(os.Stdout, iprog.Fset, file)
}
}
}
if hadErrors {
os.Exit(1)
}
return nil
}
作者:4hono
项目:obd
func Test(t *testing.T) {
switch runtime.GOOS {
case "windows":
t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
}
conf := loader.Config{
Fset: token.NewFileSet(),
ParserMode: parser.ParseComments,
SourceImports: true,
}
// Each entry is a single-file package.
// (Multi-file packages aren't interesting for this test.)
// Order matters: each non-template package is processed using
// the preceding template package.
for _, filename := range []string{
"testdata/A.template",
"testdata/A1.go",
"testdata/A2.go",
"testdata/B.template",
"testdata/B1.go",
"testdata/C.template",
"testdata/C1.go",
"testdata/D.template",
"testdata/D1.go",
"testdata/E.template",
"testdata/E1.go",
"testdata/bad_type.template",
"testdata/no_before.template",
"testdata/no_after_return.template",
"testdata/type_mismatch.template",
"testdata/expr_type_mismatch.template",
} {
pkgname := strings.TrimSuffix(filepath.Base(filename), ".go")
if err := conf.CreateFromFilenames(pkgname, filename); err != nil {
t.Fatal(err)
}
}
iprog, err := conf.Load()
if err != nil {
t.Fatal(err)
}
var xform *eg.Transformer
for _, info := range iprog.Created {
file := info.Files[0]
filename := iprog.Fset.File(file.Pos()).Name() // foo.go
if strings.HasSuffix(filename, "template") {
// a new template
shouldFail, _ := info.Pkg.Scope().Lookup("shouldFail").(*types.Const)
xform, err = eg.NewTransformer(iprog.Fset, info, *verboseFlag)
if err != nil {
if shouldFail == nil {
t.Errorf("NewTransformer(%s): %s", filename, err)
} else if want := exact.StringVal(shouldFail.Val()); !strings.Contains(err.Error(), want) {
t.Errorf("NewTransformer(%s): got error %q, want error %q", filename, err, want)
}
} else if shouldFail != nil {
t.Errorf("NewTransformer(%s) succeeded unexpectedly; want error %q",
filename, shouldFail.Val())
}
continue
}
if xform == nil {
t.Errorf("%s: no previous template", filename)
continue
}
// apply previous template to this package
n := xform.Transform(&info.Info, info.Pkg, file)
if n == 0 {
t.Errorf("%s: no matches", filename)
continue
}
got := filename + "t" // foo.got
golden := filename + "lden" // foo.golden
// Write actual output to foo.got.
if err := eg.WriteAST(iprog.Fset, got, file); err != nil {
t.Error(err)
}
defer os.Remove(got)
// Compare foo.got with foo.golden.
var cmd *exec.Cmd
switch runtime.GOOS {
case "plan9":
cmd = exec.Command("/bin/diff", "-c", golden, got)
default:
cmd = exec.Command("/usr/bin/diff", "-u", golden, got)
}
//.........这里部分代码省略.........
作者:hackrol
项目:daily-progra
func TestObjValueLookup(t *testing.T) {
conf := loader.Config{ParserMode: parser.ParseComments}
f, err := conf.ParseFile("testdata/objlookup.go", nil)
if err != nil {
t.Error(err)
return
}
conf.CreateFromFiles("main", f)
// Maps each var Ident (represented "name:linenum") to the
// kind of ssa.Value we expect (represented "Constant", "&Alloc").
expectations := make(map[string]string)
// Find all annotations of form x::BinOp, &y::Alloc, etc.
re := regexp.MustCompile(`(\b|&)?(\w*)::(\w*)\b`)
for _, c := range f.Comments {
text := c.Text()
pos := conf.Fset.Position(c.Pos())
for _, m := range re.FindAllStringSubmatch(text, -1) {
key := fmt.Sprintf("%s:%d", m[2], pos.Line)
value := m[1] + m[3]
expectations[key] = value
}
}
iprog, err := conf.Load()
if err != nil {
t.Error(err)
return
}
prog := ssa.Create(iprog, 0 /*|ssa.LogFunctions*/)
mainInfo := iprog.Created[0]
mainPkg := prog.Package(mainInfo.Pkg)
mainPkg.SetDebugMode(true)
mainPkg.Build()
var varIds []*ast.Ident
var varObjs []*types.Var
for id, obj := range mainInfo.Defs {
// Check invariants for func and const objects.
switch obj := obj.(type) {
case *types.Func:
checkFuncValue(t, prog, obj)
case *types.Const:
checkConstValue(t, prog, obj)
case *types.Var:
if id.Name == "_" {
continue
}
varIds = append(varIds, id)
varObjs = append(varObjs, obj)
}
}
for id, obj := range mainInfo.Uses {
if obj, ok := obj.(*types.Var); ok {
varIds = append(varIds, id)
varObjs = append(varObjs, obj)
}
}
// Check invariants for var objects.
// The result varies based on the specific Ident.
for i, id := range varIds {
obj := varObjs[i]
ref, _ := astutil.PathEnclosingInterval(f, id.Pos(), id.Pos())
pos := prog.Fset.Position(id.Pos())
exp := expectations[fmt.Sprintf("%s:%d", id.Name, pos.Line)]
if exp == "" {
t.Errorf("%s: no expectation for var ident %s ", pos, id.Name)
continue
}
wantAddr := false
if exp[0] == '&' {
wantAddr = true
exp = exp[1:]
}
checkVarValue(t, prog, mainPkg, ref, obj, exp, wantAddr)
}
}
作者:Karthikv
项目:15640_project
func TestStdlib(t *testing.T) {
runtime.GC()
t0 := time.Now()
var memstats runtime.MemStats
runtime.ReadMemStats(&memstats)
alloc := memstats.Alloc
// Load, parse and type-check the program.
var conf loader.Config
for _, path := range allPackages() {
if err := conf.ImportWithTests(path); err != nil {
t.Error(err)
}
}
prog, err := conf.Load()
if err != nil {
t.Fatalf("Load failed: %v", err)
}
t1 := time.Now()
runtime.GC()
runtime.ReadMemStats(&memstats)
numPkgs := len(prog.AllPackages)
if want := 205; numPkgs < want {
t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
}
// Dump package members.
if false {
for pkg := range prog.AllPackages {
fmt.Printf("Package %s:\n", pkg.Path())
scope := pkg.Scope()
for _, name := range scope.Names() {
if ast.IsExported(name) {
fmt.Printf("\t%s\n", types.ObjectString(pkg, scope.Lookup(name)))
}
}
fmt.Println()
}
}
// Check that Test functions for io/ioutil, regexp and
// compress/bzip2 are all simultaneously present.
// (The apparent cycle formed when augmenting all three of
// these packages by their tests was the original motivation
// for reporting b/7114.)
//
// compress/bzip2.TestBitReader in bzip2_test.go imports io/ioutil
// io/ioutil.TestTempFile in tempfile_test.go imports regexp
// regexp.TestRE2Search in exec_test.go imports compress/bzip2
for _, test := range []struct{ pkg, fn string }{
{"io/ioutil", "TestTempFile"},
{"regexp", "TestRE2Search"},
{"compress/bzip2", "TestBitReader"},
} {
info := prog.Imported[test.pkg]
if info == nil {
t.Errorf("failed to load package %q", test.pkg)
continue
}
obj, _ := info.Pkg.Scope().Lookup(test.fn).(*types.Func)
if obj == nil {
t.Errorf("package %q has no func %q", test.pkg, test.fn)
continue
}
}
// Dump some statistics.
// determine line count
var lineCount int
prog.Fset.Iterate(func(f *token.File) bool {
lineCount += f.LineCount()
return true
})
t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0))
t.Log("#Source lines: ", lineCount)
t.Log("Load/parse/typecheck: ", t1.Sub(t0))
t.Log("#MB: ", int64(memstats.Alloc-alloc)/1000000)
}
作者:4hono
项目:obd
func doOneInput(input, filename string) bool {
conf := loader.Config{SourceImports: true}
// 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 := ssa.Create(iprog, ssa.SanityCheckFunctions)
prog.BuildAll()
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 {
if b, ok := instr.Common().Value.(*ssa.Builtin); ok && b.Name() == "print" {
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 != "..." {
texpr, err := parser.ParseExpr(typstr)
if err != nil {
ok = false
// Don't print err since its location is bad.
e.errorf("'%s' is not a valid type", typstr)
continue
}
mainFileScope := mainpkg.Object.Scope().Child(0)
t, _, err = types.EvalNode(prog.Fset, texpr, mainpkg.Object, mainFileScope)
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)
//.........这里部分代码省略.........