summaryrefslogtreecommitdiffstats
path: root/src/cmd/gofmt
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gofmt')
-rw-r--r--src/cmd/gofmt/doc.go106
-rw-r--r--src/cmd/gofmt/gofmt.go570
-rw-r--r--src/cmd/gofmt/gofmt_test.go195
-rw-r--r--src/cmd/gofmt/gofmt_unix_test.go67
-rw-r--r--src/cmd/gofmt/internal.go176
-rw-r--r--src/cmd/gofmt/long_test.go185
-rw-r--r--src/cmd/gofmt/rewrite.go311
-rw-r--r--src/cmd/gofmt/simplify.go169
-rw-r--r--src/cmd/gofmt/testdata/comments.golden9
-rw-r--r--src/cmd/gofmt/testdata/comments.input9
-rw-r--r--src/cmd/gofmt/testdata/composites.golden218
-rw-r--r--src/cmd/gofmt/testdata/composites.input218
-rw-r--r--src/cmd/gofmt/testdata/crlf.golden13
-rw-r--r--src/cmd/gofmt/testdata/crlf.input13
-rw-r--r--src/cmd/gofmt/testdata/emptydecl.golden14
-rw-r--r--src/cmd/gofmt/testdata/emptydecl.input16
-rw-r--r--src/cmd/gofmt/testdata/go2numbers.golden186
-rw-r--r--src/cmd/gofmt/testdata/go2numbers.input186
-rw-r--r--src/cmd/gofmt/testdata/import.golden194
-rw-r--r--src/cmd/gofmt/testdata/import.input199
-rw-r--r--src/cmd/gofmt/testdata/issue28082.golden13
-rw-r--r--src/cmd/gofmt/testdata/issue28082.input13
-rw-r--r--src/cmd/gofmt/testdata/ranges.golden30
-rw-r--r--src/cmd/gofmt/testdata/ranges.input20
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.golden14
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.input14
-rw-r--r--src/cmd/gofmt/testdata/rewrite10.golden19
-rw-r--r--src/cmd/gofmt/testdata/rewrite10.input19
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.golden12
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.input12
-rw-r--r--src/cmd/gofmt/testdata/rewrite3.golden14
-rw-r--r--src/cmd/gofmt/testdata/rewrite3.input14
-rw-r--r--src/cmd/gofmt/testdata/rewrite4.golden76
-rw-r--r--src/cmd/gofmt/testdata/rewrite4.input76
-rw-r--r--src/cmd/gofmt/testdata/rewrite5.golden17
-rw-r--r--src/cmd/gofmt/testdata/rewrite5.input17
-rw-r--r--src/cmd/gofmt/testdata/rewrite6.golden17
-rw-r--r--src/cmd/gofmt/testdata/rewrite6.input17
-rw-r--r--src/cmd/gofmt/testdata/rewrite7.golden17
-rw-r--r--src/cmd/gofmt/testdata/rewrite7.input17
-rw-r--r--src/cmd/gofmt/testdata/rewrite8.golden12
-rw-r--r--src/cmd/gofmt/testdata/rewrite8.input12
-rw-r--r--src/cmd/gofmt/testdata/rewrite9.golden11
-rw-r--r--src/cmd/gofmt/testdata/rewrite9.input11
-rw-r--r--src/cmd/gofmt/testdata/slices1.golden66
-rw-r--r--src/cmd/gofmt/testdata/slices1.input66
-rw-r--r--src/cmd/gofmt/testdata/stdin1.golden5
-rw-r--r--src/cmd/gofmt/testdata/stdin1.input5
-rw-r--r--src/cmd/gofmt/testdata/stdin2.golden11
-rw-r--r--src/cmd/gofmt/testdata/stdin2.input11
-rw-r--r--src/cmd/gofmt/testdata/stdin3.golden7
-rw-r--r--src/cmd/gofmt/testdata/stdin3.input5
-rw-r--r--src/cmd/gofmt/testdata/stdin4.golden5
-rw-r--r--src/cmd/gofmt/testdata/stdin4.input5
-rw-r--r--src/cmd/gofmt/testdata/stdin5.golden3
-rw-r--r--src/cmd/gofmt/testdata/stdin5.input3
-rw-r--r--src/cmd/gofmt/testdata/stdin6.golden19
-rw-r--r--src/cmd/gofmt/testdata/stdin6.input21
-rw-r--r--src/cmd/gofmt/testdata/stdin7.golden19
-rw-r--r--src/cmd/gofmt/testdata/stdin7.input21
-rw-r--r--src/cmd/gofmt/testdata/tabs.golden33
-rw-r--r--src/cmd/gofmt/testdata/tabs.input33
-rw-r--r--src/cmd/gofmt/testdata/typealias.golden24
-rw-r--r--src/cmd/gofmt/testdata/typealias.input24
-rw-r--r--src/cmd/gofmt/testdata/typeparams.golden35
-rw-r--r--src/cmd/gofmt/testdata/typeparams.input32
-rw-r--r--src/cmd/gofmt/testdata/typeswitch.golden60
-rw-r--r--src/cmd/gofmt/testdata/typeswitch.input60
68 files changed, 4121 insertions, 0 deletions
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
new file mode 100644
index 0000000..8ac9c6a
--- /dev/null
+++ b/src/cmd/gofmt/doc.go
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Gofmt formats Go programs.
+It uses tabs for indentation and blanks for alignment.
+Alignment assumes that an editor is using a fixed-width font.
+
+Without an explicit path, it processes the standard input. Given a file,
+it operates on that file; given a directory, it operates on all .go files in
+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
+ to standard output.
+ -e
+ Print all (including spurious) errors.
+ -l
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different from gofmt's, print its name
+ to standard output.
+ -r rule
+ Apply the rewrite rule to the source before reformatting.
+ -s
+ Try to simplify code (after applying the rewrite rule, if any).
+ -w
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different from gofmt's, overwrite it
+ with gofmt's version. If an error occurred during overwriting,
+ 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
+
+Both pattern and replacement must be valid Go expressions.
+In the pattern, single-character lowercase identifiers serve as
+wildcards matching arbitrary sub-expressions; those expressions
+will be substituted for the same identifiers in the replacement.
+
+When gofmt reads from standard input, it accepts either a full Go program
+or a program fragment. A program fragment must be a syntactically
+valid declaration list, statement list, or expression. When formatting
+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
+
+To check files for unnecessary parentheses:
+
+ gofmt -r '(a) -> a' -l *.go
+
+To remove the parentheses:
+
+ gofmt -r '(a) -> a' -w *.go
+
+To convert the package tree from explicit slice upper bounds to implicit ones:
+
+ gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src
+
+# The simplify command
+
+When invoked with -s gofmt will make the following source transformations where possible.
+
+ An array, slice, or map composite literal of the form:
+ []T{T{}, T{}}
+ will be simplified to:
+ []T{{}, {}}
+
+ A slice expression of the form:
+ s[a:len(s)]
+ will be simplified to:
+ s[a:]
+
+ A range of the form:
+ for x, _ = range v {...}
+ will be simplified to:
+ for x = range v {...}
+
+ A range of the form:
+ for _ = range v {...}
+ will be simplified to:
+ for range v {...}
+
+This may result in changes that are incompatible with earlier versions of Go.
+*/
+package main
+
+// BUG(rsc): The implementation of -r is a bit slow.
+// BUG(gri): If -w fails, the restored original file may not have some of the
+// original file attributes.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
new file mode 100644
index 0000000..f4fb6bf
--- /dev/null
+++ b/src/cmd/gofmt/gofmt.go
@@ -0,0 +1,570 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "go/scanner"
+ "go/token"
+ "internal/diff"
+ "io"
+ "io/fs"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "runtime"
+ "runtime/pprof"
+ "strconv"
+ "strings"
+
+ "golang.org/x/sync/semaphore"
+)
+
+var (
+ // main operation modes
+ 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("cpuprofile", "", "write cpu profile to this file")
+)
+
+// Keep these in sync with go/format/format.go.
+const (
+ tabWidth = 8
+ printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers
+
+ // printerNormalizeNumbers means to canonicalize number literal prefixes
+ // and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
+ //
+ // This value is defined in go/printer specifically for go/format and cmd/gofmt.
+ printerNormalizeNumbers = 1 << 30
+)
+
+// fdSem guards the number of concurrently-open file descriptors.
+//
+// For now, this is arbitrarily set to 200, based on the observation that many
+// platforms default to a kernel limit of 256. Ideally, perhaps we should derive
+// it from rlimit on platforms that support that system call.
+//
+// File descriptors opened from outside of this package are not tracked,
+// so this limit may be approximate.
+var fdSem = make(chan bool, 200)
+
+var (
+ rewrite func(*token.FileSet, *ast.File) *ast.File
+ parserMode parser.Mode
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
+ flag.PrintDefaults()
+}
+
+func initParserMode() {
+ parserMode = parser.ParseComments
+ 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 {
+ // ignore non-Go files
+ name := f.Name()
+ return !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && !f.IsDir()
+}
+
+// A sequencer performs concurrent tasks that may write output, but emits that
+// output in a deterministic order.
+type sequencer struct {
+ maxWeight int64
+ sem *semaphore.Weighted // weighted by input bytes (an approximate proxy for memory overhead)
+ prev <-chan *reporterState // 1-buffered
+}
+
+// newSequencer returns a sequencer that allows concurrent tasks up to maxWeight
+// and writes tasks' output to out and err.
+func newSequencer(maxWeight int64, out, err io.Writer) *sequencer {
+ sem := semaphore.NewWeighted(maxWeight)
+ prev := make(chan *reporterState, 1)
+ prev <- &reporterState{out: out, err: err}
+ return &sequencer{
+ maxWeight: maxWeight,
+ sem: sem,
+ prev: prev,
+ }
+}
+
+// exclusive is a weight that can be passed to a sequencer to cause
+// a task to be executed without any other concurrent tasks.
+const exclusive = -1
+
+// Add blocks until the sequencer has enough weight to spare, then adds f as a
+// task to be executed concurrently.
+//
+// If the weight is either negative or larger than the sequencer's maximum
+// weight, Add blocks until all other tasks have completed, then the task
+// executes exclusively (blocking all other calls to Add until it completes).
+//
+// f may run concurrently in a goroutine, but its output to the passed-in
+// reporter will be sequential relative to the other tasks in the sequencer.
+//
+// If f invokes a method on the reporter, execution of that method may block
+// until the previous task has finished. (To maximize concurrency, f should
+// avoid invoking the reporter until it has finished any parallelizable work.)
+//
+// If f returns a non-nil error, that error will be reported after f's output
+// (if any) and will cause a nonzero final exit code.
+func (s *sequencer) Add(weight int64, f func(*reporter) error) {
+ if weight < 0 || weight > s.maxWeight {
+ weight = s.maxWeight
+ }
+ if err := s.sem.Acquire(context.TODO(), weight); err != nil {
+ // Change the task from "execute f" to "report err".
+ weight = 0
+ f = func(*reporter) error { return err }
+ }
+
+ r := &reporter{prev: s.prev}
+ next := make(chan *reporterState, 1)
+ s.prev = next
+
+ // Start f in parallel: it can run until it invokes a method on r, at which
+ // point it will block until the previous task releases the output state.
+ go func() {
+ if err := f(r); err != nil {
+ r.Report(err)
+ }
+ next <- r.getState() // Release the next task.
+ s.sem.Release(weight)
+ }()
+}
+
+// AddReport prints an error to s after the output of any previously-added
+// tasks, causing the final exit code to be nonzero.
+func (s *sequencer) AddReport(err error) {
+ s.Add(0, func(*reporter) error { return err })
+}
+
+// GetExitCode waits for all previously-added tasks to complete, then returns an
+// exit code for the sequence suitable for passing to os.Exit.
+func (s *sequencer) GetExitCode() int {
+ c := make(chan int, 1)
+ s.Add(0, func(r *reporter) error {
+ c <- r.ExitCode()
+ return nil
+ })
+ return <-c
+}
+
+// A reporter reports output, warnings, and errors.
+type reporter struct {
+ prev <-chan *reporterState
+ state *reporterState
+}
+
+// reporterState carries the state of a reporter instance.
+//
+// Only one reporter at a time may have access to a reporterState.
+type reporterState struct {
+ out, err io.Writer
+ exitCode int
+}
+
+// getState blocks until any prior reporters are finished with the reporter
+// state, then returns the state for manipulation.
+func (r *reporter) getState() *reporterState {
+ if r.state == nil {
+ r.state = <-r.prev
+ }
+ return r.state
+}
+
+// Warnf emits a warning message to the reporter's error stream,
+// without changing its exit code.
+func (r *reporter) Warnf(format string, args ...any) {
+ fmt.Fprintf(r.getState().err, format, args...)
+}
+
+// Write emits a slice to the reporter's output stream.
+//
+// Any error is returned to the caller, and does not otherwise affect the
+// reporter's exit code.
+func (r *reporter) Write(p []byte) (int, error) {
+ return r.getState().out.Write(p)
+}
+
+// Report emits a non-nil error to the reporter's error stream,
+// changing its exit code to a nonzero value.
+func (r *reporter) Report(err error) {
+ if err == nil {
+ panic("Report with nil error")
+ }
+ st := r.getState()
+ scanner.PrintError(st.err, err)
+ st.exitCode = 2
+}
+
+func (r *reporter) ExitCode() int {
+ return r.getState().exitCode
+}
+
+// If info == nil, we are formatting stdin instead of a file.
+// If in == nil, the source is the contents of the file with the given filename.
+func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) error {
+ src, err := readFile(filename, info, in)
+ if err != nil {
+ return err
+ }
+
+ fileSet := token.NewFileSet()
+ // 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
+ }
+
+ if rewrite != nil {
+ if sourceAdj == nil {
+ file = rewrite(fileSet, file)
+ } else {
+ r.Warnf("warning: rewrite ignored for incomplete programs\n")
+ }
+ }
+
+ ast.SortImports(fileSet, file)
+
+ if *simplifyAST {
+ simplify(file)
+ }
+
+ res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
+ if err != nil {
+ return err
+ }
+
+ if !bytes.Equal(src, res) {
+ // formatting has changed
+ if *list {
+ fmt.Fprintln(r, filename)
+ }
+ if *write {
+ if info == nil {
+ panic("-w should not have been allowed with stdin")
+ }
+
+ perm := info.Mode().Perm()
+ if err := writeFile(filename, src, res, perm, info.Size()); err != nil {
+ return err
+ }
+ }
+ if *doDiff {
+ newName := filepath.ToSlash(filename)
+ oldName := newName + ".orig"
+ r.Write(diff.Diff(oldName, src, newName, res))
+ }
+ }
+
+ if !*list && !*write && !*doDiff {
+ _, err = r.Write(res)
+ }
+
+ return err
+}
+
+// readFile reads the contents of filename, described by info.
+// If in is non-nil, readFile reads directly from it.
+// Otherwise, readFile opens and reads the file itself,
+// with the number of concurrently-open files limited by fdSem.
+func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) {
+ if in == nil {
+ fdSem <- true
+ var err error
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ in = f
+ defer func() {
+ f.Close()
+ <-fdSem
+ }()
+ }
+
+ // Compute the file's size and read its contents with minimal allocations.
+ //
+ // If we have the FileInfo from filepath.WalkDir, use it to make
+ // a buffer of the right size and avoid ReadAll's reallocations.
+ //
+ // If the size is unknown (or bogus, or overflows an int), fall back to
+ // a size-independent ReadAll.
+ size := -1
+ if info != nil && info.Mode().IsRegular() && int64(int(info.Size())) == info.Size() {
+ size = int(info.Size())
+ }
+ if size+1 <= 0 {
+ // The file is not known to be regular, so we don't have a reliable size for it.
+ var err error
+ src, err := io.ReadAll(in)
+ if err != nil {
+ return nil, err
+ }
+ return src, nil
+ }
+
+ // We try to read size+1 bytes so that we can detect modifications: if we
+ // read more than size bytes, then the file was modified concurrently.
+ // (If that happens, we could, say, append to src to finish the read, or
+ // proceed with a truncated buffer — but the fact that it changed at all
+ // indicates a possible race with someone editing the file, so we prefer to
+ // stop to avoid corrupting it.)
+ src := make([]byte, size+1)
+ n, err := io.ReadFull(in, src)
+ 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 {
+ return nil, fmt.Errorf("error: size of %s changed during reading (from %d to %d bytes)", filename, size, n)
+ } else if n > size {
+ return nil, fmt.Errorf("error: size of %s changed during reading (from %d to >=%d bytes)", filename, size, len(src))
+ }
+ return src[:n], nil
+}
+
+func main() {
+ // Arbitrarily limit in-flight work to 2MiB times the number of threads.
+ //
+ // The actual overhead for the parse tree and output will depend on the
+ // specifics of the file, but this at least keeps the footprint of the process
+ // roughly proportional to GOMAXPROCS.
+ maxWeight := (2 << 20) * int64(runtime.GOMAXPROCS(0))
+ s := newSequencer(maxWeight, os.Stdout, os.Stderr)
+
+ // call gofmtMain in a separate function
+ // so that it can use defer and have them
+ // run before the exit.
+ gofmtMain(s)
+ os.Exit(s.GetExitCode())
+}
+
+func gofmtMain(s *sequencer) {
+ flag.Usage = usage
+ flag.Parse()
+
+ if *cpuprofile != "" {
+ fdSem <- true
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ s.AddReport(fmt.Errorf("creating cpu profile: %s", err))
+ return
+ }
+ defer func() {
+ f.Close()
+ <-fdSem
+ }()
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+ }
+
+ initParserMode()
+ initRewrite()
+
+ args := flag.Args()
+ if len(args) == 0 {
+ if *write {
+ s.AddReport(fmt.Errorf("error: cannot use -w with standard input"))
+ return
+ }
+ s.Add(0, func(r *reporter) error {
+ return processFile("<standard input>", nil, os.Stdin, r)
+ })
+ return
+ }
+
+ for _, arg := range args {
+ switch info, err := os.Stat(arg); {
+ case err != nil:
+ s.AddReport(err)
+ case !info.IsDir():
+ // Non-directory arguments are always formatted.
+ arg := arg
+ s.Add(fileWeight(arg, info), func(r *reporter) error {
+ return processFile(arg, info, nil, r)
+ })
+ default:
+ // Directories are walked, ignoring non-Go files.
+ err := filepath.WalkDir(arg, func(path string, f fs.DirEntry, err error) error {
+ if err != nil || !isGoFile(f) {
+ return err
+ }
+ info, err := f.Info()
+ if err != nil {
+ s.AddReport(err)
+ return nil
+ }
+ s.Add(fileWeight(path, info), func(r *reporter) error {
+ return processFile(path, info, nil, r)
+ })
+ return nil
+ })
+ if err != nil {
+ s.AddReport(err)
+ }
+ }
+ }
+}
+
+func fileWeight(path string, info fs.FileInfo) int64 {
+ if info == nil {
+ return exclusive
+ }
+ if info.Mode().Type() == fs.ModeSymlink {
+ var err error
+ info, err = os.Stat(path)
+ if err != nil {
+ return exclusive
+ }
+ }
+ if !info.Mode().IsRegular() {
+ // For non-regular files, FileInfo.Size is system-dependent and thus not a
+ // reliable indicator of weight.
+ return exclusive
+ }
+ return info.Size()
+}
+
+// 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
+ }
+
+ 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)
+ }
+
+ 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
+// the chosen file name.
+func backupFile(filename string, data []byte, perm fs.FileMode) (string, error) {
+ fdSem <- true
+ defer func() { <-fdSem }()
+
+ nextRandom := func() string {
+ return strconv.Itoa(rand.Int())
+ }
+
+ 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)
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+
+ return bakname, err
+}
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
new file mode 100644
index 0000000..6b80673
--- /dev/null
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -0,0 +1,195 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "internal/diff"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "text/scanner"
+)
+
+var update = flag.Bool("update", false, "update .golden files")
+
+// gofmtFlags looks for a comment of the form
+//
+// //gofmt flags
+//
+// within the first maxLines lines of the given file,
+// and returns the flags string, if any. Otherwise it
+// returns the empty string.
+func gofmtFlags(filename string, maxLines int) string {
+ f, err := os.Open(filename)
+ if err != nil {
+ return "" // ignore errors - they will be found later
+ }
+ defer f.Close()
+
+ // initialize scanner
+ var s scanner.Scanner
+ s.Init(f)
+ s.Error = func(*scanner.Scanner, string) {} // ignore errors
+ s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
+
+ // look for //gofmt comment
+ for s.Line <= maxLines {
+ switch s.Scan() {
+ case scanner.Comment:
+ const prefix = "//gofmt "
+ if t := s.TokenText(); strings.HasPrefix(t, prefix) {
+ return strings.TrimSpace(t[len(prefix):])
+ }
+ case scanner.EOF:
+ return ""
+ }
+ }
+
+ return ""
+}
+
+func runTest(t *testing.T, in, out string) {
+ // process flags
+ *simplifyAST = false
+ *rewriteRule = ""
+ info, err := os.Lstat(in)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
+ elts := strings.SplitN(flag, "=", 2)
+ name := elts[0]
+ value := ""
+ if len(elts) == 2 {
+ value = elts[1]
+ }
+ switch name {
+ case "":
+ // no flags
+ case "-r":
+ *rewriteRule = value
+ case "-s":
+ *simplifyAST = true
+ case "-stdin":
+ // fake flag - pretend input is from stdin
+ info = nil
+ default:
+ t.Errorf("unrecognized flag name: %s", name)
+ }
+ }
+
+ initParserMode()
+ initRewrite()
+
+ const maxWeight = 2 << 20
+ var buf, errBuf bytes.Buffer
+ s := newSequencer(maxWeight, &buf, &errBuf)
+ s.Add(fileWeight(in, info), func(r *reporter) error {
+ return processFile(in, info, nil, r)
+ })
+ if errBuf.Len() > 0 {
+ t.Logf("%q", errBuf.Bytes())
+ }
+ if s.GetExitCode() != 0 {
+ t.Fail()
+ }
+
+ expected, err := os.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if got := buf.Bytes(); !bytes.Equal(got, expected) {
+ if *update {
+ if in != out {
+ if err := os.WriteFile(out, got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ // in == out: don't accidentally destroy input
+ t.Errorf("WARNING: -update did not rewrite input file %s", in)
+ }
+
+ t.Errorf("(gofmt %s) != %s (see %s.gofmt)\n%s", in, out, in,
+ diff.Diff("expected", expected, "got", got))
+ if err := os.WriteFile(in+".gofmt", got, 0666); err != nil {
+ t.Error(err)
+ }
+ }
+}
+
+// TestRewrite processes testdata/*.input files and compares them to the
+// corresponding testdata/*.golden files. The gofmt flags used to process
+// a file must be provided via a comment of the form
+//
+// //gofmt flags
+//
+// in the processed file within the first 20 lines, if any.
+func TestRewrite(t *testing.T) {
+ // determine input files
+ match, err := filepath.Glob("testdata/*.input")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // add larger examples
+ match = append(match, "gofmt.go", "gofmt_test.go")
+
+ for _, in := range match {
+ name := filepath.Base(in)
+ t.Run(name, func(t *testing.T) {
+ out := in // for files where input and output are identical
+ if strings.HasSuffix(in, ".input") {
+ out = in[:len(in)-len(".input")] + ".golden"
+ }
+ runTest(t, in, out)
+ if in != out && !t.Failed() {
+ // Check idempotence.
+ runTest(t, out, out)
+ }
+ })
+ }
+}
+
+// Test case for issue 3961.
+func TestCRLF(t *testing.T) {
+ const input = "testdata/crlf.input" // must contain CR/LF's
+ const golden = "testdata/crlf.golden" // must not contain any CR's
+
+ data, err := os.ReadFile(input)
+ if err != nil {
+ t.Error(err)
+ }
+ if !bytes.Contains(data, []byte("\r\n")) {
+ t.Errorf("%s contains no CR/LF's", input)
+ }
+
+ data, err = os.ReadFile(golden)
+ if err != nil {
+ t.Error(err)
+ }
+ if bytes.Contains(data, []byte("\r")) {
+ t.Errorf("%s contains CR's", golden)
+ }
+}
+
+func TestBackupFile(t *testing.T) {
+ dir, err := os.MkdirTemp("", "gofmt_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ name, err := backupFile(filepath.Join(dir, "foo.go"), []byte(" package main"), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Created: %s", name)
+}
diff --git a/src/cmd/gofmt/gofmt_unix_test.go b/src/cmd/gofmt/gofmt_unix_test.go
new file mode 100644
index 0000000..fec5143
--- /dev/null
+++ b/src/cmd/gofmt/gofmt_unix_test.go
@@ -0,0 +1,67 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+package main
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestPermissions(t *testing.T) {
+ if os.Getuid() == 0 {
+ t.Skip("skipping permission test when running as root")
+ }
+
+ dir := t.TempDir()
+ fn := filepath.Join(dir, "perm.go")
+
+ // Create a file that needs formatting without write permission.
+ if err := os.WriteFile(filepath.Join(fn), []byte(" package main"), 0o400); err != nil {
+ t.Fatal(err)
+ }
+
+ // Set mtime of the file in the past.
+ past := time.Now().Add(-time.Hour)
+ if err := os.Chtimes(fn, past, past); err != nil {
+ t.Fatal(err)
+ }
+
+ info, err := os.Stat(fn)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer func() { *write = false }()
+ *write = true
+
+ initParserMode()
+ initRewrite()
+
+ const maxWeight = 2 << 20
+ var buf, errBuf strings.Builder
+ s := newSequencer(maxWeight, &buf, &errBuf)
+ s.Add(fileWeight(fn, info), func(r *reporter) error {
+ return processFile(fn, info, nil, r)
+ })
+ if s.GetExitCode() == 0 {
+ t.Fatal("rewrite of read-only file succeeded unexpectedly")
+ }
+ if errBuf.Len() > 0 {
+ t.Log(errBuf)
+ }
+
+ info, err = os.Stat(fn)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !info.ModTime().Equal(past) {
+ t.Errorf("after rewrite mod time is %v, want %v", info.ModTime(), past)
+ }
+}
diff --git a/src/cmd/gofmt/internal.go b/src/cmd/gofmt/internal.go
new file mode 100644
index 0000000..058158a
--- /dev/null
+++ b/src/cmd/gofmt/internal.go
@@ -0,0 +1,176 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(gri): This file and the file src/go/format/internal.go are
+// the same (but for this comment and the package name). Do not modify
+// one without the other. Determine if we can factor out functionality
+// in a public API. See also #11844 for context.
+
+package main
+
+import (
+ "bytes"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "strings"
+)
+
+// parse parses src, which was read from the named file,
+// as a Go source file, declaration, or statement list.
+func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
+ file *ast.File,
+ sourceAdj func(src []byte, indent int) []byte,
+ indentAdj int,
+ err error,
+) {
+ // Try as whole source file.
+ file, err = parser.ParseFile(fset, filename, src, parserMode)
+ // If there's no error, return. If the error is that the source file didn't begin with a
+ // package line and source fragments are ok, fall through to
+ // try as a source fragment. Stop and return on any other error.
+ if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
+ return
+ }
+
+ // If this is a declaration list, make it a source file
+ // by inserting a package clause.
+ // Insert using a ';', not a newline, so that the line numbers
+ // in psrc match the ones in src.
+ psrc := append([]byte("package p;"), src...)
+ file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+ if err == nil {
+ sourceAdj = func(src []byte, indent int) []byte {
+ // Remove the package clause.
+ // Gofmt has turned the ';' into a '\n'.
+ src = src[indent+len("package p\n"):]
+ return bytes.TrimSpace(src)
+ }
+ return
+ }
+ // If the error is that the source file didn't begin with a
+ // declaration, fall through to try as a statement list.
+ // Stop and return on any other error.
+ if !strings.Contains(err.Error(), "expected declaration") {
+ return
+ }
+
+ // If this is a statement list, make it a source file
+ // by inserting a package clause and turning the list
+ // into a function body. This handles expressions too.
+ // Insert using a ';', not a newline, so that the line numbers
+ // in fsrc match the ones in src. Add an extra '\n' before the '}'
+ // to make sure comments are flushed before the '}'.
+ fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\n', '}')
+ file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+ if err == nil {
+ sourceAdj = func(src []byte, indent int) []byte {
+ // Cap adjusted indent to zero.
+ if indent < 0 {
+ indent = 0
+ }
+ // Remove the wrapping.
+ // Gofmt has turned the "; " into a "\n\n".
+ // There will be two non-blank lines with indent, hence 2*indent.
+ src = src[2*indent+len("package p\n\nfunc _() {"):]
+ // Remove only the "}\n" suffix: remaining whitespaces will be trimmed anyway
+ src = src[:len(src)-len("}\n")]
+ return bytes.TrimSpace(src)
+ }
+ // Gofmt has also indented the function body one level.
+ // Adjust that with indentAdj.
+ indentAdj = -1
+ }
+
+ // Succeeded, or out of options.
+ return
+}
+
+// format formats the given package file originally obtained from src
+// and adjusts the result based on the original source via sourceAdj
+// and indentAdj.
+func format(
+ fset *token.FileSet,
+ file *ast.File,
+ sourceAdj func(src []byte, indent int) []byte,
+ indentAdj int,
+ src []byte,
+ cfg printer.Config,
+) ([]byte, error) {
+ if sourceAdj == nil {
+ // Complete source file.
+ var buf bytes.Buffer
+ err := cfg.Fprint(&buf, fset, file)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+ }
+
+ // Partial source file.
+ // Determine and prepend leading space.
+ i, j := 0, 0
+ for j < len(src) && isSpace(src[j]) {
+ if src[j] == '\n' {
+ i = j + 1 // byte offset of last line in leading space
+ }
+ j++
+ }
+ var res []byte
+ res = append(res, src[:i]...)
+
+ // Determine and prepend indentation of first code line.
+ // Spaces are ignored unless there are no tabs,
+ // in which case spaces count as one tab.
+ indent := 0
+ hasSpace := false
+ for _, b := range src[i:j] {
+ switch b {
+ case ' ':
+ hasSpace = true
+ case '\t':
+ indent++
+ }
+ }
+ if indent == 0 && hasSpace {
+ indent = 1
+ }
+ for i := 0; i < indent; i++ {
+ res = append(res, '\t')
+ }
+
+ // Format the source.
+ // Write it without any leading and trailing space.
+ cfg.Indent = indent + indentAdj
+ var buf bytes.Buffer
+ err := cfg.Fprint(&buf, fset, file)
+ if err != nil {
+ return nil, err
+ }
+ out := sourceAdj(buf.Bytes(), cfg.Indent)
+
+ // If the adjusted output is empty, the source
+ // was empty but (possibly) for white space.
+ // The result is the incoming source.
+ if len(out) == 0 {
+ return src, nil
+ }
+
+ // Otherwise, append output to leading space.
+ res = append(res, out...)
+
+ // Determine and append trailing space.
+ i = len(src)
+ for i > 0 && isSpace(src[i-1]) {
+ i--
+ }
+ return append(res, src[i:]...), nil
+}
+
+// isSpace reports whether the byte is a space character.
+// isSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'.
+func isSpace(b byte) bool {
+ return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
new file mode 100644
index 0000000..8db348a
--- /dev/null
+++ b/src/cmd/gofmt/long_test.go
@@ -0,0 +1,185 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test applies gofmt to all Go files under -root.
+// To test specific files provide a list of comma-separated
+// filenames via the -files flag: go test -files=gofmt.go .
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "internal/testenv"
+ "io"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var (
+ root = flag.String("root", runtime.GOROOT(), "test root directory")
+ files = flag.String("files", "", "comma-separated list of files to test")
+ ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used")
+ verbose = flag.Bool("verbose", false, "verbose mode")
+ nfiles int // number of files processed
+)
+
+func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
+ f, _, _, err := parse(fset, filename, src.Bytes(), false)
+ if err != nil {
+ return err
+ }
+ ast.SortImports(fset, f)
+ src.Reset()
+ return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f)
+}
+
+func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
+ // open file
+ f, err := os.Open(filename)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // read file
+ b1.Reset()
+ _, err = io.Copy(b1, f)
+ f.Close()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // exclude files w/ syntax errors (typically test cases)
+ fset := token.NewFileSet()
+ if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
+ if *verbose {
+ fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
+ }
+ return
+ }
+
+ // gofmt file
+ if err = gofmt(fset, filename, b1); err != nil {
+ t.Errorf("1st gofmt failed: %v", err)
+ return
+ }
+
+ // make a copy of the result
+ b2.Reset()
+ b2.Write(b1.Bytes())
+
+ // gofmt result again
+ if err = gofmt(fset, filename, b2); err != nil {
+ t.Errorf("2nd gofmt failed: %v", err)
+ return
+ }
+
+ // the first and 2nd result should be identical
+ if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
+ // A known instance of gofmt not being idempotent
+ // (see Issue #24472)
+ if strings.HasSuffix(filename, "issue22662.go") {
+ t.Log("known gofmt idempotency bug (Issue #24472)")
+ return
+ }
+ t.Errorf("gofmt %s not idempotent", filename)
+ }
+}
+
+func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
+ b1 := new(bytes.Buffer)
+ b2 := new(bytes.Buffer)
+ for filename := range filenames {
+ testFile(t, b1, b2, filename)
+ }
+ done <- 0
+}
+
+func genFilenames(t *testing.T, filenames chan<- string) {
+ defer close(filenames)
+
+ handleFile := func(filename string, d fs.DirEntry, err error) error {
+ if err != nil {
+ t.Error(err)
+ return nil
+ }
+ // don't descend into testdata directories
+ if isGoFile(d) && !strings.Contains(filepath.ToSlash(filename), "/testdata/") {
+ filenames <- filename
+ nfiles++
+ }
+ return nil
+ }
+
+ // test Go files provided via -files, if any
+ if *files != "" {
+ for _, filename := range strings.Split(*files, ",") {
+ fi, err := os.Stat(filename)
+ handleFile(filename, &statDirEntry{fi}, err)
+ }
+ return // ignore files under -root
+ }
+
+ // otherwise, test all Go files under *root
+ goroot := *root
+ if goroot == "" {
+ goroot = testenv.GOROOT(t)
+ }
+ filepath.WalkDir(goroot, handleFile)
+}
+
+func TestAll(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ if *ngo < 1 {
+ *ngo = 1 // make sure test is run
+ }
+ if *verbose {
+ fmt.Printf("running test using %d goroutines\n", *ngo)
+ }
+
+ // generate filenames
+ filenames := make(chan string, 32)
+ go genFilenames(t, filenames)
+
+ // launch test goroutines
+ done := make(chan int)
+ for i := 0; i < *ngo; i++ {
+ go testFiles(t, filenames, done)
+ }
+
+ // wait for all test goroutines to complete
+ for i := 0; i < *ngo; i++ {
+ <-done
+ }
+
+ if *verbose {
+ fmt.Printf("processed %d files\n", nfiles)
+ }
+}
+
+type statDirEntry struct {
+ info fs.FileInfo
+}
+
+func (d *statDirEntry) Name() string { return d.info.Name() }
+func (d *statDirEntry) IsDir() bool { return d.info.IsDir() }
+func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() }
+func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil }
+
+func (d *statDirEntry) String() string {
+ return fs.FormatDirEntry(d)
+}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
new file mode 100644
index 0000000..0b7e211
--- /dev/null
+++ b/src/cmd/gofmt/rewrite.go
@@ -0,0 +1,311 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+func initRewrite() {
+ if *rewriteRule == "" {
+ rewrite = nil // disable any previous rewrite
+ return
+ }
+ f := strings.Split(*rewriteRule, "->")
+ if len(f) != 2 {
+ fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
+ os.Exit(2)
+ }
+ pattern := parseExpr(f[0], "pattern")
+ replace := parseExpr(f[1], "replacement")
+ rewrite = func(fset *token.FileSet, p *ast.File) *ast.File {
+ return rewriteFile(fset, pattern, replace, p)
+ }
+}
+
+// parseExpr parses s as an expression.
+// It might make sense to expand this to allow statement patterns,
+// but there are problems with preserving formatting and also
+// with what a wildcard for a statement looks like.
+func parseExpr(s, what string) ast.Expr {
+ x, err := parser.ParseExpr(s)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
+ os.Exit(2)
+ }
+ return x
+}
+
+// Keep this function for debugging.
+/*
+func dump(msg string, val reflect.Value) {
+ fmt.Printf("%s:\n", msg)
+ ast.Print(fileSet, val.Interface())
+ fmt.Println()
+}
+*/
+
+// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
+func rewriteFile(fileSet *token.FileSet, pattern, replace ast.Expr, p *ast.File) *ast.File {
+ cmap := ast.NewCommentMap(fileSet, p, p.Comments)
+ m := make(map[string]reflect.Value)
+ pat := reflect.ValueOf(pattern)
+ repl := reflect.ValueOf(replace)
+
+ var rewriteVal func(val reflect.Value) reflect.Value
+ rewriteVal = func(val reflect.Value) reflect.Value {
+ // don't bother if val is invalid to start with
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+ val = apply(rewriteVal, val)
+ for k := range m {
+ delete(m, k)
+ }
+ if match(m, pat, val) {
+ val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
+ }
+ return val
+ }
+
+ r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
+ r.Comments = cmap.Filter(r).Comments() // recreate comments list
+ return r
+}
+
+// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
+func set(x, y reflect.Value) {
+ // don't bother if x cannot be set or y is invalid
+ if !x.CanSet() || !y.IsValid() {
+ return
+ }
+ defer func() {
+ if x := recover(); x != nil {
+ if s, ok := x.(string); ok &&
+ (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
+ // x cannot be set to y - ignore this rewrite
+ return
+ }
+ panic(x)
+ }
+ }()
+ x.Set(y)
+}
+
+// Values/types for special cases.
+var (
+ objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
+ scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
+
+ identType = reflect.TypeOf((*ast.Ident)(nil))
+ objectPtrType = reflect.TypeOf((*ast.Object)(nil))
+ positionType = reflect.TypeOf(token.NoPos)
+ callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
+ scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
+)
+
+// apply replaces each AST field x in val with f(x), returning val.
+// To avoid extra conversions, f operates on the reflect.Value form.
+func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+
+ // *ast.Objects introduce cycles and are likely incorrect after
+ // rewrite; don't follow them but replace with nil instead
+ if val.Type() == objectPtrType {
+ return objectPtrNil
+ }
+
+ // similarly for scopes: they are likely incorrect after a rewrite;
+ // replace them with nil
+ if val.Type() == scopePtrType {
+ return scopePtrNil
+ }
+
+ switch v := reflect.Indirect(val); v.Kind() {
+ case reflect.Slice:
+ for i := 0; i < v.Len(); i++ {
+ e := v.Index(i)
+ set(e, f(e))
+ }
+ case reflect.Struct:
+ for i := 0; i < v.NumField(); i++ {
+ e := v.Field(i)
+ set(e, f(e))
+ }
+ case reflect.Interface:
+ e := v.Elem()
+ set(v, f(e))
+ }
+ return val
+}
+
+func isWildcard(s string) bool {
+ rune, size := utf8.DecodeRuneInString(s)
+ return size == len(s) && unicode.IsLower(rune)
+}
+
+// match reports whether pattern matches val,
+// recording wildcard submatches in m.
+// If m == nil, match checks whether pattern == val.
+func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
+ // Wildcard matches any expression. If it appears multiple
+ // times in the pattern, it must match the same expression
+ // each time.
+ if m != nil && pattern.IsValid() && pattern.Type() == identType {
+ name := pattern.Interface().(*ast.Ident).Name
+ if isWildcard(name) && val.IsValid() {
+ // wildcards only match valid (non-nil) expressions.
+ if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
+ if old, ok := m[name]; ok {
+ return match(nil, old, val)
+ }
+ m[name] = val
+ return true
+ }
+ }
+ }
+
+ // Otherwise, pattern and val must match recursively.
+ if !pattern.IsValid() || !val.IsValid() {
+ return !pattern.IsValid() && !val.IsValid()
+ }
+ if pattern.Type() != val.Type() {
+ return false
+ }
+
+ // Special cases.
+ switch pattern.Type() {
+ case identType:
+ // For identifiers, only the names need to match
+ // (and none of the other *ast.Object information).
+ // This is a common case, handle it all here instead
+ // of recursing down any further via reflection.
+ p := pattern.Interface().(*ast.Ident)
+ v := val.Interface().(*ast.Ident)
+ return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
+ case objectPtrType, positionType:
+ // object pointers and token positions always match
+ return true
+ case callExprType:
+ // For calls, the Ellipsis fields (token.Pos) must
+ // match since that is how f(x) and f(x...) are different.
+ // Check them here but fall through for the remaining fields.
+ p := pattern.Interface().(*ast.CallExpr)
+ v := val.Interface().(*ast.CallExpr)
+ if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
+ return false
+ }
+ }
+
+ p := reflect.Indirect(pattern)
+ v := reflect.Indirect(val)
+ if !p.IsValid() || !v.IsValid() {
+ return !p.IsValid() && !v.IsValid()
+ }
+
+ switch p.Kind() {
+ case reflect.Slice:
+ if p.Len() != v.Len() {
+ return false
+ }
+ for i := 0; i < p.Len(); i++ {
+ if !match(m, p.Index(i), v.Index(i)) {
+ return false
+ }
+ }
+ return true
+
+ case reflect.Struct:
+ for i := 0; i < p.NumField(); i++ {
+ if !match(m, p.Field(i), v.Field(i)) {
+ return false
+ }
+ }
+ return true
+
+ case reflect.Interface:
+ return match(m, p.Elem(), v.Elem())
+ }
+
+ // Handle token integers, etc.
+ return p.Interface() == v.Interface()
+}
+
+// subst returns a copy of pattern with values from m substituted in place
+// of wildcards and pos used as the position of tokens from the pattern.
+// if m == nil, subst returns a copy of pattern and doesn't change the line
+// number information.
+func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
+ if !pattern.IsValid() {
+ return reflect.Value{}
+ }
+
+ // Wildcard gets replaced with map value.
+ if m != nil && pattern.Type() == identType {
+ name := pattern.Interface().(*ast.Ident).Name
+ if isWildcard(name) {
+ if old, ok := m[name]; ok {
+ return subst(nil, old, reflect.Value{})
+ }
+ }
+ }
+
+ if pos.IsValid() && pattern.Type() == positionType {
+ // use new position only if old position was valid in the first place
+ if old := pattern.Interface().(token.Pos); !old.IsValid() {
+ return pattern
+ }
+ return pos
+ }
+
+ // Otherwise copy.
+ switch p := pattern; p.Kind() {
+ case reflect.Slice:
+ if p.IsNil() {
+ // Do not turn nil slices into empty slices. go/ast
+ // guarantees that certain lists will be nil if not
+ // populated.
+ return reflect.Zero(p.Type())
+ }
+ v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
+ for i := 0; i < p.Len(); i++ {
+ v.Index(i).Set(subst(m, p.Index(i), pos))
+ }
+ return v
+
+ case reflect.Struct:
+ v := reflect.New(p.Type()).Elem()
+ for i := 0; i < p.NumField(); i++ {
+ v.Field(i).Set(subst(m, p.Field(i), pos))
+ }
+ return v
+
+ case reflect.Pointer:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(subst(m, elem, pos).Addr())
+ }
+ return v
+
+ case reflect.Interface:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(subst(m, elem, pos))
+ }
+ return v
+ }
+
+ return pattern
+}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
new file mode 100644
index 0000000..eb55daa
--- /dev/null
+++ b/src/cmd/gofmt/simplify.go
@@ -0,0 +1,169 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+ "reflect"
+)
+
+type simplifier struct{}
+
+func (s simplifier) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.CompositeLit:
+ // array, slice, and map composite literals may be simplified
+ outer := n
+ var keyType, eltType ast.Expr
+ switch typ := outer.Type.(type) {
+ case *ast.ArrayType:
+ eltType = typ.Elt
+ case *ast.MapType:
+ keyType = typ.Key
+ eltType = typ.Value
+ }
+
+ if eltType != nil {
+ var ktyp reflect.Value
+ if keyType != nil {
+ ktyp = reflect.ValueOf(keyType)
+ }
+ typ := reflect.ValueOf(eltType)
+ for i, x := range outer.Elts {
+ px := &outer.Elts[i]
+ // look at value of indexed/named elements
+ if t, ok := x.(*ast.KeyValueExpr); ok {
+ if keyType != nil {
+ s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key)
+ }
+ x = t.Value
+ px = &t.Value
+ }
+ s.simplifyLiteral(typ, eltType, x, px)
+ }
+ // node was simplified - stop walk (there are no subnodes to simplify)
+ return nil
+ }
+
+ case *ast.SliceExpr:
+ // a slice expression of the form: s[a:len(s)]
+ // can be simplified to: s[a:]
+ // if s is "simple enough" (for now we only accept identifiers)
+ //
+ // Note: This may not be correct because len may have been redeclared in
+ // the same package. However, this is extremely unlikely and so far
+ // (April 2022, after years of supporting this rewrite feature)
+ // has never come up, so let's keep it working as is (see also #15153).
+ //
+ // Also note that this code used to use go/ast's object tracking,
+ // which was removed in exchange for go/parser.Mode.SkipObjectResolution.
+ // False positives are extremely unlikely as described above,
+ // and go/ast's object tracking is incomplete in any case.
+ if n.Max != nil {
+ // - 3-index slices always require the 2nd and 3rd index
+ break
+ }
+ if s, _ := n.X.(*ast.Ident); s != nil {
+ // the array/slice object is a single identifier
+ if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
+ // the high expression is a function call with a single argument
+ if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" {
+ // the function called is "len"
+ if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Name == s.Name {
+ // the len argument is the array/slice object
+ n.High = nil
+ }
+ }
+ }
+ }
+ // Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
+ // but we leave them as is since sometimes we want to be very explicit
+ // about the lower bound.
+ // An example where the 0 helps:
+ // x, y, z := b[0:2], b[2:4], b[4:6]
+ // An example where it does not:
+ // x, y := b[:n], b[n:]
+
+ case *ast.RangeStmt:
+ // - a range of the form: for x, _ = range v {...}
+ // can be simplified to: for x = range v {...}
+ // - a range of the form: for _ = range v {...}
+ // can be simplified to: for range v {...}
+ if isBlank(n.Value) {
+ n.Value = nil
+ }
+ if isBlank(n.Key) && n.Value == nil {
+ n.Key = nil
+ }
+ }
+
+ return s
+}
+
+func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) {
+ ast.Walk(s, x) // simplify x
+
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.ValueOf(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ // if the outer literal's element type is a pointer type *T
+ // and the element is & of a composite literal of type T,
+ // the inner &T may be omitted.
+ if ptr, ok := astType.(*ast.StarExpr); ok {
+ if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+ if inner, ok := addr.X.(*ast.CompositeLit); ok {
+ if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
+ inner.Type = nil // drop T
+ *px = inner // drop &
+ }
+ }
+ }
+ }
+}
+
+func isBlank(x ast.Expr) bool {
+ ident, ok := x.(*ast.Ident)
+ return ok && ident.Name == "_"
+}
+
+func simplify(f *ast.File) {
+ // remove empty declarations such as "const ()", etc
+ removeEmptyDeclGroups(f)
+
+ var s simplifier
+ ast.Walk(s, f)
+}
+
+func removeEmptyDeclGroups(f *ast.File) {
+ i := 0
+ for _, d := range f.Decls {
+ if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
+ f.Decls[i] = d
+ i++
+ }
+ }
+ f.Decls = f.Decls[:i]
+}
+
+func isEmpty(f *ast.File, g *ast.GenDecl) bool {
+ if g.Doc != nil || g.Specs != nil {
+ return false
+ }
+
+ for _, c := range f.Comments {
+ // if there is a comment in the declaration, it is not considered empty
+ if g.Pos() <= c.Pos() && c.End() <= g.End() {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/src/cmd/gofmt/testdata/comments.golden b/src/cmd/gofmt/testdata/comments.golden
new file mode 100644
index 0000000..ad6bcaf
--- /dev/null
+++ b/src/cmd/gofmt/testdata/comments.golden
@@ -0,0 +1,9 @@
+package main
+
+func main() {}
+
+// comment here
+
+func f() {}
+
+//line foo.go:1
diff --git a/src/cmd/gofmt/testdata/comments.input b/src/cmd/gofmt/testdata/comments.input
new file mode 100644
index 0000000..ad6bcaf
--- /dev/null
+++ b/src/cmd/gofmt/testdata/comments.input
@@ -0,0 +1,9 @@
+package main
+
+func main() {}
+
+// comment here
+
+func f() {}
+
+//line foo.go:1
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
new file mode 100644
index 0000000..a06a69d
--- /dev/null
+++ b/src/cmd/gofmt/testdata/composites.golden
@@ -0,0 +1,218 @@
+//gofmt -s
+
+package P
+
+type T struct {
+ x, y int
+}
+
+type T2 struct {
+ w, z int
+}
+
+var _ = [42]T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [...]T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []T{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []struct {
+ x, y int
+}{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []interface{}{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = [][]int{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [][]int{
+ ([]int{}),
+ ([]int{1, 2}),
+ {3, 4},
+}
+
+var _ = [][][]int{
+ {},
+ {
+ {},
+ {0, 1, 2, 3},
+ {4, 5},
+ },
+}
+
+var _ = map[string]T{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]struct {
+ x, y int
+}{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": ([]int{}),
+ "bar": ([]int{1, 2}),
+ "bal": {3, 4},
+}
+
+// from exp/4s/data.go
+var pieces4 = []Piece{
+ {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+ {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+}
+
+var _ = [42]*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [...]*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*T{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []*struct {
+ x, y int
+}{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []interface{}{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*[]int{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*[]int{
+ (&[]int{}),
+ (&[]int{1, 2}),
+ {3, 4},
+}
+
+var _ = []*[]*[]int{
+ {},
+ {
+ {},
+ {0, 1, 2, 3},
+ {4, 5},
+ },
+}
+
+var _ = map[string]*T{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]*struct {
+ x, y int
+}{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": (&[]int{}),
+ "bar": (&[]int{1, 2}),
+ "bal": {3, 4},
+}
+
+var pieces4 = []*Piece{
+ {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+ {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+}
+
+var _ = map[T]T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
+
+var _ = map[*T]*T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input
new file mode 100644
index 0000000..9d28ac7
--- /dev/null
+++ b/src/cmd/gofmt/testdata/composites.input
@@ -0,0 +1,218 @@
+//gofmt -s
+
+package P
+
+type T struct {
+ x, y int
+}
+
+type T2 struct {
+ w, z int
+}
+
+var _ = [42]T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = [...]T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = []T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = []T{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = []struct {
+ x, y int
+}{
+ struct{ x, y int }{},
+ 10: struct{ x, y int }{1, 2},
+ 20: struct{ x, y int }{3, 4},
+}
+
+var _ = []interface{}{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = [][]int{
+ []int{},
+ []int{1, 2},
+ []int{3, 4},
+}
+
+var _ = [][]int{
+ ([]int{}),
+ ([]int{1, 2}),
+ []int{3, 4},
+}
+
+var _ = [][][]int{
+ [][]int{},
+ [][]int{
+ []int{},
+ []int{0, 1, 2, 3},
+ []int{4, 5},
+ },
+}
+
+var _ = map[string]T{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string]struct {
+ x, y int
+}{
+ "foo": struct{ x, y int }{},
+ "bar": struct{ x, y int }{1, 2},
+ "bal": struct{ x, y int }{3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": []int{},
+ "bar": []int{1, 2},
+ "bal": []int{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": ([]int{}),
+ "bar": ([]int{1, 2}),
+ "bal": []int{3, 4},
+}
+
+// from exp/4s/data.go
+var pieces4 = []Piece{
+ Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+ Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+}
+
+var _ = [42]*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = [...]*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = []*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = []*T{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*struct {
+ x, y int
+}{
+ &struct{ x, y int }{},
+ 10: &struct{ x, y int }{1, 2},
+ 20: &struct{ x, y int }{3, 4},
+}
+
+var _ = []interface{}{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*[]int{
+ &[]int{},
+ &[]int{1, 2},
+ &[]int{3, 4},
+}
+
+var _ = []*[]int{
+ (&[]int{}),
+ (&[]int{1, 2}),
+ &[]int{3, 4},
+}
+
+var _ = []*[]*[]int{
+ &[]*[]int{},
+ &[]*[]int{
+ &[]int{},
+ &[]int{0, 1, 2, 3},
+ &[]int{4, 5},
+ },
+}
+
+var _ = map[string]*T{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*struct {
+ x, y int
+}{
+ "foo": &struct{ x, y int }{},
+ "bar": &struct{ x, y int }{1, 2},
+ "bal": &struct{ x, y int }{3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": &[]int{},
+ "bar": &[]int{1, 2},
+ "bal": &[]int{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": (&[]int{}),
+ "bar": (&[]int{1, 2}),
+ "bal": &[]int{3, 4},
+}
+
+var pieces4 = []*Piece{
+ &Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ &Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+ &Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ &Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+}
+
+var _ = map[T]T2{
+ T{1, 2}: T2{3, 4},
+ T{5, 6}: T2{7, 8},
+}
+
+var _ = map[*T]*T2{
+ &T{1, 2}: &T2{3, 4},
+ &T{5, 6}: &T2{7, 8},
+}
diff --git a/src/cmd/gofmt/testdata/crlf.golden b/src/cmd/gofmt/testdata/crlf.golden
new file mode 100644
index 0000000..65de9cf
--- /dev/null
+++ b/src/cmd/gofmt/testdata/crlf.golden
@@ -0,0 +1,13 @@
+/*
+Source containing CR/LF line endings.
+The gofmt'ed output must only have LF
+line endings.
+Test case for issue 3961.
+*/
+package main
+
+func main() {
+ // line comment
+ println("hello, world!") // another line comment
+ println()
+}
diff --git a/src/cmd/gofmt/testdata/crlf.input b/src/cmd/gofmt/testdata/crlf.input
new file mode 100644
index 0000000..3cd4934
--- /dev/null
+++ b/src/cmd/gofmt/testdata/crlf.input
@@ -0,0 +1,13 @@
+/*
+Source containing CR/LF line endings.
+The gofmt'ed output must only have LF
+line endings.
+Test case for issue 3961.
+*/
+package main
+
+func main() {
+ // line comment
+ println("hello, world!") // another line comment
+ println()
+}
diff --git a/src/cmd/gofmt/testdata/emptydecl.golden b/src/cmd/gofmt/testdata/emptydecl.golden
new file mode 100644
index 0000000..33d6435
--- /dev/null
+++ b/src/cmd/gofmt/testdata/emptydecl.golden
@@ -0,0 +1,14 @@
+//gofmt -s
+
+// Test case for issue 7631.
+
+package main
+
+// Keep this declaration
+var ()
+
+const (
+// Keep this declaration
+)
+
+func main() {}
diff --git a/src/cmd/gofmt/testdata/emptydecl.input b/src/cmd/gofmt/testdata/emptydecl.input
new file mode 100644
index 0000000..4948a61
--- /dev/null
+++ b/src/cmd/gofmt/testdata/emptydecl.input
@@ -0,0 +1,16 @@
+//gofmt -s
+
+// Test case for issue 7631.
+
+package main
+
+// Keep this declaration
+var ()
+
+const (
+// Keep this declaration
+)
+
+type ()
+
+func main() {} \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/go2numbers.golden b/src/cmd/gofmt/testdata/go2numbers.golden
new file mode 100644
index 0000000..0184aaa
--- /dev/null
+++ b/src/cmd/gofmt/testdata/go2numbers.golden
@@ -0,0 +1,186 @@
+package p
+
+const (
+ // 0-octals
+ _ = 0
+ _ = 0123
+ _ = 0123456
+
+ _ = 0_123
+ _ = 0123_456
+
+ // decimals
+ _ = 1
+ _ = 1234
+ _ = 1234567
+
+ _ = 1_234
+ _ = 1_234_567
+
+ // hexadecimals
+ _ = 0x0
+ _ = 0x1234
+ _ = 0xcafef00d
+
+ _ = 0x0
+ _ = 0x1234
+ _ = 0xCAFEf00d
+
+ _ = 0x_0
+ _ = 0x_1234
+ _ = 0x_CAFE_f00d
+
+ // octals
+ _ = 0o0
+ _ = 0o1234
+ _ = 0o01234567
+
+ _ = 0o0
+ _ = 0o1234
+ _ = 0o01234567
+
+ _ = 0o_0
+ _ = 0o_1234
+ _ = 0o0123_4567
+
+ _ = 0o_0
+ _ = 0o_1234
+ _ = 0o0123_4567
+
+ // binaries
+ _ = 0b0
+ _ = 0b1011
+ _ = 0b00101101
+
+ _ = 0b0
+ _ = 0b1011
+ _ = 0b00101101
+
+ _ = 0b_0
+ _ = 0b10_11
+ _ = 0b_0010_1101
+
+ // decimal floats
+ _ = 0.
+ _ = 123.
+ _ = 0123.
+
+ _ = .0
+ _ = .123
+ _ = .0123
+
+ _ = 0e0
+ _ = 123e+0
+ _ = 0123e-1
+
+ _ = 0e-0
+ _ = 123e+0
+ _ = 0123e123
+
+ _ = 0.e+1
+ _ = 123.e-10
+ _ = 0123.e123
+
+ _ = .0e-1
+ _ = .123e+10
+ _ = .0123e123
+
+ _ = 0.0
+ _ = 123.123
+ _ = 0123.0123
+
+ _ = 0.0e1
+ _ = 123.123e-10
+ _ = 0123.0123e+456
+
+ _ = 1_2_3.
+ _ = 0_123.
+
+ _ = 0_0e0
+ _ = 1_2_3e0
+ _ = 0_123e0
+
+ _ = 0e-0_0
+ _ = 1_2_3e+0
+ _ = 0123e1_2_3
+
+ _ = 0.e+1
+ _ = 123.e-1_0
+ _ = 01_23.e123
+
+ _ = .0e-1
+ _ = .123e+10
+ _ = .0123e123
+
+ _ = 1_2_3.123
+ _ = 0123.01_23
+
+ // hexadecimal floats
+ _ = 0x0.p+0
+ _ = 0xdeadcafe.p-10
+ _ = 0x1234.p123
+
+ _ = 0x.1p-0
+ _ = 0x.deadcafep2
+ _ = 0x.1234p+10
+
+ _ = 0x0p0
+ _ = 0xdeadcafep+1
+ _ = 0x1234p-10
+
+ _ = 0x0.0p0
+ _ = 0xdead.cafep+1
+ _ = 0x12.34p-10
+
+ _ = 0xdead_cafep+1
+ _ = 0x_1234p-10
+
+ _ = 0x_dead_cafe.p-10
+ _ = 0x12_34.p1_2_3
+ _ = 0x1_2_3_4.p-1_2_3
+
+ // imaginaries
+ _ = 0i
+ _ = 0i
+ _ = 8i
+ _ = 0i
+ _ = 123i
+ _ = 123i
+ _ = 56789i
+ _ = 1234i
+ _ = 1234567i
+
+ _ = 0i
+ _ = 0i
+ _ = 8i
+ _ = 0i
+ _ = 123i
+ _ = 123i
+ _ = 56_789i
+ _ = 1_234i
+ _ = 1_234_567i
+
+ _ = 0.i
+ _ = 123.i
+ _ = 0123.i
+ _ = 000123.i
+
+ _ = 0e0i
+ _ = 123e0i
+ _ = 0123e0i
+ _ = 000123e0i
+
+ _ = 0.e+1i
+ _ = 123.e-1_0i
+ _ = 01_23.e123i
+ _ = 00_01_23.e123i
+
+ _ = 0b1010i
+ _ = 0b1010i
+ _ = 0o660i
+ _ = 0o660i
+ _ = 0xabcDEFi
+ _ = 0xabcDEFi
+ _ = 0xabcDEFp0i
+ _ = 0xabcDEFp0i
+)
diff --git a/src/cmd/gofmt/testdata/go2numbers.input b/src/cmd/gofmt/testdata/go2numbers.input
new file mode 100644
index 0000000..f3e7828
--- /dev/null
+++ b/src/cmd/gofmt/testdata/go2numbers.input
@@ -0,0 +1,186 @@
+package p
+
+const (
+ // 0-octals
+ _ = 0
+ _ = 0123
+ _ = 0123456
+
+ _ = 0_123
+ _ = 0123_456
+
+ // decimals
+ _ = 1
+ _ = 1234
+ _ = 1234567
+
+ _ = 1_234
+ _ = 1_234_567
+
+ // hexadecimals
+ _ = 0x0
+ _ = 0x1234
+ _ = 0xcafef00d
+
+ _ = 0X0
+ _ = 0X1234
+ _ = 0XCAFEf00d
+
+ _ = 0X_0
+ _ = 0X_1234
+ _ = 0X_CAFE_f00d
+
+ // octals
+ _ = 0o0
+ _ = 0o1234
+ _ = 0o01234567
+
+ _ = 0O0
+ _ = 0O1234
+ _ = 0O01234567
+
+ _ = 0o_0
+ _ = 0o_1234
+ _ = 0o0123_4567
+
+ _ = 0O_0
+ _ = 0O_1234
+ _ = 0O0123_4567
+
+ // binaries
+ _ = 0b0
+ _ = 0b1011
+ _ = 0b00101101
+
+ _ = 0B0
+ _ = 0B1011
+ _ = 0B00101101
+
+ _ = 0b_0
+ _ = 0b10_11
+ _ = 0b_0010_1101
+
+ // decimal floats
+ _ = 0.
+ _ = 123.
+ _ = 0123.
+
+ _ = .0
+ _ = .123
+ _ = .0123
+
+ _ = 0e0
+ _ = 123e+0
+ _ = 0123E-1
+
+ _ = 0e-0
+ _ = 123E+0
+ _ = 0123E123
+
+ _ = 0.e+1
+ _ = 123.E-10
+ _ = 0123.e123
+
+ _ = .0e-1
+ _ = .123E+10
+ _ = .0123E123
+
+ _ = 0.0
+ _ = 123.123
+ _ = 0123.0123
+
+ _ = 0.0e1
+ _ = 123.123E-10
+ _ = 0123.0123e+456
+
+ _ = 1_2_3.
+ _ = 0_123.
+
+ _ = 0_0e0
+ _ = 1_2_3e0
+ _ = 0_123e0
+
+ _ = 0e-0_0
+ _ = 1_2_3E+0
+ _ = 0123E1_2_3
+
+ _ = 0.e+1
+ _ = 123.E-1_0
+ _ = 01_23.e123
+
+ _ = .0e-1
+ _ = .123E+10
+ _ = .0123E123
+
+ _ = 1_2_3.123
+ _ = 0123.01_23
+
+ // hexadecimal floats
+ _ = 0x0.p+0
+ _ = 0Xdeadcafe.p-10
+ _ = 0x1234.P123
+
+ _ = 0x.1p-0
+ _ = 0X.deadcafep2
+ _ = 0x.1234P+10
+
+ _ = 0x0p0
+ _ = 0Xdeadcafep+1
+ _ = 0x1234P-10
+
+ _ = 0x0.0p0
+ _ = 0Xdead.cafep+1
+ _ = 0x12.34P-10
+
+ _ = 0Xdead_cafep+1
+ _ = 0x_1234P-10
+
+ _ = 0X_dead_cafe.p-10
+ _ = 0x12_34.P1_2_3
+ _ = 0X1_2_3_4.P-1_2_3
+
+ // imaginaries
+ _ = 0i
+ _ = 00i
+ _ = 08i
+ _ = 0000000000i
+ _ = 0123i
+ _ = 0000000123i
+ _ = 0000056789i
+ _ = 1234i
+ _ = 1234567i
+
+ _ = 0i
+ _ = 0_0i
+ _ = 0_8i
+ _ = 0_000_000_000i
+ _ = 0_123i
+ _ = 0_000_000_123i
+ _ = 0_000_056_789i
+ _ = 1_234i
+ _ = 1_234_567i
+
+ _ = 0.i
+ _ = 123.i
+ _ = 0123.i
+ _ = 000123.i
+
+ _ = 0e0i
+ _ = 123e0i
+ _ = 0123E0i
+ _ = 000123E0i
+
+ _ = 0.e+1i
+ _ = 123.E-1_0i
+ _ = 01_23.e123i
+ _ = 00_01_23.e123i
+
+ _ = 0b1010i
+ _ = 0B1010i
+ _ = 0o660i
+ _ = 0O660i
+ _ = 0xabcDEFi
+ _ = 0XabcDEFi
+ _ = 0xabcDEFP0i
+ _ = 0XabcDEFp0i
+)
diff --git a/src/cmd/gofmt/testdata/import.golden b/src/cmd/gofmt/testdata/import.golden
new file mode 100644
index 0000000..1125b70
--- /dev/null
+++ b/src/cmd/gofmt/testdata/import.golden
@@ -0,0 +1,194 @@
+// package comment
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+)
+
+import (
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+// We reset the line numbering to test that
+// the formatting works independent of line directives
+//line :19
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ // a block with comments
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ // for Printf
+ "fmt"
+
+ "math"
+
+ // for Fatal
+ "log"
+
+ "errors"
+
+ // for Reader
+ "io"
+)
+
+import (
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "errors"
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+)
+
+// Test deduping and extended sorting
+import (
+ a "A" // aA
+ b "A" // bA1
+ b "A" // bA2
+ "B" // B
+ . "B" // .B
+ _ "B" // _b
+ "C"
+ a "D" // aD
+)
+
+import (
+ "dedup_by_group"
+
+ "dedup_by_group"
+)
+
+import (
+ "fmt" // for Printf
+ /* comment */ io1 "io"
+ /* comment */ io2 "io"
+ /* comment */ "log"
+)
+
+import (
+ "fmt"
+ /* comment */ io1 "io"
+ /* comment */ io2 "io" // hello
+ "math" /* right side */
+ // end
+)
+
+import (
+ "errors" // for New
+ "fmt"
+ /* comment */ io1 "io" /* before */ // after
+ io2 "io" // another
+ // end
+)
+
+import (
+ "errors" // for New
+ /* left */ "fmt" /* right */
+ "log" // for Fatal
+ /* left */ "math" /* right */
+)
+
+import /* why */ /* comment here? */ (
+ /* comment */ "fmt"
+ "math"
+)
+
+// Reset it again
+//line :100
+
+// Dedup with different import styles
+import (
+ "path"
+ . "path"
+ _ "path"
+ pathpkg "path"
+)
+
+/* comment */
+import (
+ "fmt"
+ "math" // for Abs
+ // This is a new run
+ "errors"
+ "fmt"
+)
+
+// End an import declaration in the same line
+// as the last import. See golang.org/issue/33538.
+// Note: Must be the last (or 2nd last) line of the file.
+import (
+ "fmt"
+ "math"
+)
diff --git a/src/cmd/gofmt/testdata/import.input b/src/cmd/gofmt/testdata/import.input
new file mode 100644
index 0000000..040b872
--- /dev/null
+++ b/src/cmd/gofmt/testdata/import.input
@@ -0,0 +1,199 @@
+// package comment
+package main
+
+import (
+ "fmt"
+ "math"
+ "log"
+ "errors"
+ "io"
+)
+
+import (
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+// We reset the line numbering to test that
+// the formatting works independent of line directives
+//line :19
+
+import (
+ "fmt"
+ "math"
+ "log"
+ "errors"
+ "io"
+
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ // a block with comments
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ // for Printf
+ "fmt"
+
+ "math"
+
+ // for Fatal
+ "log"
+
+ "errors"
+
+ // for Reader
+ "io"
+)
+
+import (
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+)
+
+// Test deduping and extended sorting
+import (
+ "B" // B
+ a "A" // aA
+ b "A" // bA2
+ b "A" // bA1
+ . "B" // .B
+ . "B"
+ "C"
+ "C"
+ "C"
+ a "D" // aD
+ "B"
+ _ "B" // _b
+)
+
+import (
+ "dedup_by_group"
+ "dedup_by_group"
+
+ "dedup_by_group"
+)
+
+import (
+ /* comment */ io1 "io"
+ "fmt" // for Printf
+ /* comment */ "log"
+ /* comment */ io2 "io"
+)
+
+import (
+ /* comment */ io2 "io" // hello
+ /* comment */ io1 "io"
+ "math" /* right side */
+ "fmt"
+ // end
+)
+
+import (
+ /* comment */ io1 "io" /* before */ // after
+ "fmt"
+ "errors" // for New
+ io2 "io" // another
+ // end
+)
+
+import (
+ /* left */ "fmt" /* right */
+ "errors" // for New
+ /* left */ "math" /* right */
+ "log" // for Fatal
+)
+
+import /* why */ /* comment here? */ (
+ /* comment */ "fmt"
+ "math"
+)
+
+// Reset it again
+//line :100
+
+// Dedup with different import styles
+import (
+ "path"
+ . "path"
+ _ "path"
+ "path"
+ pathpkg "path"
+)
+
+/* comment */
+import (
+ "math" // for Abs
+ "fmt"
+ // This is a new run
+ "errors"
+ "fmt"
+ "errors"
+)
+
+// End an import declaration in the same line
+// as the last import. See golang.org/issue/33538.
+// Note: Must be the last (or 2nd last) line of the file.
+import("fmt"
+"math") \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/issue28082.golden b/src/cmd/gofmt/testdata/issue28082.golden
new file mode 100644
index 0000000..5837fd5
--- /dev/null
+++ b/src/cmd/gofmt/testdata/issue28082.golden
@@ -0,0 +1,13 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// testcase for issue #28082
+
+func foo() {}
+
+func main() {}
+
+func bar() {}
diff --git a/src/cmd/gofmt/testdata/issue28082.input b/src/cmd/gofmt/testdata/issue28082.input
new file mode 100644
index 0000000..ab7d218
--- /dev/null
+++ b/src/cmd/gofmt/testdata/issue28082.input
@@ -0,0 +1,13 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// testcase for issue #28082
+
+func foo( ) {}
+
+func main( ) {}
+
+func bar() {}
diff --git a/src/cmd/gofmt/testdata/ranges.golden b/src/cmd/gofmt/testdata/ranges.golden
new file mode 100644
index 0000000..506b3a0
--- /dev/null
+++ b/src/cmd/gofmt/testdata/ranges.golden
@@ -0,0 +1,30 @@
+//gofmt -s
+
+// Test cases for range simplification.
+package p
+
+func _() {
+ for a, b = range x {
+ }
+ for a = range x {
+ }
+ for _, b = range x {
+ }
+ for range x {
+ }
+
+ for a = range x {
+ }
+ for range x {
+ }
+
+ for a, b := range x {
+ }
+ for a := range x {
+ }
+ for _, b := range x {
+ }
+
+ for a := range x {
+ }
+}
diff --git a/src/cmd/gofmt/testdata/ranges.input b/src/cmd/gofmt/testdata/ranges.input
new file mode 100644
index 0000000..df5f833
--- /dev/null
+++ b/src/cmd/gofmt/testdata/ranges.input
@@ -0,0 +1,20 @@
+//gofmt -s
+
+// Test cases for range simplification.
+package p
+
+func _() {
+ for a, b = range x {}
+ for a, _ = range x {}
+ for _, b = range x {}
+ for _, _ = range x {}
+
+ for a = range x {}
+ for _ = range x {}
+
+ for a, b := range x {}
+ for a, _ := range x {}
+ for _, b := range x {}
+
+ for a := range x {}
+}
diff --git a/src/cmd/gofmt/testdata/rewrite1.golden b/src/cmd/gofmt/testdata/rewrite1.golden
new file mode 100644
index 0000000..3ee5373
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite1.golden
@@ -0,0 +1,14 @@
+//gofmt -r=Foo->Bar
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Bar int
+
+func main() {
+ var a Bar
+ println(a)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite1.input b/src/cmd/gofmt/testdata/rewrite1.input
new file mode 100644
index 0000000..a84c8f7
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite1.input
@@ -0,0 +1,14 @@
+//gofmt -r=Foo->Bar
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo int
+
+func main() {
+ var a Foo
+ println(a)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite10.golden b/src/cmd/gofmt/testdata/rewrite10.golden
new file mode 100644
index 0000000..1dd781f
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite10.golden
@@ -0,0 +1,19 @@
+//gofmt -r=a->a
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 33103, 33104, and 33105.
+
+package pkg
+
+func fn() {
+ _ = func() {
+ switch {
+ default:
+ }
+ }
+ _ = func() string {}
+ _ = func() { var ptr *string; println(ptr) }
+}
diff --git a/src/cmd/gofmt/testdata/rewrite10.input b/src/cmd/gofmt/testdata/rewrite10.input
new file mode 100644
index 0000000..1dd781f
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite10.input
@@ -0,0 +1,19 @@
+//gofmt -r=a->a
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 33103, 33104, and 33105.
+
+package pkg
+
+func fn() {
+ _ = func() {
+ switch {
+ default:
+ }
+ }
+ _ = func() string {}
+ _ = func() { var ptr *string; println(ptr) }
+}
diff --git a/src/cmd/gofmt/testdata/rewrite2.golden b/src/cmd/gofmt/testdata/rewrite2.golden
new file mode 100644
index 0000000..f980e03
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite2.golden
@@ -0,0 +1,12 @@
+//gofmt -r=int->bool
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// Slices have nil Len values in the corresponding ast.ArrayType
+// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
+// The rewriter must not crash in that case. Was issue 1696.
+func f() []bool {}
diff --git a/src/cmd/gofmt/testdata/rewrite2.input b/src/cmd/gofmt/testdata/rewrite2.input
new file mode 100644
index 0000000..489be4e
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite2.input
@@ -0,0 +1,12 @@
+//gofmt -r=int->bool
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// Slices have nil Len values in the corresponding ast.ArrayType
+// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
+// The rewriter must not crash in that case. Was issue 1696.
+func f() []int {}
diff --git a/src/cmd/gofmt/testdata/rewrite3.golden b/src/cmd/gofmt/testdata/rewrite3.golden
new file mode 100644
index 0000000..261a220
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite3.golden
@@ -0,0 +1,14 @@
+//gofmt -r=x->x
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Field tags are *ast.BasicLit nodes that are nil when the tag is
+// absent. These nil nodes must not be mistaken for expressions,
+// the rewriter should not try to dereference them. Was issue 2410.
+type Foo struct {
+ Field int
+}
diff --git a/src/cmd/gofmt/testdata/rewrite3.input b/src/cmd/gofmt/testdata/rewrite3.input
new file mode 100644
index 0000000..261a220
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite3.input
@@ -0,0 +1,14 @@
+//gofmt -r=x->x
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Field tags are *ast.BasicLit nodes that are nil when the tag is
+// absent. These nil nodes must not be mistaken for expressions,
+// the rewriter should not try to dereference them. Was issue 2410.
+type Foo struct {
+ Field int
+}
diff --git a/src/cmd/gofmt/testdata/rewrite4.golden b/src/cmd/gofmt/testdata/rewrite4.golden
new file mode 100644
index 0000000..b05547b
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite4.golden
@@ -0,0 +1,76 @@
+//gofmt -r=(x)->x
+
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of parenthesized expressions (x) -> x
+// must not drop parentheses if that would lead to
+// wrong association of the operands.
+// Was issue 1847.
+
+package main
+
+// From example 1 of issue 1847.
+func _() {
+ var t = (&T{1000}).Id()
+}
+
+// From example 2 of issue 1847.
+func _() {
+ fmt.Println((*xpp).a)
+}
+
+// Some more test cases.
+func _() {
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+}
diff --git a/src/cmd/gofmt/testdata/rewrite4.input b/src/cmd/gofmt/testdata/rewrite4.input
new file mode 100644
index 0000000..0817099
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite4.input
@@ -0,0 +1,76 @@
+//gofmt -r=(x)->x
+
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of parenthesized expressions (x) -> x
+// must not drop parentheses if that would lead to
+// wrong association of the operands.
+// Was issue 1847.
+
+package main
+
+// From example 1 of issue 1847.
+func _() {
+ var t = (&T{1000}).Id()
+}
+
+// From example 2 of issue 1847.
+func _() {
+ fmt.Println((*xpp).a)
+}
+
+// Some more test cases.
+func _() {
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = (-x.f)
+ _ = (*x.f)
+ _ = (&x.f)
+ _ = (!x.f)
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = (-x.f())
+ _ = (*x.f())
+ _ = (&x.f())
+ _ = (!x.f())
+
+ _ = ((-x)).f
+ _ = ((*x)).f
+ _ = ((&x)).f
+ _ = ((!x)).f
+ _ = ((-x.f))
+ _ = ((*x.f))
+ _ = ((&x.f))
+ _ = ((!x.f))
+ ((-x)).f()
+ ((*x)).f()
+ ((&x)).f()
+ ((!x)).f()
+ _ = ((-x.f()))
+ _ = ((*x.f()))
+ _ = ((&x.f()))
+ _ = ((!x.f()))
+
+ _ = -(x).f
+ _ = *(x).f
+ _ = &(x).f
+ _ = !(x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -(x).f()
+ _ = *(x).f()
+ _ = &(x).f()
+ _ = !(x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+}
diff --git a/src/cmd/gofmt/testdata/rewrite5.golden b/src/cmd/gofmt/testdata/rewrite5.golden
new file mode 100644
index 0000000..9beb34a
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite5.golden
@@ -0,0 +1,17 @@
+//gofmt -r=x+x->2*x
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of expressions containing nodes with associated comments to
+// expressions without those nodes must also eliminate the associated
+// comments.
+
+package p
+
+func f(x int) int {
+ _ = 2 * x // this comment remains in the rewrite
+ _ = 2 * x
+ return 2 * x
+}
diff --git a/src/cmd/gofmt/testdata/rewrite5.input b/src/cmd/gofmt/testdata/rewrite5.input
new file mode 100644
index 0000000..d7a6122
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite5.input
@@ -0,0 +1,17 @@
+//gofmt -r=x+x->2*x
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of expressions containing nodes with associated comments to
+// expressions without those nodes must also eliminate the associated
+// comments.
+
+package p
+
+func f(x int) int {
+ _ = x + x // this comment remains in the rewrite
+ _ = x /* this comment must not be in the rewrite */ + x
+ return x /* this comment must not be in the rewrite */ + x
+}
diff --git a/src/cmd/gofmt/testdata/rewrite6.golden b/src/cmd/gofmt/testdata/rewrite6.golden
new file mode 100644
index 0000000..48ec9aa
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite6.golden
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x)->Fun(x)
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ Fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
+ fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
+}
diff --git a/src/cmd/gofmt/testdata/rewrite6.input b/src/cmd/gofmt/testdata/rewrite6.input
new file mode 100644
index 0000000..b085a84
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite6.input
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x)->Fun(x)
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
+ fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
+}
diff --git a/src/cmd/gofmt/testdata/rewrite7.golden b/src/cmd/gofmt/testdata/rewrite7.golden
new file mode 100644
index 0000000..8386a0b
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite7.golden
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x...)->Fun(x)
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
+ Fun(x) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite7.input b/src/cmd/gofmt/testdata/rewrite7.input
new file mode 100644
index 0000000..c198470
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite7.input
@@ -0,0 +1,17 @@
+//gofmt -r=fun(x...)->Fun(x)
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
+ fun(x...) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite8.golden b/src/cmd/gofmt/testdata/rewrite8.golden
new file mode 100644
index 0000000..62f0419
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite8.golden
@@ -0,0 +1,12 @@
+//gofmt -r=interface{}->int
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that literal type expression rewrites are accepted.
+// Was issue 4406.
+
+package p
+
+type T int
diff --git a/src/cmd/gofmt/testdata/rewrite8.input b/src/cmd/gofmt/testdata/rewrite8.input
new file mode 100644
index 0000000..7964c5c
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite8.input
@@ -0,0 +1,12 @@
+//gofmt -r=interface{}->int
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that literal type expression rewrites are accepted.
+// Was issue 4406.
+
+package p
+
+type T interface{}
diff --git a/src/cmd/gofmt/testdata/rewrite9.golden b/src/cmd/gofmt/testdata/rewrite9.golden
new file mode 100644
index 0000000..fffbd3d
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite9.golden
@@ -0,0 +1,11 @@
+//gofmt -r=a&&b!=2->a
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 18987.
+
+package p
+
+const _ = x != 1
diff --git a/src/cmd/gofmt/testdata/rewrite9.input b/src/cmd/gofmt/testdata/rewrite9.input
new file mode 100644
index 0000000..106ad94
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite9.input
@@ -0,0 +1,11 @@
+//gofmt -r=a&&b!=2->a
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 18987.
+
+package p
+
+const _ = x != 1 && x != 2
diff --git a/src/cmd/gofmt/testdata/slices1.golden b/src/cmd/gofmt/testdata/slices1.golden
new file mode 100644
index 0000000..04bc16f
--- /dev/null
+++ b/src/cmd/gofmt/testdata/slices1.golden
@@ -0,0 +1,66 @@
+//gofmt -s
+
+// Test cases for slice expression simplification.
+package p
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:]
+ _ = a[3:(len(a))]
+ _ = a[len(a) : len(a)-1]
+ _ = a[0:len(b)]
+ _ = a[2:len(a):len(a)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:]
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(b)]
+ _ = a[:len(a):len(a)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:]
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+ _ = s[2:len(s):len(s)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:]
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+ _ = s[:len(s):len(s)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+ _ = t.s[2:len(t.s):len(t.s)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+ _ = t.s[:len(t.s):len(t.s)]
+)
+
+func _() {
+ s := s[0:]
+ _ = s
+}
diff --git a/src/cmd/gofmt/testdata/slices1.input b/src/cmd/gofmt/testdata/slices1.input
new file mode 100644
index 0000000..1f25c43
--- /dev/null
+++ b/src/cmd/gofmt/testdata/slices1.input
@@ -0,0 +1,66 @@
+//gofmt -s
+
+// Test cases for slice expression simplification.
+package p
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:len(a)]
+ _ = a[3:(len(a))]
+ _ = a[len(a) : len(a)-1]
+ _ = a[0:len(b)]
+ _ = a[2:len(a):len(a)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:len(a)]
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(b)]
+ _ = a[:len(a):len(a)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:len(s)]
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+ _ = s[2:len(s):len(s)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:len(s)]
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+ _ = s[:len(s):len(s)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+ _ = t.s[2:len(t.s):len(t.s)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+ _ = t.s[:len(t.s):len(t.s)]
+)
+
+func _() {
+ s := s[0:len(s)]
+ _ = s
+}
diff --git a/src/cmd/gofmt/testdata/stdin1.golden b/src/cmd/gofmt/testdata/stdin1.golden
new file mode 100644
index 0000000..9e4dcd2
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin1.golden
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ if x {
+ y
+ }
diff --git a/src/cmd/gofmt/testdata/stdin1.input b/src/cmd/gofmt/testdata/stdin1.input
new file mode 100644
index 0000000..9e4dcd2
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin1.input
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ if x {
+ y
+ }
diff --git a/src/cmd/gofmt/testdata/stdin2.golden b/src/cmd/gofmt/testdata/stdin2.golden
new file mode 100644
index 0000000..57df355
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin2.golden
@@ -0,0 +1,11 @@
+//gofmt -stdin
+
+var x int
+
+func f() {
+ y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/src/cmd/gofmt/testdata/stdin2.input b/src/cmd/gofmt/testdata/stdin2.input
new file mode 100644
index 0000000..69d6bdd
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin2.input
@@ -0,0 +1,11 @@
+//gofmt -stdin
+
+var x int
+
+
+func f() { y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/src/cmd/gofmt/testdata/stdin3.golden b/src/cmd/gofmt/testdata/stdin3.golden
new file mode 100644
index 0000000..d6da0e4
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin3.golden
@@ -0,0 +1,7 @@
+ //gofmt -stdin
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ {
+ s += i
+ }
+ \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin3.input b/src/cmd/gofmt/testdata/stdin3.input
new file mode 100644
index 0000000..ab46c10
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin3.input
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ { s += i }
+ \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin4.golden b/src/cmd/gofmt/testdata/stdin4.golden
new file mode 100644
index 0000000..0c7acac
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin4.golden
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ // comment
+
+ i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.input b/src/cmd/gofmt/testdata/stdin4.input
new file mode 100644
index 0000000..1fc73f3
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin4.input
@@ -0,0 +1,5 @@
+ //gofmt -stdin
+
+ // comment
+
+ i := 0
diff --git a/src/cmd/gofmt/testdata/stdin5.golden b/src/cmd/gofmt/testdata/stdin5.golden
new file mode 100644
index 0000000..31ce6b2
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin5.golden
@@ -0,0 +1,3 @@
+//gofmt -stdin
+
+i := 5 // Line comment without newline. \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin5.input b/src/cmd/gofmt/testdata/stdin5.input
new file mode 100644
index 0000000..0a7c97d
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin5.input
@@ -0,0 +1,3 @@
+//gofmt -stdin
+
+i :=5// Line comment without newline. \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin6.golden b/src/cmd/gofmt/testdata/stdin6.golden
new file mode 100644
index 0000000..ffcea80
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin6.golden
@@ -0,0 +1,19 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f := func(hat, tail string) {
+
+ fmt.Println(hat+`
+foo
+
+
+`+tail,
+ "more",
+ "and more")
+ }
diff --git a/src/cmd/gofmt/testdata/stdin6.input b/src/cmd/gofmt/testdata/stdin6.input
new file mode 100644
index 0000000..7833002
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin6.input
@@ -0,0 +1,21 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f:=func( hat, tail string){
+
+
+
+ fmt. Println ( hat+ `
+foo
+
+
+`+ tail ,
+ "more" ,
+ "and more" )
+ }
diff --git a/src/cmd/gofmt/testdata/stdin7.golden b/src/cmd/gofmt/testdata/stdin7.golden
new file mode 100644
index 0000000..bbac713
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin7.golden
@@ -0,0 +1,19 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f := func(hat, tail string) {
+
+ fmt.Println(hat+`
+ foo
+
+
+ `+tail,
+ "more",
+ "and more")
+ }
diff --git a/src/cmd/gofmt/testdata/stdin7.input b/src/cmd/gofmt/testdata/stdin7.input
new file mode 100644
index 0000000..fd772a3
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin7.input
@@ -0,0 +1,21 @@
+ //gofmt -stdin
+
+ if err != nil {
+ source := strings.NewReader(`line 1.
+line 2.
+`)
+ return source
+ }
+
+ f:=func( hat, tail string){
+
+
+
+ fmt. Println ( hat+ `
+ foo
+
+
+ `+ tail ,
+ "more" ,
+ "and more" )
+ }
diff --git a/src/cmd/gofmt/testdata/tabs.golden b/src/cmd/gofmt/testdata/tabs.golden
new file mode 100644
index 0000000..287678c
--- /dev/null
+++ b/src/cmd/gofmt/testdata/tabs.golden
@@ -0,0 +1,33 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//gofmt
+
+package main
+
+var _ = []struct {
+ S string
+ Integer int
+}{
+ {
+ S: "Hello World",
+ Integer: 42,
+ },
+ {
+ S: "\t",
+ Integer: 42,
+ },
+ {
+ S: " ", // an actual <tab>
+ Integer: 42,
+ },
+ {
+ S: ` `, // an actual <tab>
+ Integer: 42,
+ },
+ {
+ S: "\u0009",
+ Integer: 42,
+ },
+}
diff --git a/src/cmd/gofmt/testdata/tabs.input b/src/cmd/gofmt/testdata/tabs.input
new file mode 100644
index 0000000..635be79
--- /dev/null
+++ b/src/cmd/gofmt/testdata/tabs.input
@@ -0,0 +1,33 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//gofmt
+
+package main
+
+var _ = []struct{
+ S string
+ Integer int
+}{
+ {
+ S: "Hello World",
+ Integer: 42,
+ },
+ {
+ S: "\t",
+ Integer: 42,
+ },
+ {
+ S: " ", // an actual <tab>
+ Integer: 42,
+ },
+ {
+ S: ` `, // an actual <tab>
+ Integer: 42,
+ },
+ {
+ S: "\u0009",
+ Integer: 42,
+ },
+}
diff --git a/src/cmd/gofmt/testdata/typealias.golden b/src/cmd/gofmt/testdata/typealias.golden
new file mode 100644
index 0000000..bbbbf32
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typealias.golden
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+ _ = chan<- int
+ aa = interface{}
+ bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+ _ chan<- int
+ _ = chan<- int
+ aa0 interface{}
+ aaa = interface{}
+ bb0 p.BB
+ bbb = p.BB
+)
diff --git a/src/cmd/gofmt/testdata/typealias.input b/src/cmd/gofmt/testdata/typealias.input
new file mode 100644
index 0000000..6e49328
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typealias.input
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+ _ = chan<- int
+ aa = interface{}
+ bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+ _ chan<- int
+ _ = chan<- int
+ aa0 interface{}
+ aaa = interface{}
+ bb0 p.BB
+ bbb = p.BB
+)
diff --git a/src/cmd/gofmt/testdata/typeparams.golden b/src/cmd/gofmt/testdata/typeparams.golden
new file mode 100644
index 0000000..d57a2ba
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typeparams.golden
@@ -0,0 +1,35 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//gofmt
+
+package typeparams
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface {
+ m1(P1)
+ ~P2 | ~P3
+}](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func (T[P]) m(x T[P]) P
+
+func _() {
+ type _ []T[P]
+ var _ []T[P]
+ _ = []T[P]{}
+}
diff --git a/src/cmd/gofmt/testdata/typeparams.input b/src/cmd/gofmt/testdata/typeparams.input
new file mode 100644
index 0000000..775cf9e
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typeparams.input
@@ -0,0 +1,32 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//gofmt
+
+package typeparams
+
+type T[ P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1,P2, P3 C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1,P2,P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface{ m1(P1); ~P2|~P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func ((T[P])) m(x T[P]) P
+
+func _() {
+ type _ []T[P]
+ var _ []T[P]
+ _ = []T[P]{}
+}
diff --git a/src/cmd/gofmt/testdata/typeswitch.golden b/src/cmd/gofmt/testdata/typeswitch.golden
new file mode 100644
index 0000000..3cf4dca
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typeswitch.golden
@@ -0,0 +1,60 @@
+/*
+Parenthesized type switch expressions originally
+accepted by gofmt must continue to be rewritten
+into the correct unparenthesized form.
+
+Only type-switches that didn't declare a variable
+in the type switch type assertion and which
+contained only "expression-like" (named) types in their
+cases were permitted to have their type assertion parenthesized
+by go/parser (due to a weak predicate in the parser). All others
+were rejected always, either with a syntax error in the
+type switch header or in the case.
+
+See also issue 4470.
+*/
+package p
+
+func f() {
+ var x interface{}
+ switch x.(type) { // should remain the same
+ }
+ switch x.(type) { // should become: switch x.(type) {
+ }
+
+ switch x.(type) { // should remain the same
+ case int:
+ }
+ switch x.(type) { // should become: switch x.(type) {
+ case int:
+ }
+
+ switch x.(type) { // should remain the same
+ case []int:
+ }
+
+ // Parenthesized (x.(type)) in type switches containing cases
+ // with unnamed (literal) types were never permitted by gofmt;
+ // thus there won't be any code in the wild using this style if
+ // the code was gofmt-ed.
+ /*
+ switch (x.(type)) {
+ case []int:
+ }
+ */
+
+ switch t := x.(type) { // should remain the same
+ default:
+ _ = t
+ }
+
+ // Parenthesized (x.(type)) in type switches declaring a variable
+ // were never permitted by gofmt; thus there won't be any code in
+ // the wild using this style if the code was gofmt-ed.
+ /*
+ switch t := (x.(type)) {
+ default:
+ _ = t
+ }
+ */
+}
diff --git a/src/cmd/gofmt/testdata/typeswitch.input b/src/cmd/gofmt/testdata/typeswitch.input
new file mode 100644
index 0000000..992a772
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typeswitch.input
@@ -0,0 +1,60 @@
+/*
+Parenthesized type switch expressions originally
+accepted by gofmt must continue to be rewritten
+into the correct unparenthesized form.
+
+Only type-switches that didn't declare a variable
+in the type switch type assertion and which
+contained only "expression-like" (named) types in their
+cases were permitted to have their type assertion parenthesized
+by go/parser (due to a weak predicate in the parser). All others
+were rejected always, either with a syntax error in the
+type switch header or in the case.
+
+See also issue 4470.
+*/
+package p
+
+func f() {
+ var x interface{}
+ switch x.(type) { // should remain the same
+ }
+ switch (x.(type)) { // should become: switch x.(type) {
+ }
+
+ switch x.(type) { // should remain the same
+ case int:
+ }
+ switch (x.(type)) { // should become: switch x.(type) {
+ case int:
+ }
+
+ switch x.(type) { // should remain the same
+ case []int:
+ }
+
+ // Parenthesized (x.(type)) in type switches containing cases
+ // with unnamed (literal) types were never permitted by gofmt;
+ // thus there won't be any code in the wild using this style if
+ // the code was gofmt-ed.
+ /*
+ switch (x.(type)) {
+ case []int:
+ }
+ */
+
+ switch t := x.(type) { // should remain the same
+ default:
+ _ = t
+ }
+
+ // Parenthesized (x.(type)) in type switches declaring a variable
+ // were never permitted by gofmt; thus there won't be any code in
+ // the wild using this style if the code was gofmt-ed.
+ /*
+ switch t := (x.(type)) {
+ default:
+ _ = t
+ }
+ */
+}