Skip to content

feat(gofmt): update to gofmt from Go 1.21.1 #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ module github.com/golangci/gofmt
go 1.18

require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f
golang.org/x/tools v0.1.12
golang.org/x/sync v0.3.0
golang.org/x/tools v0.13.0
)

require (
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.12.0 // indirect
)
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
8 changes: 5 additions & 3 deletions gofmt/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ that directory, recursively. (Files starting with a period are ignored.)
By default, gofmt prints the reformatted sources to standard output.

Usage:

gofmt [flags] [path ...]

The flags are:

-d
Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs
Expand All @@ -37,10 +39,10 @@ The flags are:
the original file is restored from an automatic backup.

Debugging support:

-cpuprofile filename
Write cpu profile to the specified file.


The rewrite rule specified with the -r flag must be a string of the form:

pattern -> replacement
Expand All @@ -57,7 +59,7 @@ such a fragment, gofmt preserves leading indentation as well as leading
and trailing spaces, so that individual sections of a Go program can be
formatted by piping them through gofmt.

Examples
# Examples

To check files for unnecessary parentheses:

Expand All @@ -71,7 +73,7 @@ To convert the package tree from explicit slice upper bounds to implicit ones:

gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src

The simplify command
# The simplify command

When invoked with -s gofmt will make the following source transformations where possible.

Expand Down
203 changes: 120 additions & 83 deletions gofmt/gofmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,30 @@ import (
"go/token"
"io"
"io/fs"
"math/rand"
"os"
"path/filepath"
"runtime"
"runtime/pprof"
"strconv"
"strings"

"github.com/golangci/gofmt/gofmt/internal/diff"
"golang.org/x/sync/semaphore"

"github.com/golangci/gofmt/gofmt/internal/diff"
)

var (
// main operation modes
list = flag.Bool("gofmt.l", false, "list files whose formatting differs from gofmt's")
write = flag.Bool("gofmt.w", false, "write result to (source) file instead of stdout")
rewriteRule = flag.String("gofmt.r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
simplifyAST = flag.Bool("gofmt.s", false, "simplify code")
doDiff = flag.Bool("gofmt.d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("gofmt.e", false, "report all errors (not just the first 10 on different lines)")
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
simplifyAST = flag.Bool("s", false, "simplify code")
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")

// debugging
cpuprofile = flag.String("gofmt.cpuprofile", "", "write cpu profile to this file")
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)

// Keep these in sync with go/format/format.go.
Expand Down Expand Up @@ -76,6 +79,11 @@ func initParserMode() {
if *allErrors {
parserMode |= parser.AllErrors
}
// It's only -r that makes use of go/ast's object resolution,
// so avoid the unnecessary work if the flag isn't used.
if *rewriteRule == "" {
parserMode |= parser.SkipObjectResolution
}
}

func isGoFile(f fs.DirEntry) bool {
Expand Down Expand Up @@ -228,12 +236,9 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) e
}

fileSet := token.NewFileSet()
fragmentOk := false
if info == nil {
// If we are formatting stdin, we accept a program fragment in lieu of a
// complete source file.
fragmentOk = true
}
// If we are formatting stdin, we accept a program fragment in lieu of a
// complete source file.
fragmentOk := info == nil
file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, fragmentOk)
if err != nil {
return err
Expand Down Expand Up @@ -267,31 +272,16 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) e
if info == nil {
panic("-w should not have been allowed with stdin")
}
// make a temporary backup before overwriting original

perm := info.Mode().Perm()
bakname, err := backupFile(filename+".", src, perm)
if err != nil {
return err
}
fdSem <- true
err = os.WriteFile(filename, res, perm)
<-fdSem
if err != nil {
os.Rename(bakname, filename)
return err
}
err = os.Remove(bakname)
if err != nil {
if err := writeFile(filename, src, res, perm, info.Size()); err != nil {
return err
}
}
if *doDiff {
data, err := diffWithReplaceTempFile(src, res, filename)
if err != nil {
return fmt.Errorf("computing diff: %s", err)
}
fmt.Fprintf(r, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename))
r.Write(data)
newName := filepath.ToSlash(filename)
oldName := newName + ".orig"
r.Write(diff.Diff(oldName, src, newName, res))
}
}

