Initial commit: Go 1.23 release state
This commit is contained in:
106
src/cmd/gofmt/doc.go
Normal file
106
src/cmd/gofmt/doc.go
Normal file
@@ -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.
|
||||
575
src/cmd/gofmt/gofmt.go
Normal file
575
src/cmd/gofmt/gofmt.go
Normal file
@@ -0,0 +1,575 @@
|
||||
// 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"
|
||||
|
||||
"cmd/internal/telemetry/counter"
|
||||
|
||||
"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) {
|
||||
counter.Open()
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
counter.Inc("gofmt/invocations")
|
||||
counter.CountFlags("gofmt/flag:", *flag.CommandLine)
|
||||
|
||||
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 !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
|
||||
}
|
||||
195
src/cmd/gofmt/gofmt_test.go
Normal file
195
src/cmd/gofmt/gofmt_test.go
Normal file
@@ -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)
|
||||
}
|
||||
67
src/cmd/gofmt/gofmt_unix_test.go
Normal file
67
src/cmd/gofmt/gofmt_unix_test.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
176
src/cmd/gofmt/internal.go
Normal file
176
src/cmd/gofmt/internal.go
Normal file
@@ -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'
|
||||
}
|
||||
172
src/cmd/gofmt/long_test.go
Normal file
172
src/cmd/gofmt/long_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
// 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, fs.FileInfoToDirEntry(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)
|
||||
}
|
||||
}
|
||||
309
src/cmd/gofmt/rewrite.go
Normal file
309
src/cmd/gofmt/rewrite.go
Normal file
@@ -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(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)
|
||||
clear(m)
|
||||
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
|
||||
}
|
||||
169
src/cmd/gofmt/simplify.go
Normal file
169
src/cmd/gofmt/simplify.go
Normal file
@@ -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
|
||||
}
|
||||
9
src/cmd/gofmt/testdata/comments.golden
vendored
Normal file
9
src/cmd/gofmt/testdata/comments.golden
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
// comment here
|
||||
|
||||
func f() {}
|
||||
|
||||
//line foo.go:1
|
||||
9
src/cmd/gofmt/testdata/comments.input
vendored
Normal file
9
src/cmd/gofmt/testdata/comments.input
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
// comment here
|
||||
|
||||
func f() {}
|
||||
|
||||
//line foo.go:1
|
||||
218
src/cmd/gofmt/testdata/composites.golden
vendored
Normal file
218
src/cmd/gofmt/testdata/composites.golden
vendored
Normal file
@@ -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},
|
||||
}
|
||||
218
src/cmd/gofmt/testdata/composites.input
vendored
Normal file
218
src/cmd/gofmt/testdata/composites.input
vendored
Normal file
@@ -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},
|
||||
}
|
||||
13
src/cmd/gofmt/testdata/crlf.golden
vendored
Normal file
13
src/cmd/gofmt/testdata/crlf.golden
vendored
Normal file
@@ -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()
|
||||
}
|
||||
13
src/cmd/gofmt/testdata/crlf.input
vendored
Normal file
13
src/cmd/gofmt/testdata/crlf.input
vendored
Normal file
@@ -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()
|
||||
}
|
||||
14
src/cmd/gofmt/testdata/emptydecl.golden
vendored
Normal file
14
src/cmd/gofmt/testdata/emptydecl.golden
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test case for issue 7631.
|
||||
|
||||
package main
|
||||
|
||||
// Keep this declaration
|
||||
var ()
|
||||
|
||||
const (
|
||||
// Keep this declaration
|
||||
)
|
||||
|
||||
func main() {}
|
||||
16
src/cmd/gofmt/testdata/emptydecl.input
vendored
Normal file
16
src/cmd/gofmt/testdata/emptydecl.input
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test case for issue 7631.
|
||||
|
||||
package main
|
||||
|
||||
// Keep this declaration
|
||||
var ()
|
||||
|
||||
const (
|
||||
// Keep this declaration
|
||||
)
|
||||
|
||||
type ()
|
||||
|
||||
func main() {}
|
||||
186
src/cmd/gofmt/testdata/go2numbers.golden
vendored
Normal file
186
src/cmd/gofmt/testdata/go2numbers.golden
vendored
Normal file
@@ -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
|
||||
)
|
||||
186
src/cmd/gofmt/testdata/go2numbers.input
vendored
Normal file
186
src/cmd/gofmt/testdata/go2numbers.input
vendored
Normal file
@@ -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
|
||||
)
|
||||
194
src/cmd/gofmt/testdata/import.golden
vendored
Normal file
194
src/cmd/gofmt/testdata/import.golden
vendored
Normal file
@@ -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"
|
||||
)
|
||||
199
src/cmd/gofmt/testdata/import.input
vendored
Normal file
199
src/cmd/gofmt/testdata/import.input
vendored
Normal file
@@ -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")
|
||||
13
src/cmd/gofmt/testdata/issue28082.golden
vendored
Normal file
13
src/cmd/gofmt/testdata/issue28082.golden
vendored
Normal file
@@ -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() {}
|
||||
13
src/cmd/gofmt/testdata/issue28082.input
vendored
Normal file
13
src/cmd/gofmt/testdata/issue28082.input
vendored
Normal file
@@ -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() {}
|
||||
30
src/cmd/gofmt/testdata/ranges.golden
vendored
Normal file
30
src/cmd/gofmt/testdata/ranges.golden
vendored
Normal file
@@ -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 {
|
||||
}
|
||||
}
|
||||
20
src/cmd/gofmt/testdata/ranges.input
vendored
Normal file
20
src/cmd/gofmt/testdata/ranges.input
vendored
Normal file
@@ -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 {}
|
||||
}
|
||||
14
src/cmd/gofmt/testdata/rewrite1.golden
vendored
Normal file
14
src/cmd/gofmt/testdata/rewrite1.golden
vendored
Normal file
@@ -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)
|
||||
}
|
||||
14
src/cmd/gofmt/testdata/rewrite1.input
vendored
Normal file
14
src/cmd/gofmt/testdata/rewrite1.input
vendored
Normal file
@@ -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)
|
||||
}
|
||||
19
src/cmd/gofmt/testdata/rewrite10.golden
vendored
Normal file
19
src/cmd/gofmt/testdata/rewrite10.golden
vendored
Normal file
@@ -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) }
|
||||
}
|
||||
19
src/cmd/gofmt/testdata/rewrite10.input
vendored
Normal file
19
src/cmd/gofmt/testdata/rewrite10.input
vendored
Normal file
@@ -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) }
|
||||
}
|
||||
12
src/cmd/gofmt/testdata/rewrite2.golden
vendored
Normal file
12
src/cmd/gofmt/testdata/rewrite2.golden
vendored
Normal file
@@ -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 {}
|
||||
12
src/cmd/gofmt/testdata/rewrite2.input
vendored
Normal file
12
src/cmd/gofmt/testdata/rewrite2.input
vendored
Normal file
@@ -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 {}
|
||||
14
src/cmd/gofmt/testdata/rewrite3.golden
vendored
Normal file
14
src/cmd/gofmt/testdata/rewrite3.golden
vendored
Normal file
@@ -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
|
||||
}
|
||||
14
src/cmd/gofmt/testdata/rewrite3.input
vendored
Normal file
14
src/cmd/gofmt/testdata/rewrite3.input
vendored
Normal file
@@ -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
|
||||
}
|
||||
76
src/cmd/gofmt/testdata/rewrite4.golden
vendored
Normal file
76
src/cmd/gofmt/testdata/rewrite4.golden
vendored
Normal file
@@ -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()
|
||||
}
|
||||
76
src/cmd/gofmt/testdata/rewrite4.input
vendored
Normal file
76
src/cmd/gofmt/testdata/rewrite4.input
vendored
Normal file
@@ -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()
|
||||
}
|
||||
17
src/cmd/gofmt/testdata/rewrite5.golden
vendored
Normal file
17
src/cmd/gofmt/testdata/rewrite5.golden
vendored
Normal file
@@ -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
|
||||
}
|
||||
17
src/cmd/gofmt/testdata/rewrite5.input
vendored
Normal file
17
src/cmd/gofmt/testdata/rewrite5.input
vendored
Normal file
@@ -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
|
||||
}
|
||||
17
src/cmd/gofmt/testdata/rewrite6.golden
vendored
Normal file
17
src/cmd/gofmt/testdata/rewrite6.golden
vendored
Normal file
@@ -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
|
||||
}
|
||||
17
src/cmd/gofmt/testdata/rewrite6.input
vendored
Normal file
17
src/cmd/gofmt/testdata/rewrite6.input
vendored
Normal file
@@ -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
|
||||
}
|
||||
17
src/cmd/gofmt/testdata/rewrite7.golden
vendored
Normal file
17
src/cmd/gofmt/testdata/rewrite7.golden
vendored
Normal file
@@ -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)
|
||||
}
|
||||
17
src/cmd/gofmt/testdata/rewrite7.input
vendored
Normal file
17
src/cmd/gofmt/testdata/rewrite7.input
vendored
Normal file
@@ -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)
|
||||
}
|
||||
12
src/cmd/gofmt/testdata/rewrite8.golden
vendored
Normal file
12
src/cmd/gofmt/testdata/rewrite8.golden
vendored
Normal file
@@ -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
|
||||
12
src/cmd/gofmt/testdata/rewrite8.input
vendored
Normal file
12
src/cmd/gofmt/testdata/rewrite8.input
vendored
Normal file
@@ -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{}
|
||||
11
src/cmd/gofmt/testdata/rewrite9.golden
vendored
Normal file
11
src/cmd/gofmt/testdata/rewrite9.golden
vendored
Normal file
@@ -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
|
||||
11
src/cmd/gofmt/testdata/rewrite9.input
vendored
Normal file
11
src/cmd/gofmt/testdata/rewrite9.input
vendored
Normal file
@@ -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
|
||||
66
src/cmd/gofmt/testdata/slices1.golden
vendored
Normal file
66
src/cmd/gofmt/testdata/slices1.golden
vendored
Normal file
@@ -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
|
||||
}
|
||||
66
src/cmd/gofmt/testdata/slices1.input
vendored
Normal file
66
src/cmd/gofmt/testdata/slices1.input
vendored
Normal file
@@ -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
|
||||
}
|
||||
5
src/cmd/gofmt/testdata/stdin1.golden
vendored
Normal file
5
src/cmd/gofmt/testdata/stdin1.golden
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if x {
|
||||
y
|
||||
}
|
||||
5
src/cmd/gofmt/testdata/stdin1.input
vendored
Normal file
5
src/cmd/gofmt/testdata/stdin1.input
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if x {
|
||||
y
|
||||
}
|
||||
11
src/cmd/gofmt/testdata/stdin2.golden
vendored
Normal file
11
src/cmd/gofmt/testdata/stdin2.golden
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//gofmt -stdin
|
||||
|
||||
var x int
|
||||
|
||||
func f() {
|
||||
y := z
|
||||
/* this is a comment */
|
||||
// this is a comment too
|
||||
}
|
||||
|
||||
|
||||
11
src/cmd/gofmt/testdata/stdin2.input
vendored
Normal file
11
src/cmd/gofmt/testdata/stdin2.input
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//gofmt -stdin
|
||||
|
||||
var x int
|
||||
|
||||
|
||||
func f() { y := z
|
||||
/* this is a comment */
|
||||
// this is a comment too
|
||||
}
|
||||
|
||||
|
||||
7
src/cmd/gofmt/testdata/stdin3.golden
vendored
Normal file
7
src/cmd/gofmt/testdata/stdin3.golden
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//gofmt -stdin
|
||||
|
||||
/* note: no newline at end of file */
|
||||
for i := 0; i < 10; i++ {
|
||||
s += i
|
||||
}
|
||||
|
||||
5
src/cmd/gofmt/testdata/stdin3.input
vendored
Normal file
5
src/cmd/gofmt/testdata/stdin3.input
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
/* note: no newline at end of file */
|
||||
for i := 0; i < 10; i++ { s += i }
|
||||
|
||||
5
src/cmd/gofmt/testdata/stdin4.golden
vendored
Normal file
5
src/cmd/gofmt/testdata/stdin4.golden
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
// comment
|
||||
|
||||
i := 0
|
||||
5
src/cmd/gofmt/testdata/stdin4.input
vendored
Normal file
5
src/cmd/gofmt/testdata/stdin4.input
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
// comment
|
||||
|
||||
i := 0
|
||||
3
src/cmd/gofmt/testdata/stdin5.golden
vendored
Normal file
3
src/cmd/gofmt/testdata/stdin5.golden
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
//gofmt -stdin
|
||||
|
||||
i := 5 // Line comment without newline.
|
||||
3
src/cmd/gofmt/testdata/stdin5.input
vendored
Normal file
3
src/cmd/gofmt/testdata/stdin5.input
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
//gofmt -stdin
|
||||
|
||||
i :=5// Line comment without newline.
|
||||
19
src/cmd/gofmt/testdata/stdin6.golden
vendored
Normal file
19
src/cmd/gofmt/testdata/stdin6.golden
vendored
Normal file
@@ -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")
|
||||
}
|
||||
21
src/cmd/gofmt/testdata/stdin6.input
vendored
Normal file
21
src/cmd/gofmt/testdata/stdin6.input
vendored
Normal file
@@ -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" )
|
||||
}
|
||||
19
src/cmd/gofmt/testdata/stdin7.golden
vendored
Normal file
19
src/cmd/gofmt/testdata/stdin7.golden
vendored
Normal file
@@ -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")
|
||||
}
|
||||
21
src/cmd/gofmt/testdata/stdin7.input
vendored
Normal file
21
src/cmd/gofmt/testdata/stdin7.input
vendored
Normal file
@@ -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" )
|
||||
}
|
||||
33
src/cmd/gofmt/testdata/tabs.golden
vendored
Normal file
33
src/cmd/gofmt/testdata/tabs.golden
vendored
Normal file
@@ -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,
|
||||
},
|
||||
}
|
||||
33
src/cmd/gofmt/testdata/tabs.input
vendored
Normal file
33
src/cmd/gofmt/testdata/tabs.input
vendored
Normal file
@@ -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,
|
||||
},
|
||||
}
|
||||
24
src/cmd/gofmt/testdata/typealias.golden
vendored
Normal file
24
src/cmd/gofmt/testdata/typealias.golden
vendored
Normal file
@@ -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
|
||||
)
|
||||
24
src/cmd/gofmt/testdata/typealias.input
vendored
Normal file
24
src/cmd/gofmt/testdata/typealias.input
vendored
Normal file
@@ -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
|
||||
)
|
||||
35
src/cmd/gofmt/testdata/typeparams.golden
vendored
Normal file
35
src/cmd/gofmt/testdata/typeparams.golden
vendored
Normal file
@@ -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]{}
|
||||
}
|
||||
32
src/cmd/gofmt/testdata/typeparams.input
vendored
Normal file
32
src/cmd/gofmt/testdata/typeparams.input
vendored
Normal file
@@ -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]{}
|
||||
}
|
||||
60
src/cmd/gofmt/testdata/typeswitch.golden
vendored
Normal file
60
src/cmd/gofmt/testdata/typeswitch.golden
vendored
Normal file
@@ -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
|
||||
}
|
||||
*/
|
||||
}
|
||||
60
src/cmd/gofmt/testdata/typeswitch.input
vendored
Normal file
60
src/cmd/gofmt/testdata/typeswitch.input
vendored
Normal file
@@ -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
|
||||
}
|
||||
*/
|
||||
}
|
||||
Reference in New Issue
Block a user