Example #1
0
func (v *ShortError) VisitExpr(scope *ast.Scope, expr ast.Expr) ScopeVisitor {
	if expr, ok := expr.(*ast.CallExpr); ok {
		if fun, ok := expr.Fun.(*ast.Ident); ok && fun.Name == MustKeyword {
			if len(expr.Args) != 1 {
				pos := v.file.Fset.Position(fun.Pos())
				fmt.Printf("%s:%d:%d: 'must' builtin must be called with exactly one argument\n", pos.Filename, pos.Line, pos.Column)
				return nil
			}
			tmpVar, tmpErr := v.tempVar("tmp_", scope), v.tempVar("err_", scope)
			mustexpr := v.file.Get(expr.Args[0])
			if v.block == nil {
				// if in top level decleration
				v.addToInit("if " + tmpErr + " != nil {panic(" + tmpErr + ")};")
				*v.patches = append(*v.patches,
					patch.Replace(expr, tmpVar),
					patch.Insert(afterImports(v.file.File), ";var "+tmpVar+", "+tmpErr+" = "+mustexpr))
			} else {
				*v.patches = append(*v.patches, patch.Insert(v.stmt.Pos(),
					fmt.Sprint("var ", tmpVar, ", ", tmpErr, " = ", mustexpr, "; ",
						"if ", tmpErr, " != nil {panic(", tmpErr, ")};")))
				*v.patches = append(*v.patches, patch.Replace(expr, tmpVar))
			}
		}
	}
	return v
}
Example #2
0
func (v *ShortError) VisitStmt(scope *ast.Scope, stmt ast.Stmt) ScopeVisitor {
	v.stmt = stmt
	switch stmt := stmt.(type) {
	case *ast.BlockStmt:
		return &ShortError{v.file, v.patches, v.stmt, stmt, 0, new([]byte)}
	case *ast.ExprStmt:
		if call := calltomust(stmt.X); call != nil {
			// TODO(elazarl): depends on number of variables it returns, currently we assume one
			pos := v.file.Fset.Position(stmt.Pos())
			fmt.Printf("%s:%d:%d: 'must' builtin must be assigned into variable\n",
				pos.Filename, pos.Line, pos.Column)
		}
	case *ast.AssignStmt:
		if len(stmt.Rhs) != 1 {
			return v
		}
		if rhs, ok := stmt.Rhs[0].(*ast.CallExpr); ok {
			if fun, ok := rhs.Fun.(*ast.Ident); ok && fun.Name == MustKeyword {
				if stmt.Tok == token.DEFINE {
					tmpVar := v.tempVar("assignerr_", scope)
					*v.patches = append(*v.patches,
						patch.Insert(stmt.TokPos, ", "+tmpVar+" "),
						patch.Replace(fun, ""),
						patch.Insert(stmt.End(),
							"; if "+tmpVar+" != nil "+
								"{ panic("+tmpVar+") };"),
					)
					for _, arg := range rhs.Args {
						v.VisitExpr(scope, arg)
					}
					return nil
				} else if stmt.Tok == token.ASSIGN {
					vars := []string{}
					for i := 0; i < len(stmt.Lhs); i++ {
						vars = append(vars, v.tempVar(fmt.Sprint("assgn", i, "_"), scope))
					}
					assgnerr := v.tempVar("assgnErr_", scope)

					*v.patches = append(*v.patches,
						patch.Insert(stmt.Pos(),
							strings.Join(append(vars, assgnerr), ", ")+":="),
						patch.InsertNode(stmt.Pos(), rhs.Args[0]),
						patch.Insert(stmt.Pos(),
							"; if "+assgnerr+" != nil "+
								"{ panic("+assgnerr+") };"),
						patch.Replace(rhs, strings.Join(vars, ", ")),
					)
					v.VisitExpr(scope, rhs.Args[0])
					return nil
				}
			}
		}
	}
	return v
}
Example #3
0
func (i *Instrumentable) instrumentPatchable(outdir, relpath string, pkg *patch.PatchablePkg, f func(file *patch.PatchableFile) patch.Patches) error {
	path := ""
	if build.IsLocalImport(relpath) {
		path = filepath.Join("locals", relpath)
		path = strings.Replace(path, "..", "__", -1)
	} else if relpath != "" {
		path = filepath.Join("gopath", i.pkg.ImportPath)
	}
	if err := os.MkdirAll(filepath.Join(outdir, path), 0755); err != nil {
		return err
	}
	for filename, file := range pkg.Files {
		if outfile, err := os.Create(filepath.Join(outdir, path, filepath.Base(filename))); err != nil {
			return err
		} else {
			patches := f(file)
			// TODO(elazar): check the relative path from current location (aka relpath, path), to the import path
			// (aka v)
			for _, imp := range file.File.Imports {
				switch v := imp.Path.Value[1 : len(imp.Path.Value)-1]; {
				case v == i.pkg.ImportPath:
					patches = appendNoContradict(patches, patch.Replace(imp.Path, `"."`))
				case !i.relevantImport(v):
					continue
				case build.IsLocalImport(v):
					rel, err := filepath.Rel(path, filepath.Join("locals", v))
					if err != nil {
						return err
					}
					patches = appendNoContradict(patches, patch.Replace(imp.Path, `"./`+rel+`"`))
				default:
					if v == i.name {
						v = ""
					} else {
						v = filepath.Join("gopath", v)
					}
					rel, err := filepath.Rel(path, v)
					if err != nil {
						return err
					}
					patches = appendNoContradict(patches, patch.Replace(imp.Path, `"./`+rel+`"`))
				}
			}
			file.FprintPatched(outfile, file.File, patches)
			if err := outfile.Close(); err != nil {
				return err
			}
		}
	}
	return nil
}
Example #4
0
func (v *ShortError) VisitDecl(scope *ast.Scope, decl ast.Decl) ScopeVisitor {
	if decl, ok := decl.(*ast.GenDecl); ok {
		for _, spec := range decl.Specs {
			// We'll act only in cases like top level `var a, b, c = must(expr)`
			if spec, ok := spec.(*ast.ValueSpec); ok && len(spec.Values) == 1 {
				if fun, ok := spec.Values[0].(*ast.CallExpr); ok {
					if name, ok := fun.Fun.(*ast.Ident); !ok || name.Name != MustKeyword {
						return v
					}
					if len(fun.Args) != 1 {
						pos := v.file.Fset.Position(fun.Pos())
						fmt.Printf("%s:%d:%d: 'must' builtin must be called with exactly one argument\n", pos.Filename, pos.Line, pos.Column)
						return nil
					}
					tmpErr := v.tempVar("tlderr_", scope)
					*v.patches = append(*v.patches,
						patch.Insert(spec.Names[len(spec.Names)-1].End(), ", "+tmpErr),
						patch.Replace(fun, v.file.Get(fun.Args[0])))
					v.addToInit("if " + tmpErr + " != nil { panic(" + tmpErr + ") }")
				}
			}
		}
		return nil
	}
	return v
}
Example #5
0
func TestGuessSubpackage(t *testing.T) {
	fs := dir(
		"test",
		dir("sub1", file("sub1.go", "package sub1")),
		dir("sub2", file("sub2.go", "package sub2")),
		dir("sub3", file("sub3.go", `package sub3;import "../sub1"`)),
		file("base.go", `package test1;import "./sub1"`), file("a_test.go", `package test1;import "./sub2"`),
	)
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("test"), t) }()
	func() {
		pkg, err := ImportDir("", "test/sub3")
		OrFail(err, t)
		if fmt.Sprint(pkg.Files()) != "[test/sub3/sub3.go]" {
			t.Fatal("Expected [test/sub3/sub3.go] got", pkg.Files())
		}
		OrFail(os.Mkdir("temp", 0755), t)
		defer func() { OrFail(os.RemoveAll("temp"), t) }()
		_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
			return patch.Patches{patch.Replace(pf.File, "koko")}
		})
		OrFail(err, t)
		dir("temp",
			dir("locals", dir("__", dir("sub1", file("sub1.go", "koko")))),
			file("sub3.go", "koko"),
		).AssertEqual("temp", t)
	}()
}
Example #6
0
func TestGopath(t *testing.T) {
	fs := dir(
		"gopath/src/mypkg",
		file("a.go", "package mypkg"), file("a_test.go", "package mypkg"),
	)
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("gopath"), t) }()
	gopath, err := filepath.Abs("gopath")
	OrFail(err, t)
	prevgopath := build.Default.GOPATH
	defer func() { build.Default.GOPATH = prevgopath }()
	build.Default.GOPATH = gopath
	pkg, err := Import("mypkg", "mypkg")
	OrFail(err, t)
	OrFail(os.Mkdir("temp", 0755), t)
	defer func() { OrFail(os.RemoveAll("temp"), t) }()
	_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
		return patch.Patches{patch.Replace(pf.File, "koko")}
	})
	OrFail(err, t)
	dir("temp",
		file("a.go", "koko"),
		file("a_test.go", "koko"),
	).AssertEqual("temp", t)
}
Example #7
0
func TestGuessSubpkgGopath(t *testing.T) {
	fs := dir(
		"gopath/src/mypkg",
		dir("sub1", file("sub1.go", "package sub1")),
		dir("sub2", file("sub2.go", "package sub2")),
		dir("sub3", dir("subsub3", file("subsub3.go", `package subsub3;import "mypkg/sub1"`))),
		file("base.go", `package test1;import "mypkg/sub1"`), file("a_test.go", `package test1;import "mypkg/sub2"`),
	)
	// TODO(elazar): find a way to use build.Context
	gopath, err := filepath.Abs("gopath")
	OrFail(err, t)
	prevgopath := build.Default.GOPATH
	defer func() { build.Default.GOPATH = prevgopath }()
	build.Default.GOPATH = gopath
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("gopath"), t) }()
	func() {
		pkg, err := Import("", "mypkg/sub3/subsub3")
		OrFail(err, t)
		OrFail(os.Mkdir("temp", 0755), t)
		defer func() { OrFail(os.RemoveAll("temp"), t) }()
		_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
			return patch.Patches{patch.Replace(pf.File, "koko")}
		})
		OrFail(err, t)
		dir("temp",
			file("subsub3.go", "koko"),
		).AssertEqual("temp", t)
	}()
}
Example #8
0
func (p *patchUnused) UnusedImport(imp *ast.ImportSpec) {
	if imp.Name != nil {
		p.patches = append(p.patches, patch.Replace(imp.Name, "_"))
	} else {
		p.patches = append(p.patches, patch.Insert(imp.Pos(), "_ "))
	}
}
Example #9
0
func TestInline(t *testing.T) {
	OrFail(dir("temp", file("a.go", "package main;func main() {println(`bobo`)}")).Build("."), t)
	defer os.RemoveAll("temp")
	pkg, err := ImportDir("", "temp")
	OrFail(err, t)
	OrFail(pkg.InstrumentInline(func(pf *patch.PatchableFile) patch.Patches {
		return patch.Patches{patch.Replace(pf.File, "koko")}
	}), t)
	dir("temp", file("a.go", "koko")).AssertEqual("temp", t)
}
Example #10
0
func TestGuessStdlibPkg(t *testing.T) {
	pkg, err := Import("", "io/ioutil")
	OrFail(err, t)
	OrFail(os.Mkdir("temp", 0755), t)
	defer func() { OrFail(os.RemoveAll("temp"), t) }()
	_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
		return patch.Patches{patch.Replace(pf.All(), "koko")}
	})
	OrFail(err, t)
	dir("temp",
		dir("goroot", dir("src", dir("pkg", dir("io", dir("ioutil", file("ioutil.go", "koko")))))),
	).AssertContains("temp", t)
}
Example #11
0
func TestDontTakeStdLibByDefault(t *testing.T) {
	fs := dir(
		"test",
		file("main.go", `package main;import "fmt";func main() {fmt.Println()}`),
	)
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("test"), t) }()
	pkg, err := ImportDir("", "test")
	OrFail(err, t)
	OrFail(os.Mkdir("temp", 0755), t)
	defer func() { OrFail(os.RemoveAll("temp"), t) }()
	_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
		return patch.Patches{patch.Replace(pf.All(), "koko")}
	})
	OrFail(err, t)
	dir("temp",
		file("main.go", "koko"),
	).AssertEqual("temp", t)
}
Example #12
0
func TestGetStdlibIfInstructed(t *testing.T) {
	fs := dir(
		"test",
		file("main.go", `package main;import "fmt";func main() {fmt.Println()}`),
	)
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("test"), t) }()
	pkg, err := ImportDir("fmt", "test")
	pkg.InstrumentGoroot = true
	OrFail(err, t)
	defer func() { OrFail(os.RemoveAll("temp"), t) }()
	_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
		return patch.Patches{patch.Replace(pf.All(), "koko")}
	})
	OrFail(err, t)
	dir("temp",
		dir("goroot", dir("src", dir("pkg",
			dir("fmt", file("doc.go", "koko")),
			dir("go", dir("parser"))))), // should be symlinked
		file("main.go", "koko"),
	).AssertContains("temp", t)
}
Example #13
0
func TestDir(t *testing.T) {
	fs := dir(
		"test1",
		file("a.go", "package test1"), file("a_test.go", "package test1"),
	)
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("test1"), t) }()
	pkg, err := ImportDir("test1", "test1")
	OrFail(err, t)
	if fmt.Sprint(pkg.Files()) != "[test1/a.go]" {
		t.Fatal("Expected [a.go] got", pkg.Files())
	}
	outdir, _, err := pkg.Instrument(true, func(pf *patch.PatchableFile) patch.Patches {
		return patch.Patches{patch.Replace(pf.File, "koko")}
	})

	defer func() { OrFail(os.RemoveAll(outdir), t) }()
	OrFail(err, t)
	dir(filepath.Base(outdir),
		file("a.go", "koko"),
		file("a_test.go", "koko"),
	).AssertEqual(outdir, t)
}
Example #14
0
func (i *Instrumentable) instrumentPatchable(outdir, relpath string, pkg *patch.PatchablePkg, f func(file *patch.PatchableFile) patch.Patches) error {
	path := ""
	if build.IsLocalImport(relpath) {
		path = strings.Replace(relpath, "..", "__", -1)
		path = filepath.Join("locals", path)
	} else if i.pkg.Goroot {
		path = filepath.Join("goroot", "src", "pkg", i.pkg.ImportPath)
		i.gorootPkgs[i.pkg.ImportPath] = true
	} else if relpath != "" {
		path = filepath.Join("gopath", i.pkg.ImportPath)
	}
	if err := os.MkdirAll(filepath.Join(outdir, path), 0755); err != nil {
		return err
	}
	// copy all none-go files (TODO: symlink? OTOH you wouldn't have standalone package)
	for _, files := range [][]string{i.pkg.CFiles, i.pkg.HFiles, i.pkg.SFiles, i.pkg.SysoFiles} {
		for _, file := range files {
			if err := cp(filepath.Join(outdir, path, file), filepath.Join(i.pkg.Dir, file)); err != nil {
				return err
			}
		}
	}
	for filename, file := range pkg.Files {
		if outfile, err := os.Create(filepath.Join(outdir, path, filepath.Base(filename))); err != nil {
			return err
		} else {
			patches := f(file)
			// TODO(elazar): check the relative path from current location (aka relpath, path), to the import path
			// (aka v)
			for _, imp := range file.File.Imports {
				switch v := imp.Path.Value[1 : len(imp.Path.Value)-1]; {
				case v == i.pkg.ImportPath:
					patches = appendNoContradict(patches, patch.Replace(imp.Path, `"."`))
				case !i.relevantImport(v) || i.gorootPkgs[v]:
					continue
				case build.IsLocalImport(v):
					rel, err := filepath.Rel(path, filepath.Join("locals", v))
					if err != nil {
						return err
					}
					patches = appendNoContradict(patches, patch.Replace(imp.Path, `"./`+rel+`"`))
				default:
					if v == i.name {
						v = ""
					} else {
						v = filepath.Join("gopath", v)
					}
					rel, err := filepath.Rel(path, v)
					if err != nil {
						return err
					}
					patches = appendNoContradict(patches, patch.Replace(imp.Path, `"./`+rel+`"`))
				}
			}
			if _, err := file.FprintPatched(outfile, file.All(), patches); err != nil {
				return err
			}
			if err := outfile.Close(); err != nil {
				return err
			}
		}
	}
	return nil
}
Example #15
0
func TestGopathSubDir(t *testing.T) {
	fs := dir(
		"gopath/src/mypkg",
		dir("sub1", file("sub1.go", "package sub1")),
		dir("sub2", file("sub2.go", "package sub2")),
		dir("sub3", dir("subsub3", file("subsub3.go", `package subsub3;import "mypkg/sub1"`))),
		file("base.go", `package test1;import "mypkg/sub1"`), file("a_test.go", `package test1;import "mypkg/sub2"`),
	)
	// TODO(elazar): find a way to use build.Context
	gopath, err := filepath.Abs("gopath")
	OrFail(err, t)
	prevgopath := build.Default.GOPATH
	defer func() { build.Default.GOPATH = prevgopath }()
	build.Default.GOPATH = gopath
	OrFail(fs.Build("."), t)
	defer func() { OrFail(os.RemoveAll("gopath"), t) }()
	func() {
		pkg, err := Import("mypkg", "mypkg")
		OrFail(err, t)
		OrFail(os.Mkdir("temp", 0755), t)
		defer func() { OrFail(os.RemoveAll("temp"), t) }()
		_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
			return patch.Patches{patch.Replace(pf.File, "koko")}
		})
		OrFail(err, t)
		dir("temp", dir("gopath", dir("mypkg",
			dir("sub1", file("sub1.go", "koko")),
			dir("sub2", file("sub2.go", "koko")))),
			file("base.go", "koko"), file("a_test.go", "koko"),
		).AssertEqual("temp", t)
	}()
	func() {
		pkg, err := Import("mypkg", "mypkg/sub3/subsub3")
		OrFail(err, t)
		if len(pkg.Files()) != 1 || pkg.Files()[0] != filepath.Join(gopath, "src", "mypkg", "sub3", "subsub3", "subsub3.go") {
			t.Fatal("When import \"mypkg/sub3/subsub3\" Expected", filepath.Join(gopath, "src", "mypkg", "sub3", "subsub3", "subsub3.go"))
		}
		OrFail(os.Mkdir("temp", 0755), t)
		defer func() { OrFail(os.RemoveAll("temp"), t) }()
		_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
			return nil
		})
		OrFail(err, t)
		dir("temp", dir("gopath", dir("mypkg",
			dir("sub1", file("sub1.go", "package sub1")))),
			file("subsub3.go", `package subsub3;import "./gopath/mypkg/sub1"`),
		).AssertEqual("temp", t)
	}()
	func() {
		pkg, err := Import("mypkg/sub3", "mypkg/sub3/subsub3")
		OrFail(err, t)
		if len(pkg.Files()) != 1 || pkg.Files()[0] != filepath.Join(gopath, "src", "mypkg", "sub3", "subsub3", "subsub3.go") {
			t.Fatal(`When import "mypkg/sub3/subsub3" Expected`, filepath.Join(gopath, "src", "mypkg", "sub3", "subsub3", "subsub3.go"))
		}
		OrFail(os.Mkdir("temp", 0755), t)
		defer func() { OrFail(os.RemoveAll("temp"), t) }()
		_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
			return patch.Patches{patch.Replace(pf.File, "koko")}
		})
		OrFail(err, t)
		dir("temp",
			file("subsub3.go", "koko"),
		).AssertEqual("temp", t)
	}()
	func() {
		pkg, err := Import("mypkg", "mypkg/sub2")
		OrFail(err, t)
		OrFail(os.Mkdir("temp", 0755), t)
		defer func() { OrFail(os.RemoveAll("temp"), t) }()
		_, err = pkg.InstrumentTo(true, "temp", func(pf *patch.PatchableFile) patch.Patches {
			return patch.Patches{patch.Replace(pf.File, "koko")}
		})
		OrFail(err, t)
		dir("temp",
			file("sub2.go", "koko"),
		).AssertEqual("temp", t)
	}()
}