Expand Down Expand Up @@ -350,7 +340,12 @@ func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) {
// stop to avoid corrupting it.)
src := make([]byte, size+1)
n, err := io.ReadFull(in, src)
if err != nil && err != io.ErrUnexpectedEOF {
switch err {
case nil, io.EOF, io.ErrUnexpectedEOF:
// io.ReadFull returns io.EOF (for an empty file) or io.ErrUnexpectedEOF
// (for a non-empty file) if the file was changed unexpectedly. Continue
// with comparing file sizes in those cases.
default:
return nil, err
}
if n < size {
Expand Down Expand Up @@ -463,69 +458,111 @@ func fileWeight(path string, info fs.FileInfo) int64 {
return info.Size()
}

func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) {
data, err := diff.Diff("gofmt", b1, b2)
if len(data) > 0 {
return replaceTempFilename(data, filename)
// writeFile updates a file with the new formatted data.
func writeFile(filename string, orig, formatted []byte, perm fs.FileMode, size int64) error {
// Make a temporary backup file before rewriting the original file.
bakname, err := backupFile(filename, orig, perm)
if err != nil {
return err
}
return data, err
}

// replaceTempFilename replaces temporary filenames in diff with actual one.
//
// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500
// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500
// ...
// ->
// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500
// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500
// ...
func replaceTempFilename(diff []byte, filename string) ([]byte, error) {
bs := bytes.SplitN(diff, []byte{'\n'}, 3)
if len(bs) < 3 {
return nil, fmt.Errorf("got unexpected diff for %s", filename)
}
// Preserve timestamps.
var t0, t1 []byte
if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 {
t0 = bs[0][i:]
}
if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 {
t1 = bs[1][i:]
}
// Always print filepath with slash separator.
f := filepath.ToSlash(filename)
bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0))
bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1))
return bytes.Join(bs, []byte{'\n'}), nil
}
fdSem <- true
defer func() { <-fdSem }()

fout, err := os.OpenFile(filename, os.O_WRONLY, perm)
if err != nil {
// We couldn't even open the file, so it should
// not have changed.
os.Remove(bakname)
return err
}
defer fout.Close() // for error paths

restoreFail := func(err error) {
fmt.Fprintf(os.Stderr, "gofmt: %s: error restoring file to original: %v; backup in %s\n", filename, err, bakname)
}

const chmodSupported = runtime.GOOS != "windows"
n, err := fout.Write(formatted)
if err == nil && int64(n) < size {
err = fout.Truncate(int64(n))
}

if err != nil {
// Rewriting the file failed.

if n == 0 {
// Original file unchanged.
os.Remove(bakname)
return err
}

// Try to restore the original contents.

no, erro := fout.WriteAt(orig, 0)
if erro != nil {
// That failed too.
restoreFail(erro)
return err
}

if no < n {
// Original file is shorter. Truncate.
if erro = fout.Truncate(int64(no)); erro != nil {
restoreFail(erro)
return err
}
}

if erro := fout.Close(); erro != nil {
restoreFail(erro)
return err
}

// Original contents restored.
os.Remove(bakname)
return err
}

if err := fout.Close(); err != nil {
restoreFail(err)
return err
}

// File updated.
os.Remove(bakname)
return nil
}

// backupFile writes data to a new file named filename<number> with permissions perm,
// with <number randomly chosen such that the file name is unique. backupFile returns
// with <number> randomly chosen such that the file name is unique. backupFile returns
// the chosen file name.
func backupFile(filename string, data []byte, perm fs.FileMode) (string, error) {
fdSem <- true
defer func() { <-fdSem }()

// create backup file
f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename))
if err != nil {
return "", err
nextRandom := func() string {
return strconv.Itoa(rand.Int())
}
bakname := f.Name()
if chmodSupported {
err = f.Chmod(perm)
if err != nil {
f.Close()
os.Remove(bakname)
return bakname, err

dir, base := filepath.Split(filename)
var (
bakname string
f *os.File
)
for {
bakname = filepath.Join(dir, base+"."+nextRandom())
var err error
f, err = os.OpenFile(bakname, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm)
if err == nil {
break
}
if err != nil && !os.IsExist(err) {
return "", err
}
}

// write data to backup file
_, err = f.Write(data)
_, err := f.Write(data)
if err1 := f.Close(); err == nil {
err = err1
}
Expand Down
Loading