diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 13:14:23 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 13:14:23 +0000 |
commit | 73df946d56c74384511a194dd01dbe099584fd1a (patch) | |
tree | fd0bcea490dd81327ddfbb31e215439672c9a068 /src/cmd/gofmt | |
parent | Initial commit. (diff) | |
download | golang-1.16-73df946d56c74384511a194dd01dbe099584fd1a.tar.xz golang-1.16-73df946d56c74384511a194dd01dbe099584fd1a.zip |
Adding upstream version 1.16.10.upstream/1.16.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/gofmt')
63 files changed, 3692 insertions, 0 deletions
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go new file mode 100644 index 0000000..e340665 --- /dev/null +++ b/src/cmd/gofmt/doc.go @@ -0,0 +1,104 @@ +// 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..2793c2c --- /dev/null +++ b/src/cmd/gofmt/gofmt.go @@ -0,0 +1,301 @@ +// 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" + "flag" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/scanner" + "go/token" + "io" + "io/fs" + "os" + "path/filepath" + "runtime" + "runtime/pprof" + "strings" + + "cmd/internal/diff" +) + +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 +) + +var ( + fileSet = token.NewFileSet() // per process FileSet + exitCode = 0 + rewrite func(*ast.File) *ast.File + parserMode parser.Mode +) + +func report(err error) { + scanner.PrintError(os.Stderr, err) + exitCode = 2 +} + +func usage() { + fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n") + flag.PrintDefaults() +} + +func initParserMode() { + parserMode = parser.ParseComments + if *allErrors { + parserMode |= parser.AllErrors + } +} + +func isGoFile(f fs.DirEntry) bool { + // ignore non-Go files + name := f.Name() + return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") +} + +// If in == nil, the source is the contents of the file with the given filename. +func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error { + var perm fs.FileMode = 0644 + if in == nil { + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + fi, err := f.Stat() + if err != nil { + return err + } + in = f + perm = fi.Mode().Perm() + } + + src, err := io.ReadAll(in) + if err != nil { + return err + } + + file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin) + if err != nil { + return err + } + + if rewrite != nil { + if sourceAdj == nil { + file = rewrite(file) + } else { + fmt.Fprintf(os.Stderr, "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(out, filename) + } + if *write { + // make a temporary backup before overwriting original + bakname, err := backupFile(filename+".", src, perm) + if err != nil { + return err + } + err = os.WriteFile(filename, res, perm) + if err != nil { + os.Rename(bakname, filename) + return err + } + err = os.Remove(bakname) + if err != nil { + return err + } + } + if *doDiff { + data, err := diffWithReplaceTempFile(src, res, filename) + if err != nil { + return fmt.Errorf("computing diff: %s", err) + } + fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) + out.Write(data) + } + } + + if !*list && !*write && !*doDiff { + _, err = out.Write(res) + } + + return err +} + +func visitFile(path string, f fs.DirEntry, err error) error { + if err == nil && isGoFile(f) { + err = processFile(path, nil, os.Stdout, false) + } + // Don't complain if a file was deleted in the meantime (i.e. + // the directory changed concurrently while running gofmt). + if err != nil && !os.IsNotExist(err) { + report(err) + } + return nil +} + +func walkDir(path string) { + filepath.WalkDir(path, visitFile) +} + +func main() { + // call gofmtMain in a separate function + // so that it can use defer and have them + // run before the exit. + gofmtMain() + os.Exit(exitCode) +} + +func gofmtMain() { + flag.Usage = usage + flag.Parse() + + if *cpuprofile != "" { + f, err := os.Create(*cpuprofile) + if err != nil { + fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err) + exitCode = 2 + return + } + defer f.Close() + pprof.StartCPUProfile(f) + defer pprof.StopCPUProfile() + } + + initParserMode() + initRewrite() + + if flag.NArg() == 0 { + if *write { + fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input") + exitCode = 2 + return + } + if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil { + report(err) + } + return + } + + for i := 0; i < flag.NArg(); i++ { + path := flag.Arg(i) + switch dir, err := os.Stat(path); { + case err != nil: + report(err) + case dir.IsDir(): + walkDir(path) + default: + if err := processFile(path, nil, os.Stdout, false); err != nil { + report(err) + } + } + } +} + +func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) { + data, err := diff.Diff("gofmt", b1, b2) + if len(data) > 0 { + return replaceTempFilename(data, filename) + } + return data, err +} + +// replaceTempFilename replaces temporary filenames in diff with actual one. +// +// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500 +// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500 +// ... +// -> +// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500 +// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500 +// ... +func replaceTempFilename(diff []byte, filename string) ([]byte, error) { + bs := bytes.SplitN(diff, []byte{'\n'}, 3) + if len(bs) < 3 { + return nil, fmt.Errorf("got unexpected diff for %s", filename) + } + // Preserve timestamps. + var t0, t1 []byte + if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 { + t0 = bs[0][i:] + } + if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 { + t1 = bs[1][i:] + } + // Always print filepath with slash separator. + f := filepath.ToSlash(filename) + bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0)) + bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) + return bytes.Join(bs, []byte{'\n'}), nil +} + +const chmodSupported = runtime.GOOS != "windows" + +// 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) { + // create backup file + f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)) + if err != nil { + return "", err + } + bakname := f.Name() + if chmodSupported { + err = f.Chmod(perm) + if err != nil { + f.Close() + os.Remove(bakname) + return bakname, 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..bf2adfe --- /dev/null +++ b/src/cmd/gofmt/gofmt_test.go @@ -0,0 +1,253 @@ +// 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" + "os" + "os/exec" + "path/filepath" + "runtime" + "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 = "" + stdin := false + 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 + stdin = true + default: + t.Errorf("unrecognized flag name: %s", name) + } + } + + initParserMode() + initRewrite() + + var buf bytes.Buffer + err := processFile(in, nil, &buf, stdin) + if err != nil { + t.Error(err) + return + } + + 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)", in, out, in) + d, err := diffWithReplaceTempFile(expected, got, in) + if err == nil { + t.Errorf("%s", d) + } + 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 { + 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 { + // 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) +} + +func TestDiff(t *testing.T) { + if _, err := exec.LookPath("diff"); err != nil { + t.Skipf("skip test on %s: diff command is required", runtime.GOOS) + } + in := []byte("first\nsecond\n") + out := []byte("first\nthird\n") + filename := "difftest.txt" + b, err := diffWithReplaceTempFile(in, out, filename) + if err != nil { + t.Fatal(err) + } + + if runtime.GOOS == "windows" { + b = bytes.ReplaceAll(b, []byte{'\r', '\n'}, []byte{'\n'}) + } + + bs := bytes.SplitN(b, []byte{'\n'}, 3) + line0, line1 := bs[0], bs[1] + + if prefix := "--- difftest.txt.orig"; !bytes.HasPrefix(line0, []byte(prefix)) { + t.Errorf("diff: first line should start with `%s`\ngot: %s", prefix, line0) + } + + if prefix := "+++ difftest.txt"; !bytes.HasPrefix(line1, []byte(prefix)) { + t.Errorf("diff: second line should start with `%s`\ngot: %s", prefix, line1) + } + + want := `@@ -1,2 +1,2 @@ + first +-second ++third +` + + if got := string(bs[2]); got != want { + t.Errorf("diff: got:\n%s\nwant:\n%s", got, want) + } +} + +func TestReplaceTempFilename(t *testing.T) { + diff := []byte(`--- /tmp/tmpfile1 2017-02-08 00:53:26.175105619 +0900 ++++ /tmp/tmpfile2 2017-02-08 00:53:38.415151275 +0900 +@@ -1,2 +1,2 @@ + first +-second ++third +`) + want := []byte(`--- path/to/file.go.orig 2017-02-08 00:53:26.175105619 +0900 ++++ path/to/file.go 2017-02-08 00:53:38.415151275 +0900 +@@ -1,2 +1,2 @@ + first +-second ++third +`) + // Check path in diff output is always slash regardless of the + // os.PathSeparator (`/` or `\`). + sep := string(os.PathSeparator) + filename := strings.Join([]string{"path", "to", "file.go"}, sep) + got, err := replaceTempFilename(diff, filename) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, want) { + t.Errorf("os.PathSeparator='%s': replacedDiff:\ngot:\n%s\nwant:\n%s", sep, got, want) + } +} 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..4a82170 --- /dev/null +++ b/src/cmd/gofmt/long_test.go @@ -0,0 +1,175 @@ +// 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" + "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 + } + if isGoFile(d) { + 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 + filepath.WalkDir(*root, 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 } diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go new file mode 100644 index 0000000..bab22e0 --- /dev/null +++ b/src/cmd/gofmt/rewrite.go @@ -0,0 +1,309 @@ +// 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(p *ast.File) *ast.File { return rewriteFile(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(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.Position) 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.Ptr: + 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..1a0e817 --- /dev/null +++ b/src/cmd/gofmt/simplify.go @@ -0,0 +1,165 @@ +// 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 another + // file belonging to the same package. However, this is extremely unlikely + // and so far (April 2016, after years of supporting this rewrite feature) + // has never come up, so let's keep it working as is (see also #15153). + if n.Max != nil { + // - 3-index slices always require the 2nd and 3rd index + break + } + if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil { + // the array/slice object is a single, resolved 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" && fun.Obj == nil { + // the function called is "len" and it is not locally defined; and + // because we don't have dot imports, it must be the predefined len() + if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj { + // 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..193dbac --- /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..ae7e14d --- /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/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/typeswitch.golden b/src/cmd/gofmt/testdata/typeswitch.golden new file mode 100644 index 0000000..2b1905e --- /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..8f8cba9 --- /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 + } + */ +} |