diff --git a/README.md b/README.md index d572972..e152b30 100644 --- a/README.md +++ b/README.md @@ -651,7 +651,7 @@ package p $ gofumpt f.go package p -//gofumpt:diagnose v0.1.1-0.20211103104632-bdfa3b02e50a -lang=v1.16 +//gofumpt:diagnose v0.1.1-0.20211103104632-bdfa3b02e50a -lang=go1.16 ``` ### License diff --git a/format/format.go b/format/format.go index 64d4fe0..e81420c 100644 --- a/format/format.go +++ b/format/format.go @@ -12,6 +12,7 @@ import ( "go/ast" "go/parser" "go/token" + goversion "go/version" "os" "reflect" "regexp" @@ -23,7 +24,6 @@ import ( "unicode/utf8" "github.com/google/go-cmp/cmp" - "golang.org/x/mod/semver" "golang.org/x/tools/go/ast/astutil" "mvdan.cc/gofumpt/internal/govendor/go/format" @@ -32,26 +32,25 @@ import ( // Options is the set of formatting options which affect gofumpt. type Options struct { - // TODO: link to the go/version docs once Go 1.22 is out. - // The old semver docs said: - // - // LangVersion is treated as a semantic version, which may start with a "v" - // prefix. Like Go versions, it may also be incomplete; "1.14" is equivalent - // to "1.14.0". When empty, it is equivalent to "v1", to not use language - // features which could break programs. - // LangVersion is the Go version a piece of code is written in. // The version is used to decide whether to apply formatting // rules which require new language features. - // When inside a Go module, LangVersion should typically be: + // When empty, a default of go1 is assumed. + // Otherwise, the version must satisfy [go/version.IsValid]. + // + // When formatting a Go module, LangVersion should typically be // - // go mod edit -json | jq -r '.Go' + // go list -m -f {{.GoVersion}} + // + // with a "go" prefix, or the equivalent from `go mod edit -json`. LangVersion string // ModulePath corresponds to the Go module path which contains the source - // code being formatted. When inside a Go module, ModulePath should be: + // code being formatted. When formatting a Go module, ModulePath should be + // + // go list -m -f {{.Path}} // - // go mod edit -json | jq -r '.Module.Path' + // or the equivalent from `go mod edit -json`. // // ModulePath is used for formatting decisions like what import paths are // considered to be not part of the standard library. When empty, the source @@ -86,26 +85,21 @@ func Source(src []byte, opts Options) ([]byte, error) { return buf.Bytes(), nil } -var rxGoVersionMajorMinor = regexp.MustCompile(`^(v|go)?([1-9]+)\.([0-9]+)`) - // File modifies a file and fset in place to follow gofumpt's format. The // changes might include manipulating adding or removing newlines in fset, // modifying the position of nodes, or modifying literal values. func File(fset *token.FileSet, file *ast.File, opts Options) { simplify(file) - // TODO: replace this hacky mess with go/version once we can rely on Go 1.22, - // as well as replacing our uses of the semver package. - // In particular, we likely want to allow any of 1.21, 1.21.2, or go1.21rc3, - // but we can rely on go/version.Lang to validate and normalize. if opts.LangVersion == "" { - opts.LangVersion = "v1.0" - } - m := rxGoVersionMajorMinor.FindStringSubmatch(opts.LangVersion) - if m == nil { - panic(fmt.Sprintf("invalid Go version: %q", opts.LangVersion)) + opts.LangVersion = "go1" + } else { + lang := goversion.Lang(opts.LangVersion) + if lang == "" { + panic(fmt.Sprintf("invalid Go version: %q", opts.LangVersion)) + } + opts.LangVersion = lang } - opts.LangVersion = "v" + m[2] + "." + m[3] f := &fumpter{ file: fset.File(file.Pos()), fset: fset, @@ -680,8 +674,8 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { } case *ast.BasicLit: - // Octal number literals were introduced in 1.13. - if semver.Compare(f.LangVersion, "v1.13") >= 0 { + // Octal number literals were introduced in Go 1.13. + if goversion.Compare(f.LangVersion, "go1.13") >= 0 { if node.Kind == token.INT && rxOctalInteger.MatchString(node.Value) { node.Value = "0o" + node.Value[1:] c.Replace(node) diff --git a/format/fuzz_test.go b/format/fuzz_test.go index 8dfa113..649c20c 100644 --- a/format/fuzz_test.go +++ b/format/fuzz_test.go @@ -26,9 +26,9 @@ func FuzzFormat(f *testing.F) { for _, file := range archive.Files { f.Logf("adding %s from %s", file.Name, path) if strings.HasSuffix(file.Name, ".go") || strings.Contains(file.Name, ".go.") { - f.Add(string(file.Data), int8(18), false) // -lang=1.18 - f.Add(string(file.Data), int8(1), false) // -lang=1.1 - f.Add(string(file.Data), int8(18), true) // -lang=1.18 -extra + f.Add(string(file.Data), int8(18), false) // -lang=go1.18 + f.Add(string(file.Data), int8(1), false) // -lang=go1.1 + f.Add(string(file.Data), int8(18), true) // -lang=go1.18 -extra } } } @@ -40,7 +40,7 @@ func FuzzFormat(f *testing.F) { // TODO: also fuzz Options.ModulePath opts := Options{ExtraRules: extraRules} if majorVersion >= 0 { - opts.LangVersion = fmt.Sprintf("1.%d", majorVersion) + opts.LangVersion = fmt.Sprintf("go1.%d", majorVersion) } orig := []byte(src) diff --git a/go.mod b/go.mod index c973b93..e862bba 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module mvdan.cc/gofumpt -go 1.21 +go 1.22 require ( github.com/go-quicktest/qt v1.101.0 diff --git a/gofmt.go b/gofmt.go index 384795a..873a74d 100644 --- a/gofmt.go +++ b/gofmt.go @@ -96,7 +96,7 @@ func usage() { -w write result to (source) file instead of stdout -extra enable extra rules which should be vetted by a human - -lang str target Go version in the form "1.X" (default from go.mod) + -lang str target Go version in the form "go1.X" (default from go.mod) -modpath str Go module path containing the source file (default from go.mod) `) } @@ -298,7 +298,7 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter, e if ok && mod != nil { mod := mod.(*module) if lang == "" { - lang = mod.Go + lang = "go" + mod.Go } if modpath == "" { modpath = mod.Module.Path diff --git a/testdata/script/diagnose.txtar b/testdata/script/diagnose.txtar index 6bbcb8f..ec40644 100644 --- a/testdata/script/diagnose.txtar +++ b/testdata/script/diagnose.txtar @@ -14,7 +14,7 @@ cmp stdout foo.go.golden exec gofumpt -extra foo.go cmp stdout foo.go.golden-extra -exec gofumpt -lang=1.0 foo.go +exec gofumpt -lang=go1 foo.go cmp stdout foo.go.golden-lang exec gofumpt -d nochange.go @@ -79,24 +79,24 @@ package p -- foo.go.golden -- package p -//gofumpt:diagnose version: v0.0.0-20220727155840-8dda8068d9f3 (go1.18.29) flags: -lang=v1.16 -modpath=test +//gofumpt:diagnose version: v0.0.0-20220727155840-8dda8068d9f3 (go1.18.29) flags: -lang=go1.16 -modpath=test -- foo.go.golden-devel -- package p -//gofumpt:diagnose version: (devel) (go1.18.29) flags: -lang=v1.16 -modpath=test +//gofumpt:diagnose version: (devel) (go1.18.29) flags: -lang=go1.16 -modpath=test -- foo.go.golden-extra -- package p -//gofumpt:diagnose version: v0.0.0-20220727155840-8dda8068d9f3 (go1.18.29) flags: -lang=v1.16 -modpath=test -extra +//gofumpt:diagnose version: v0.0.0-20220727155840-8dda8068d9f3 (go1.18.29) flags: -lang=go1.16 -modpath=test -extra -- foo.go.golden-lang -- package p -//gofumpt:diagnose version: v0.0.0-20220727155840-8dda8068d9f3 (go1.18.29) flags: -lang=v1.0 -modpath=test +//gofumpt:diagnose version: v0.0.0-20220727155840-8dda8068d9f3 (go1.18.29) flags: -lang=go1 -modpath=test -- foo.go.golden-released -- package p -//gofumpt:diagnose v0.3.2-0.20220627183521-8dda8068d9f3 -lang=v1.16 -modpath=test +//gofumpt:diagnose v0.3.2-0.20220627183521-8dda8068d9f3 -lang=go1.16 -modpath=test -- foo.go.golden-external -- package p -//gofumpt:diagnose (devel) -lang=v1.16 -modpath= +//gofumpt:diagnose (devel) -lang=go1.16 -modpath= diff --git a/testdata/script/gomod.txtar b/testdata/script/gomod.txtar index 90f13a8..e3c0258 100644 --- a/testdata/script/gomod.txtar +++ b/testdata/script/gomod.txtar @@ -1,10 +1,10 @@ # Test various edge cases with go.mod files. exec gofumpt toolchain-stable/a.go -stdout '//gofumpt:diagnose.* -lang=v1.21' +stdout '//gofumpt:diagnose.* -lang=go1.21' exec gofumpt toolchain-unstable/a.go -stdout '//gofumpt:diagnose.* -lang=v1.21' +stdout '//gofumpt:diagnose.* -lang=go1.21' -- toolchain-stable/go.mod -- module a diff --git a/testdata/script/octal-literals.txtar b/testdata/script/octal-literals.txtar index 0408dda..3577a72 100644 --- a/testdata/script/octal-literals.txtar +++ b/testdata/script/octal-literals.txtar @@ -3,7 +3,7 @@ exec gofumpt -l . ! stdout . # We can give an explicitly newer version. -exec gofumpt -lang=1.13 -l . +exec gofumpt -lang=go1.13 -l . stdout -count=1 'foo\.go' stdout -count=1 'nested[/\\]nested\.go' @@ -20,7 +20,7 @@ exec gofumpt -d foo.go.golden ! stdout . # We can give an explicitly older version, too -exec gofumpt -lang=1.0 -l . +exec gofumpt -lang=go1.0 -l . ! stdout . -- go.mod --