Repository: goplus/gop
Pull request #1066 (2021-12-20 04:53:30)

Release v1.0.37
features:
- implement `gop bug` command
- fix var name collision with package name (#1063)

changes:
- cl: remove isBuiltinAutoCall
- fix: clear gop running cache in HOME dir
- remove env.BuildRevision
- feat: add format support for vars in inner scopes



Patch:
diff --git a/README.md b/README.md
index d7afc11c..0409f108 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@
 
 For now, we suggest you install Go+ from source code.
 
+Note: Requires go1.16 or later
+
 ```bash
 git clone https://github.com/goplus/gop.git
 cd gop
diff --git a/README_zh.md b/README_zh.md
index bab531c9..03d6fc13 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -17,6 +17,8 @@
 
 当前，我们推荐下载源代码来安装 Go+。
 
+注意：需要 go1.16 或更高版本
+
 ```bash
 git clone https://github.com/goplus/gop.git
 cd gop
diff --git a/cl/compile.go b/cl/compile.go
index 4bf51367..7925f9eb 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -305,6 +305,23 @@ type blockCtx struct {
 	fileType     int16
 }
 
+func (bc *blockCtx) findImport(name string) (pr *gox.PkgRef, ok bool) {
+	if pr, ok = bc.imports[name]; ok {
+		return
+	}
+	for k, v := range bc.imports {
+		v.EnsureImported()
+		if v.Types != nil {
+			if v.Types.Name() != k {
+				delete(bc.imports, k)
+				bc.imports[v.Types.Name()] = v
+			}
+		}
+	}
+	pr, ok = bc.imports[name]
+	return
+}
+
 func newCodeErrorf(pos *token.Position, format string, args ...interface{}) *gox.CodeError {
 	return &gox.CodeError{Pos: pos, Msg: fmt.Sprintf(format, args...)}
 }
diff --git a/cl/expr.go b/cl/expr.go
index 342afe8e..81f43ddd 100644
--- a/cl/expr.go
+++ b/cl/expr.go
@@ -103,8 +103,8 @@ func compileIdent(ctx *blockCtx, ident *ast.Ident, flags int) *gox.PkgRef {
 
 	// pkgRef object
 	if (flags & clIdentSelectorExpr) != 0 {
-		if pkgRef, ok := ctx.imports[name]; ok {
-			return pkgRef
+		if pr, ok := ctx.findImport(name); ok {
+			return pr
 		}
 	}
 
@@ -420,7 +420,7 @@ func compileCallExpr(ctx *blockCtx, v *ast.CallExpr, flags int) {
 	}
 	var fn fnType
 	fnt := ctx.cb.Get(-1).Type
-	ellipsis := (v.Ellipsis != gotoken.NoPos)
+	ellipsis := v.Ellipsis != gotoken.NoPos
 	for i, arg := range v.Args {
 		switch expr := arg.(type) {
 		case *ast.LambdaExpr:
@@ -857,7 +857,7 @@ var (
 
 func compileErrWrapExpr(ctx *blockCtx, v *ast.ErrWrapExpr) {
 	pkg, cb := ctx.pkg, ctx.cb
-	useClosure := (v.Tok == token.NOT || v.Default != nil)
+	useClosure := v.Tok == token.NOT || v.Default != nil
 	if !useClosure && (cb.Scope().Parent() == types.Universe) {
 		panic("TODO: can't use expr? in global")
 	}
diff --git a/cl/func_type_and_var.go b/cl/func_type_and_var.go
index 0e54d2b6..f24de2da 100644
--- a/cl/func_type_and_var.go
+++ b/cl/func_type_and_var.go
@@ -146,8 +146,8 @@ func toChanType(ctx *blockCtx, v *ast.ChanType) *types.Chan {
 
 func toExternalType(ctx *blockCtx, v *ast.SelectorExpr) types.Type {
 	name := v.X.(*ast.Ident).Name
-	if pkgRef, ok := ctx.imports[name]; ok {
-		o := pkgRef.TryRef(v.Sel.Name)
+	if pr, ok := ctx.findImport(name); ok {
+		o := pr.TryRef(v.Sel.Name)
 		if t, ok := o.(*types.TypeName); ok {
 			return t.Type()
 		}
diff --git a/cl/stmt.go b/cl/stmt.go
index d8bc695a..02b66f76 100644
--- a/cl/stmt.go
+++ b/cl/stmt.go
@@ -81,14 +81,9 @@ func compileStmt(ctx *blockCtx, stmt ast.Stmt) {
 	commentStmt(ctx, stmt)
 	switch v := stmt.(type) {
 	case *ast.ExprStmt:
-		if obj, ok := isBuiltinAutoCall(ctx, v.X); ok {
-			ctx.cb.Val(obj)
+		compileExpr(ctx, v.X)
+		if canAutoCall(v.X) && gox.IsFunc(ctx.cb.InternalStack().Get(-1).Type) {
 			ctx.cb.Call(0)
-		} else {
-			compileExpr(ctx, v.X)
-			if canAutoCall(v.X) && gox.IsFunc(ctx.cb.InternalStack().Get(-1).Type) {
-				ctx.cb.Call(0)
-			}
 		}
 	case *ast.AssignStmt:
 		compileAssignStmt(ctx, v)
@@ -147,19 +142,6 @@ retry:
 	return false
 }
 
-func isBuiltinAutoCall(ctx *blockCtx, expr ast.Expr) (types.Object, bool) {
-	if ident, ok := expr.(*ast.Ident); ok {
-		switch ident.Name {
-		case "print", "println":
-			_, builtin := lookupType(ctx, ident.Name)
-			if isBuiltin(builtin) {
-				return builtin, true
-			}
-		}
-	}
-	return nil, false
-}
-
 func compileReturnStmt(ctx *blockCtx, expr *ast.ReturnStmt) {
 	var n = -1
 	var results *types.Tuple
diff --git a/cmd/gop/main.go b/cmd/gop/main.go
index da742aa9..a1c6664f 100644
--- a/cmd/gop/main.go
+++ b/cmd/gop/main.go
@@ -22,6 +22,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/goplus/gop/cmd/internal/bug"
 	"github.com/qiniu/x/log"
 
 	"github.com/goplus/gop/cmd/internal/base"
@@ -52,6 +53,7 @@ func init() {
 		mod.Cmd,
 		install.Cmd,
 		build.Cmd,
+		bug.Cmd,
 		clean.Cmd,
 		env.Cmd,
 		test.Cmd,
diff --git a/cmd/internal/bug/bug.go b/cmd/internal/bug/bug.go
new file mode 100644
index 00000000..e61d4723
--- /dev/null
+++ b/cmd/internal/bug/bug.go
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2021-2021 The GoPlus Authors (goplus.org). All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package bug
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"log"
+	urlpkg "net/url"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"time"
+
+	"github.com/goplus/gop/cmd/internal/base"
+	"github.com/goplus/gop/env"
+)
+
+// -----------------------------------------------------------------------------
+
+// Cmd - gop clean
+var Cmd = &base.Command{
+	UsageLine: "gop bug",
+	Short:     "Start a bug report",
+}
+
+func init() {
+	Cmd.Run = runCmd
+}
+
+func runCmd(_ *base.Command, args []string) {
+	if len(args) > 0 {
+		log.Fatalf("gop: bug takes no arguments")
+	}
+	var buf bytes.Buffer
+	buf.WriteString(bugHeader)
+	printGopVersion(&buf)
+	buf.WriteString("### Does this issue reproduce with the latest release?\n\n\n")
+	printEnvDetails(&buf)
+	buf.WriteString(bugFooter)
+
+	body := buf.String()
+	url := "https://github.com/goplus/gop/issues/new?body=" + urlpkg.QueryEscape(body)
+	if !open(url) {
+		fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
+		fmt.Print(body)
+	}
+}
+
+// -----------------------------------------------------------------------------
+
+const bugHeader = `<!-- Please answer these questions before submitting your issue. Thanks! -->
+
+`
+const bugFooter = `### What did you do?
+
+<!--
+If possible, provide a recipe for reproducing the error.
+A complete runnable program is good.
+A link on play.goplus.org is best.
+-->
+
+
+
+### What did you expect to see?
+
+
+
+### What did you see instead?
+
+`
+
+func printGopVersion(w io.Writer) {
+	fmt.Fprintf(w, "### What version of gop are you using (`gop version`)?\n\n")
+	fmt.Fprintf(w, "<pre>\n")
+	fmt.Fprintf(w, "$ gop version\n")
+	fmt.Fprintf(w, "gop version %s %s/%s\n", env.Version(), runtime.GOOS, runtime.GOARCH)
+	fmt.Fprintf(w, "</pre>\n")
+	fmt.Fprintf(w, "\n")
+}
+
+func printEnvDetails(w io.Writer) {
+	fmt.Fprintf(w, "### What operating system and processor architecture are you using (`gop env`)?\n\n")
+	fmt.Fprintf(w, "<details><summary><code>gop env</code> Output</summary><br><pre>\n")
+	fmt.Fprintf(w, "$ gop env\n")
+	printGopEnv(w)
+	printGopDetails(w)
+	printOSDetails(w)
+	printCDetails(w)
+	fmt.Fprintf(w, "</pre></details>\n\n")
+}
+
+func printGopEnv(w io.Writer) {
+	cmd := exec.Command("gop", "env")
+	cmd.Env = os.Environ()
+	cmd.Stdout = w
+
+	err := cmd.Run()
+	if err != nil {
+		log.Fatalln("run gop env failed:", err)
+	}
+}
+
+func printGopDetails(w io.Writer) {
+	gopcmd := filepath.Join(runtime.GOROOT(), "bin/gop")
+	printCmdOut(w, "GOPROOT/bin/gop version: ", gopcmd, "version")
+	printCmdOut(w, "GOPROOT/bin/gop tool compile -V: ", gopcmd, "tool", "compile", "-V")
+}
+
+func printOSDetails(w io.Writer) {
+	switch runtime.GOOS {
+	case "darwin", "ios":
+		printCmdOut(w, "uname -v: ", "uname", "-v")
+		printCmdOut(w, "", "sw_vers")
+	case "linux":
+		printCmdOut(w, "uname -sr: ", "uname", "-sr")
+		printCmdOut(w, "", "lsb_release", "-a")
+		printGlibcVersion(w)
+	case "openbsd", "netbsd", "freebsd", "dragonfly":
+		printCmdOut(w, "uname -v: ", "uname", "-v")
+	case "illumos", "solaris":
+		// Be sure to use the OS-supplied uname, in "/usr/bin":
+		printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv")
+		out, err := os.ReadFile("/etc/release")
+		if err == nil {
+			fmt.Fprintf(w, "/etc/release: %s\n", out)
+		}
+	}
+}
+
+func printCDetails(w io.Writer) {
+	printCmdOut(w, "lldb --version: ", "lldb", "--version")
+	cmd := exec.Command("gdb", "--version")
+	out, err := cmd.Output()
+	if err == nil {
+		// There's apparently no combination of command line flags
+		// to get gdb to spit out its version without the license and warranty.
+		// Print up to the first newline.
+		fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
+	}
+}
+
+// printCmdOut prints the output of running the given command.
+// It ignores failures; 'gop bug' is best effort.
+func printCmdOut(w io.Writer, prefix, path string, args ...string) {
+	cmd := exec.Command(path, args...)
+	out, err := cmd.Output()
+	if err != nil {
+		return
+	}
+	fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
+}
+
+// firstLine returns the first line of a given byte slice.
+func firstLine(buf []byte) []byte {
+	idx := bytes.IndexByte(buf, '\n')
+	if idx > 0 {
+		buf = buf[:idx]
+	}
+	return bytes.TrimSpace(buf)
+}
+
+// printGlibcVersion prints information about the glibc version.
+// It ignores failures.
+func printGlibcVersion(w io.Writer) {
+	tempdir := os.TempDir()
+	if tempdir == "" {
+		return
+	}
+	src := []byte(`int main() {}`)
+	srcfile := filepath.Join(tempdir, "go-bug.c")
+	outfile := filepath.Join(tempdir, "go-bug")
+	err := os.WriteFile(srcfile, src, 0644)
+	if err != nil {
+		return
+	}
+	defer os.Remove(srcfile)
+	cmd := exec.Command("gcc", "-o", outfile, srcfile)
+	if _, err = cmd.CombinedOutput(); err != nil {
+		return
+	}
+	defer os.Remove(outfile)
+
+	cmd = exec.Command("ldd", outfile)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return
+	}
+	re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
+	m := re.FindStringSubmatch(string(out))
+	if m == nil {
+		return
+	}
+	cmd = exec.Command(m[1])
+	out, err = cmd.Output()
+	if err != nil {
+		return
+	}
+	fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
+
+	// print another line (the one containing version string) in case of musl libc
+	if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
+		fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
+	}
+}
+
+// Commands returns a list of possible commands to use to open a url.
+func commands() [][]string {
+	var cmds [][]string
+	if exe := os.Getenv("BROWSER"); exe != "" {
+		cmds = append(cmds, []string{exe})
+	}
+	switch runtime.GOOS {
+	case "darwin":
+		cmds = append(cmds, []string{"/usr/bin/open"})
+	case "windows":
+		cmds = append(cmds, []string{"cmd", "/c", "start"})
+	default:
+		if os.Getenv("DISPLAY") != "" {
+			// xdg-open is only for use in a desktop environment.
+			cmds = append(cmds, []string{"xdg-open"})
+		}
+	}
+	cmds = append(cmds,
+		[]string{"chrome"},
+		[]string{"google-chrome"},
+		[]string{"chromium"},
+		[]string{"firefox"},
+	)
+	return cmds
+}
+
+// Open tries to open url in a browser and reports whether it succeeded.
+func open(url string) bool {
+	for _, args := range commands() {
+		cmd := exec.Command(args[0], append(args[1:], url)...)
+		if cmd.Start() == nil && appearsSuccessful(cmd, 3*time.Second) {
+			return true
+		}
+	}
+	return false
+}
+
+// appearsSuccessful reports whether the command appears to have run successfully.
+// If the command runs longer than the timeout, it's deemed successful.
+// If the command runs within the timeout, it's deemed successful if it exited cleanly.
+func appearsSuccessful(cmd *exec.Cmd, timeout time.Duration) bool {
+	errc := make(chan error, 1)
+	go func() {
+		errc <- cmd.Wait()
+	}()
+
+	select {
+	case <-time.After(timeout):
+		return true
+	case err := <-errc:
+		return err == nil
+	}
+}
diff --git a/cmd/internal/env/env.go b/cmd/internal/env/env.go
index bc502bab..27d85735 100644
--- a/cmd/internal/env/env.go
+++ b/cmd/internal/env/env.go
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package env
 
 import (
@@ -66,7 +67,6 @@ func runCmd(_ *base.Command, args []string) {
 	}
 
 	gopEnv["BUILDDATE"] = env.BuildDate()
-	gopEnv["BUILDREV"] = env.BuildRevision()
 	gopEnv["GOPVERSION"] = env.Version()
 	gopEnv["GOPROOT"] = env.GOPROOT()
 	gopEnv["GOPATH"] = env.GOPATH()
diff --git a/cmd/make.go b/cmd/make.go
index 7d8506d3..b510e7d2 100644
--- a/cmd/make.go
+++ b/cmd/make.go
@@ -109,6 +109,7 @@ func getRevCommit(tag string) string {
 	return strings.TrimRight(commit, "\n")
 }
 
+/*
 func getGitInfo() (string, bool) {
 	gitDir := filepath.Join(gopRoot, ".git")
 	if checkPathExist(gitDir, true) {
@@ -116,6 +117,7 @@ func getGitInfo() (string, bool) {
 	}
 	return "", false
 }
+*/
 
 func getBuildDateTime() string {
 	now := time.Now()
@@ -137,11 +139,8 @@ func getGopBuildFlags() string {
 	}
 	buildFlags := fmt.Sprintf("-X \"github.com/goplus/gop/env.defaultGopRoot=%s\"", defaultGopRoot)
 	buildFlags += fmt.Sprintf(" -X \"github.com/goplus/gop/env.buildDate=%s\"", getBuildDateTime())
-	if commit, ok := getGitInfo(); ok {
-		buildFlags += fmt.Sprintf(" -X github.com/goplus/gop/env.buildCommit=%s", commit)
-		if buildVer := getBuildVer(); buildVer != "" {
-			buildFlags += fmt.Sprintf(" -X github.com/goplus/gop/env.buildVersion=%s", buildVer)
-		}
+	if buildVer := getBuildVer(); buildVer != "" {
+		buildFlags += fmt.Sprintf(" -X github.com/goplus/gop/env.buildVersion=%s", buildVer)
 	}
 	return buildFlags
 }
diff --git a/env/build.go b/env/build.go
index 9b4e0d37..b7325414 100644
--- a/env/build.go
+++ b/env/build.go
@@ -17,17 +17,11 @@
 package env
 
 // The value of variables come form
-// `go build -ldflags '-X "buildDate=xxxxx" -X "buildCommit=xxxx"'`
+// `go build -ldflags '-X "buildDate=xxxxx"`
 var (
-	buildDate   string
-	buildCommit string
+	buildDate string
 )
 
 func BuildDate() string {
 	return buildDate
 }
-
-// BuildRevision returns build revision id.
-func BuildRevision() string {
-	return buildCommit
-}
diff --git a/x/format/README.md b/x/format/README.md
index 1b308cee..5276fd6c 100644
--- a/x/format/README.md
+++ b/x/format/README.md
@@ -56,11 +56,16 @@ n, err := println("Hello world")
 
 Note:
 
+* Convert `fmt.Errorf => errorf`
+* Convert `fmt.Fprint => fprint`
+* Convert `fmt.Fprintf => fprintf`
+* Convert `fmt.Fprintln => fprintln`
 * Convert `fmt.Print` => `print`
 * Convert `fmt.Printf` => `printf`
 * Convert `fmt.Println` => `println`
-* ...
-
+* Convert `fmt.Sprint => sprint`
+* Convert `fmt.Sprintf => sprintf`
+* Convert `fmt.Sprintln => sprintln`
 
 ### Command style first
 
diff --git a/x/format/gopstyle.go b/x/format/gopstyle.go
index 9afe25ee..92b31a0f 100644
--- a/x/format/gopstyle.go
+++ b/x/format/gopstyle.go
@@ -142,16 +142,20 @@ type importCtx struct {
 
 type formatCtx struct {
 	imports map[string]*importCtx
+	scp     *scope
 }
 
 func formatFile(file *ast.File) {
+	var funcs []*ast.FuncDecl
 	ctx := &formatCtx{
 		imports: make(map[string]*importCtx),
+		scp:     newScope(),
 	}
 	for _, decl := range file.Decls {
 		switch v := decl.(type) {
 		case *ast.FuncDecl:
-			formatFuncDecl(ctx, v)
+			// delay the process, because package level vars need to be processed first.
+			funcs = append(funcs, v)
 		case *ast.GenDecl:
 			switch v.Tok {
 			case token.IMPORT:
@@ -174,6 +178,10 @@ func formatFile(file *ast.File) {
 			}
 		}
 	}
+
+	for _, fn := range funcs {
+		formatFuncDecl(ctx, fn)
+	}
 	for _, imp := range ctx.imports {
 		if imp.pkgPath == "fmt" && !imp.isUsed {
 			if len(imp.decl.Specs) == 1 {
@@ -192,6 +200,7 @@ func formatGenDecl(ctx *formatCtx, v *ast.GenDecl) {
 			spec := item.(*ast.ValueSpec)
 			formatType(ctx, spec.Type, &spec.Type)
 			formatExprs(ctx, spec.Values)
+			fillVarCtx(ctx, spec)
 		}
 	case token.TYPE:
 		for _, item := range v.Specs {
@@ -206,4 +215,42 @@ func formatFuncDecl(ctx *formatCtx, v *ast.FuncDecl) {
 	formatBlockStmt(ctx, v.Body)
 }
 
+func fillVarCtx(ctx *formatCtx, spec *ast.ValueSpec) {
+	for _, name := range spec.Names {
+		ctx.scp.addVar(name.Name)
+	}
+}
+
 // -----------------------------------------------------------------------------
+
+type scope struct {
+	vars []map[string]bool
+}
+
+func newScope() *scope {
+	return &scope{
+		vars: []map[string]bool{make(map[string]bool)},
+	}
+}
+
+func (s *scope) addVar(name string) {
+	s.vars[len(s.vars)-1][name] = true
+}
+
+func (s *scope) containsVar(name string) bool {
+	for _, m := range s.vars {
+		if m[name] {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (s *scope) enterScope() {
+	s.vars = append(s.vars, make(map[string]bool))
+}
+
+func (s *scope) exitScope() {
+	s.vars = s.vars[:len(s.vars)-1]
+}
diff --git a/x/format/stmt_expr_or_type.go b/x/format/stmt_expr_or_type.go
index 60bec773..e9f51462 100644
--- a/x/format/stmt_expr_or_type.go
+++ b/x/format/stmt_expr_or_type.go
@@ -170,7 +170,9 @@ func formatCallExpr(ctx *formatCtx, v *ast.CallExpr) {
 func formatSelectorExpr(ctx *formatCtx, v *ast.SelectorExpr, ref *ast.Expr) {
 	switch x := v.X.(type) {
 	case *ast.Ident:
-		// TODO: maybe have bugs: `x.Name` may be a variable, not a import.
+		if ctx.scp.containsVar(x.Name) {
+			break
+		}
 		if imp, ok := ctx.imports[x.Name]; ok {
 			if !fmtToBuiltin(imp, v.Sel, ref) {
 				imp.isUsed = true
@@ -185,7 +187,9 @@ func formatSelectorExpr(ctx *formatCtx, v *ast.SelectorExpr, ref *ast.Expr) {
 
 func formatBlockStmt(ctx *formatCtx, stmt *ast.BlockStmt) {
 	if stmt != nil {
+		ctx.scp.enterScope()
 		formatStmts(ctx, stmt.List)
+		ctx.scp.exitScope()
 	}
 }
 
diff --git a/x/gopmod/gocmd.go b/x/gopmod/gocmd.go
index b405ca85..7aa79f0a 100644
--- a/x/gopmod/gocmd.go
+++ b/x/gopmod/gocmd.go
@@ -30,23 +30,21 @@ import (
 const (
 	ldFlagVersion   = "-X \"github.com/goplus/gop/env.buildVersion=%s\""
 	ldFlagBuildDate = "-X \"github.com/goplus/gop/env.buildDate=%s\""
-	ldFlagBuildRev  = "-X \"github.com/goplus/gop/env.buildCommit=%s\""
 	ldFlagGopRoot   = "-X \"github.com/goplus/gop/env.defaultGopRoot=%s\""
 )
 
 const (
-	ldFlagAll = ldFlagVersion + " " + ldFlagBuildDate + " " + ldFlagBuildRev + " " + ldFlagGopRoot
+	ldFlagAll = ldFlagVersion + " " + ldFlagBuildDate + " " + ldFlagGopRoot
 )
 
 var (
 	GOPVERSION   = env.Version()
 	GOPBUILDDATE = env.BuildDate()
-	GOPBUILDREV  = env.BuildRevision()
 	GOPROOT      = env.GOPROOT()
 )
 
 func LoadFlags() string {
-	return fmt.Sprintf(ldFlagAll, GOPVERSION, GOPBUILDDATE, GOPBUILDREV, GOPROOT)
+	return fmt.Sprintf(ldFlagAll, GOPVERSION, GOPBUILDDATE, GOPROOT)
 }
 
 // -----------------------------------------------------------------------------


Test patch:
diff --git a/env/version_test.go b/env/version_test.go
index 20fb033b..5b51422d 100644
--- a/env/version_test.go
+++ b/env/version_test.go
@@ -30,9 +30,6 @@ func TestVersion(t *testing.T) {
 }
 
 func TestBuild(t *testing.T) {
-	if BuildRevision() != "" {
-		t.Fatal("BuildCommit failed:", BuildRevision())
-	}
 	if BuildDate() != "" {
 		t.Fatal("BuildInfo failed:", BuildDate())
 	}
diff --git a/x/format/gopstyle_test.go b/x/format/gopstyle_test.go
index 5492477e..e2bb3e99 100644
--- a/x/format/gopstyle_test.go
+++ b/x/format/gopstyle_test.go
@@ -342,3 +342,139 @@ func f() {
 }
 `)
 }
+
+func TestErrorfWithPackageLevelVar(t *testing.T) {
+	testFormat(t, "print", `package main
+
+import "errors"
+import "fmt"
+
+var _ = fmt.Errorf("hello %w", errors.New("world"))
+`, `import "errors"
+
+var _ = errorf("hello %w", errors.new("world"))
+`)
+}
+
+func TestPrintlnWithFmtVarNoImport(t *testing.T) {
+	testFormat(t, "print", `package main
+
+func f() {
+	var fmt Foo
+	fmt.Println(1)
+}
+`, `func f() {
+	var fmt Foo
+	fmt.println 1
+}
+`)
+}
+
+func TestPrintlnWithFmtVar(t *testing.T) {
+	testFormat(t, "print", `package main
+
+import "fmt"
+
+var _ fmt.Stringer
+
+func f() {
+	var fmt Foo
+	fmt.Println(1)
+}
+`, `import "fmt"
+
+var _ fmt.Stringer
+
+func f() {
+	var fmt Foo
+	fmt.println 1
+}
+`)
+}
+
+// todo: fix inner scope vars
+// func TestPrintlnWithScopedFmtVar(t *testing.T) {
+// 	testFormat(t, "print", `package main
+//
+// import "fmt"
+//
+// func f() {
+// 	{
+// 		var fmt Foo
+// 		_ = fmt
+// 	}
+// 	fmt.Println(1)
+// }
+// `, `func f() {
+// 	{
+// 		var fmt Foo
+// 		_ = fmt
+// 	}
+// 	println 1
+// }
+// `)
+// }
+
+func TestPrintlnWithFmtVarAfter(t *testing.T) {
+	testFormat(t, "print", `package main
+
+import "fmt"
+
+func f() {
+	fmt.Println(1)
+	var fmt Foo
+	_ = fmt
+}
+`, `func f() {
+	println 1
+	var fmt Foo
+	_ = fmt
+}
+`)
+}
+
+func TestPrintlnWithPackageLevelFmtVar(t *testing.T) {
+	testFormat(t, "print", `package main
+
+var fmt Foo
+
+func f() {
+	fmt.Println(1)
+}
+`, `var fmt Foo
+
+func f() {
+	fmt.println 1
+}
+`)
+}
+
+func TestPrintlnWithPackageLevelFmtVarAfter(t *testing.T) {
+	testFormat(t, "print", `package main
+
+func f() {
+	fmt.Println(1)
+}
+
+var fmt Foo
+`, `func f() {
+	fmt.println 1
+}
+
+var fmt Foo
+`)
+}
+
+func TestPrintlnWithVarFromCall(t *testing.T) {
+	testFormat(t, "print", `package main
+
+func f() {
+	var fmt = Foo()
+	fmt.Println(1)
+}
+`, `func f() {
+	var fmt = Foo()
+	fmt.println 1
+}
+`)
+}