统一错误码

This commit is contained in:
likun 2025-05-08 17:33:46 +08:00
parent aea644c553
commit 9d2f572c35
84 changed files with 4459 additions and 85 deletions

View File

@ -95,7 +95,11 @@ func (repo *commonResourceRepoImpl) Create(projectEt *entity.Project, dtoObj dto
et := (&entity.CommonResource{}).FromPo(repo.newEmptyPo()).FromDto(dtoObj)
err := repo.db.Create(et.Po).Error
if err != nil {
return et, errcode.New(errcode.DBError, "create resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err)
if strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "UNIQUE constraint") {
return et, errcode.New(errcode.DBInsertDuplicate, "create resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err)
} else {
return et, errcode.New(errcode.DBError, "create resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err)
}
}
return et, nil
}

View File

@ -25,12 +25,13 @@ func (ctx *WebContext) Ok(data any) {
}
func (ctx *WebContext) Fail(err error) {
code, stack, msg := errcode.ParseError(err)
code, codeContent, stack, msg := errcode.ParseError(err)
ctx.rawCtx.JSON(200, map[string]any{
"code": code,
"stack": stack,
"msg": msg,
"data": "",
"code": code,
"stack": stack,
"msg": codeContent,
"detail_msg": msg,
"data": "",
})
}

View File

@ -0,0 +1,14 @@
package main
import (
"admin/cmd/tools/generator/errcode"
"log"
)
func init() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
}
func main() {
errcode.Generate()
}

View File

@ -0,0 +1,195 @@
package errcode
import (
"flag"
"fmt"
"go/ast"
"go/token"
"golang.org/x/tools/go/packages"
"log"
"os"
"path/filepath"
"strconv"
"strings"
)
type File struct {
pkg *Package
fileName string
rawAstFile *ast.File
content string
importList map[string]struct{}
errcodeList *ErrCodeList
}
type Package struct {
Name string
rawAstPkg *packages.Package
rawAstFileSet *token.FileSet
files []*File
ImportList []string
}
func Generate() {
flag.Parse()
curRootDir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
log.Printf("================================================")
log.Printf("args: %v", os.Args[1:])
log.Printf("pwd: %v", curRootDir)
cfg := &packages.Config{
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedFiles,
Tests: true,
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join([]string{}, " "))},
Logf: func(format string, args ...interface{}) {
//log.Printf(format, args...)
},
}
rawPkgs, err := packages.Load(cfg, ".")
if err != nil {
log.Fatal(err)
}
if len(rawPkgs) == 0 {
log.Fatalf("当前包居然读取不到ast信息尝试项目根目录执行go mod tidy解决报错")
}
pkgs := make([]*Package, 0, len(rawPkgs))
firstPkgPath := ""
for i, pkg := range rawPkgs {
if i == 0 {
firstPkgPath = pkg.PkgPath
} else {
if strings.Contains(pkg.PkgPath, firstPkgPath) {
continue
}
}
p := &Package{
Name: pkg.Name,
rawAstPkg: pkg,
rawAstFileSet: pkg.Fset,
files: make([]*File, 0, len(pkg.Syntax)),
}
for j, file := range pkg.Syntax {
goFile := pkg.GoFiles[j]
if strings.HasSuffix(goFile, ".gen.go") {
continue
}
content, err := os.ReadFile(goFile)
if err != nil {
panic(err)
}
p.files = append(p.files, &File{
pkg: p,
fileName: filepath.Base(goFile),
rawAstFile: file,
content: string(content),
importList: make(map[string]struct{}),
})
}
pkgs = append(pkgs, p)
}
if len(pkgs) > 1 {
s := ""
for _, v := range pkgs {
s += v.rawAstPkg.Name + ","
log.Printf("pak:%v, gofiles:%v", v.rawAstPkg.PkgPath, v.rawAstPkg.GoFiles)
}
log.Fatalf("居然发现%v个包(%v),联系@李坤支持:", len(pkgs), s)
}
for _, pkg := range pkgs {
for _, file := range pkg.files {
file.errcodeList = &ErrCodeList{
List: make([]*ErrCode, 0),
}
ast.Inspect(file.rawAstFile, file.genDecl)
//log.Printf("after gen, file %v list len:%v", file.fileName, len(file.errcodeList.List))
if len(file.errcodeList.List) > 0 {
fileName := "code_content.gen.go"
outputFile := filepath.Join(curRootDir, fileName)
err := renderFile(file.errcodeList, tpl, outputFile)
if err != nil {
log.Printf("render file %v error:%v", fileName, err)
os.Exit(1)
}
}
}
}
}
// genDecl processes one declaration clause.
func (f *File) genDecl(node ast.Node) bool {
//log.Printf("node:%+v", node)
if f.pkg.Name != "errcode" {
return true
}
if f.fileName != "code.go" {
return true
}
if node == nil {
return true
}
fileSet := f.pkg.rawAstFileSet
fpos := fileSet.File(node.Pos())
fileNode, ok := node.(*ast.File)
if !ok {
return true
}
for _, v := range fileNode.Decls {
d := v.(*ast.GenDecl)
if d.Tok.String() != "const" {
continue
}
// 静态错误码
for _, spec := range d.Specs {
specValue := spec.(*ast.ValueSpec)
specContent := f.content[fpos.Offset(specValue.Pos()):fpos.Offset(specValue.End())]
specContent = strings.ReplaceAll(specContent, " ", "")
values := strings.Split(specContent, "=")
if len(values) != 2 {
log.Printf("错误码:%v 按等号分隔字符串之后不满足var=value格式", specContent)
os.Exit(1)
}
commentContent := specValue.Comment.Text()
commentContent = strings.ReplaceAll(commentContent, "\n", "")
if commentContent == "" {
log.Printf("错误码:%v 没有定义文本内容格式为ErrCode = 123 // <文本内容>", specContent)
os.Exit(1)
}
code, _ := strconv.Atoi(values[1])
f.errcodeList.List = append(f.errcodeList.List, &ErrCode{
Name: values[0],
Value: code,
Comment: commentContent,
})
//log.Printf("错误码:%v 值:%v --> 注释:%v\n", values[0], values[1], commentContent)
}
}
return true
}

View File

@ -0,0 +1,69 @@
package errcode
import (
"admin/lib/gofmt"
"fmt"
"log"
"os"
"path/filepath"
"text/template"
)
type ErrCode struct {
Name string
Value int
Comment string
}
type ErrCodeList struct {
List []*ErrCode
}
var tpl = `
// Code generated by generator. DO NOT EDIT.
package errcode
import (
"fmt"
)
func GetErrCodeContent(code int) string {
switch code {
{{- range .List }}
case {{ .Name }}:
return "{{ .Comment -}}"
{{- end }}
default:
return fmt.Sprintf("错误码%v没有找到文本内容", code)
}
}
`
func renderFile(data any, templateContent, filePath string) error {
dir := filepath.Dir(filePath)
if dir != "" {
_ = os.MkdirAll(dir, os.ModePerm)
}
tmpl, err := template.New("client").Parse(templateContent)
if err != nil {
return fmt.Errorf("create template for file:%v error:%v", filePath, err)
}
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return fmt.Errorf("open file %v error:%v", filePath, err)
}
defer file.Close()
err = tmpl.Execute(file, data)
if err != nil {
return fmt.Errorf("execute template for file:%v error:%v", filePath, err)
}
log.Printf("write content file [%v] ok.", filePath)
gofmt.Go(filePath)
return nil
}
func must(err error) {
if err != nil {
panic(err)
}
}

View File

@ -9,7 +9,8 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/prometheus/client_golang v1.22.0
github.com/rs/zerolog v1.34.0
golang.org/x/crypto v0.37.0
golang.org/x/crypto v0.38.0
golang.org/x/tools v0.33.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.7
gorm.io/driver/sqlite v1.5.7
@ -47,8 +48,11 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.16.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/telemetry v0.0.0-20250507143331-155ddd5254aa // indirect
golang.org/x/text v0.25.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)

View File

@ -112,17 +112,25 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20250507143331-155ddd5254aa h1:MHtJsiOHK4ZJBZ+1Mj/vw1OfVBmCaVTJ4r1mi30Urlg=
golang.org/x/telemetry v0.0.0-20250507143331-155ddd5254aa/go.mod h1:QNvpSH4vItB4zw8JazOv6Ba3fs1TorwPx9cCU6qTIdE=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -68,12 +68,13 @@ func (ctx *WebContext) Fail(err error) {
return
}
code, stack, msg := errcode.ParseError(err)
code, codeContent, stack, msg := errcode.ParseError(err)
ctx.rawCtx.JSON(200, map[string]any{
"code": code,
"stack": stack,
"msg": msg,
"data": "",
"code": code,
"stack": stack,
"msg": codeContent,
"detail_msg": msg,
"data": "",
})
ctx.alreadySetRsp = true

View File

@ -1,15 +1,18 @@
package errcode
//go:generate go run ../../cmd/tools/generator/errcode.go
const (
Ok = 0
ServerError = 1 // 服务器错误
DBError = 2 // 数据库错误
NotLogin = 3 // 没有登录,重定向到登录页面
HeaderParamsInvalid = 4
TokenInvalid = 5
UserOrPassInValid = 7 // 用户名或密码错误
NoPermission = 8 // 没有权限
ParamsInvalid = 9
Ok = 0 // ok
ServerError = 1 // 服务器错误
DBError = 2 // 数据库错误
NotLogin = 3 // 没有登录,重定向到登录页面
HeaderParamsInvalid = 4 // http请求头参数不合法
TokenInvalid = 5 // http请求token不合法
UserOrPassInValid = 7 // 用户名或密码错误
NoPermission = 8 // 没有权限
ParamsInvalid = 9 // 参数不合法
DBInsertDuplicate = 10 // 数据重复
)
// sdk系统错误码给内部别的游戏调用api返回

View File

@ -0,0 +1,41 @@
// Code generated by generator. DO NOT EDIT.
package errcode
import (
"fmt"
)
func GetErrCodeContent(code int) string {
switch code {
case Ok:
return "ok"
case ServerError:
return "服务器错误"
case DBError:
return "数据库错误"
case NotLogin:
return "没有登录,重定向到登录页面"
case HeaderParamsInvalid:
return "http请求头参数不合法"
case TokenInvalid:
return "http请求token不合法"
case UserOrPassInValid:
return "用户名或密码错误"
case NoPermission:
return "没有权限"
case ParamsInvalid:
return "参数不合法"
case DBInsertDuplicate:
return "数据重复"
case CDKey_:
return "cdkey系统占用100"
case CDKeyInvalid:
return "cdkey无效"
case CDKeyAlreadyUsed:
return "cdkey已经使用过"
case CDKeyAlreadyExpired:
return "cdkey过期"
default:
return fmt.Sprintf("错误码%v没有找到文本内容", code)
}
}

View File

@ -29,9 +29,9 @@ func New(code int, format string, args ...interface{}) error {
return newError(code, 2, format, args...)
}
func ParseError(err error) (int, string, string) {
func ParseError(err error) (int, string, string, string) {
if specErr, ok := err.(*errorWithCode); ok {
return specErr.code, specErr.stack, specErr.msg
return specErr.code, GetErrCodeContent(specErr.code), specErr.stack, specErr.msg
}
return ParseError(newError(ServerError, 3, err.Error()))
}

View File

@ -0,0 +1,62 @@
// Copyright 2024 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 !cmd_go_bootstrap && !compiler_bootstrap
package counter
import (
"flag"
"os"
"golang.org/x/telemetry/counter"
)
var openCalled bool
func OpenCalled() bool { return openCalled }
// Open opens the counter files for writing if telemetry is supported
// on the current platform (and does nothing otherwise).
func Open() {
openCalled = true
counter.OpenDir(os.Getenv("TEST_TELEMETRY_DIR"))
}
// Inc increments the counter with the given name.
func Inc(name string) {
counter.Inc(name)
}
// New returns a counter with the given name.
func New(name string) *counter.Counter {
return counter.New(name)
}
// NewStack returns a new stack counter with the given name and depth.
func NewStack(name string, depth int) *counter.StackCounter {
return counter.NewStack(name, depth)
}
// CountFlags creates a counter for every flag that is set
// and increments the counter. The name of the counter is
// the concatenation of prefix and the flag name.
func CountFlags(prefix string, flagSet flag.FlagSet) {
counter.CountFlags(prefix, flagSet)
}
// CountFlagValue creates a counter for the flag value
// if it is set and increments the counter. The name of the
// counter is the concatenation of prefix, the flagName, ":",
// and value.String() for the flag's value.
func CountFlagValue(prefix string, flagSet flag.FlagSet, flagName string) {
// TODO(matloob): Maybe pass in a list of flagNames if we end up counting
// values for more than one?
// TODO(matloob): Add this to x/telemetry?
flagSet.Visit(func(f *flag.Flag) {
if f.Name == flagName {
counter.New(prefix + f.Name + ":" + f.Value.String()).Inc()
}
})
}

View File

@ -0,0 +1,20 @@
// Copyright 2024 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 cmd_go_bootstrap || compiler_bootstrap
package counter
import "flag"
type dummyCounter struct{}
func (dc dummyCounter) Inc() {}
func Open() {}
func Inc(name string) {}
func New(name string) dummyCounter { return dummyCounter{} }
func NewStack(name string, depth int) dummyCounter { return dummyCounter{} }
func CountFlags(name string, flagSet flag.FlagSet) {}
func CountFlagValue(prefix string, flagSet flag.FlagSet, flagName string) {}

515
admin/lib/gofmt/gofmt.go Normal file
View File

@ -0,0 +1,515 @@
// 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 gofmt
import (
"admin/lib/gofmt/counter"
"bytes"
"context"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/scanner"
"go/token"
"io"
"io/fs"
"math/rand"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"golang.org/x/sync/semaphore"
)
var (
// main operation modes
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
write *bool
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)")
)
// 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 !*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 Go(dstFile string) {
writeBool := true
write = &writeBool
// 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, dstFile)
s.GetExitCode()
return
}
func gofmtMain(s *sequencer, dstFile string) {
counter.Open()
counter.Inc("gofmt/invocations")
counter.CountFlags("gofmt/flag:", *flag.CommandLine)
initParserMode()
initRewrite()
info, err := os.Stat(dstFile)
if err != nil {
panic(err)
}
s.Add(fileWeight(dstFile, info), func(r *reporter) error {
return processFile(dstFile, info, nil, r)
})
}
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
}

View 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 gofmt
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)
}

View 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 gofmt
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
admin/lib/gofmt/internal.go Normal file
View 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 gofmt
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'
}

View 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 gofmt
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
admin/lib/gofmt/rewrite.go Normal file
View 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 gofmt
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
admin/lib/gofmt/simplify.go Normal file
View 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 gofmt
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
}

View File

@ -0,0 +1,9 @@
package main
func main() {}
// comment here
func f() {}
//line foo.go:1

View File

@ -0,0 +1,9 @@
package main
func main() {}
// comment here
func f() {}
//line foo.go:1

View 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},
}

View 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
admin/lib/gofmt/testdata/crlf.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/crlf.input vendored Normal file
View 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()
}

View File

@ -0,0 +1,14 @@
//gofmt -s
// Test case for issue 7631.
package main
// Keep this declaration
var ()
const (
// Keep this declaration
)
func main() {}

View 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() {}

View 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
)

View 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
admin/lib/gofmt/testdata/import.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/import.input vendored Normal file
View 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")

View 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() {}

View 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
admin/lib/gofmt/testdata/ranges.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/ranges.input vendored Normal file
View 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 {}
}

View 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
admin/lib/gofmt/testdata/rewrite1.input vendored Normal file
View 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)
}

View 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) }
}

View 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) }
}

View 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
admin/lib/gofmt/testdata/rewrite2.input vendored Normal file
View 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 {}

View 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
admin/lib/gofmt/testdata/rewrite3.input vendored Normal file
View 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
}

View 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
admin/lib/gofmt/testdata/rewrite4.input vendored Normal file
View 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()
}

View 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
admin/lib/gofmt/testdata/rewrite5.input vendored Normal file
View 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
}

View 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
admin/lib/gofmt/testdata/rewrite6.input vendored Normal file
View 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
}

View 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
admin/lib/gofmt/testdata/rewrite7.input vendored Normal file
View 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)
}

View 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
admin/lib/gofmt/testdata/rewrite8.input vendored Normal file
View 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{}

View 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
admin/lib/gofmt/testdata/rewrite9.input vendored Normal file
View 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
admin/lib/gofmt/testdata/slices1.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/slices1.input vendored Normal file
View 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
}

View File

@ -0,0 +1,5 @@
//gofmt -stdin
if x {
y
}

5
admin/lib/gofmt/testdata/stdin1.input vendored Normal file
View File

@ -0,0 +1,5 @@
//gofmt -stdin
if x {
y
}

11
admin/lib/gofmt/testdata/stdin2.golden vendored Normal file
View File

@ -0,0 +1,11 @@
//gofmt -stdin
var x int
func f() {
y := z
/* this is a comment */
// this is a comment too
}

11
admin/lib/gofmt/testdata/stdin2.input vendored Normal file
View File

@ -0,0 +1,11 @@
//gofmt -stdin
var x int
func f() { y := z
/* this is a comment */
// this is a comment too
}

View File

@ -0,0 +1,7 @@
//gofmt -stdin
/* note: no newline at end of file */
for i := 0; i < 10; i++ {
s += i
}

5
admin/lib/gofmt/testdata/stdin3.input vendored Normal file
View File

@ -0,0 +1,5 @@
//gofmt -stdin
/* note: no newline at end of file */
for i := 0; i < 10; i++ { s += i }

View File

@ -0,0 +1,5 @@
//gofmt -stdin
// comment
i := 0

5
admin/lib/gofmt/testdata/stdin4.input vendored Normal file
View File

@ -0,0 +1,5 @@
//gofmt -stdin
// comment
i := 0

View File

@ -0,0 +1,3 @@
//gofmt -stdin
i := 5 // Line comment without newline.

3
admin/lib/gofmt/testdata/stdin5.input vendored Normal file
View File

@ -0,0 +1,3 @@
//gofmt -stdin
i :=5// Line comment without newline.

19
admin/lib/gofmt/testdata/stdin6.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/stdin6.input vendored Normal file
View 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
admin/lib/gofmt/testdata/stdin7.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/stdin7.input vendored Normal file
View 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
admin/lib/gofmt/testdata/tabs.golden vendored Normal file
View 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
admin/lib/gofmt/testdata/tabs.input vendored Normal file
View 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,
},
}

View 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
)

View 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
)

View 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]{}
}

View 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]{}
}

View 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
}
*/
}

View 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
}
*/
}

View File

@ -62,14 +62,14 @@ const listData = async () => {
for (let i = 0; i < fieldsDescInfo.value.length; i++) {
var field = fieldsDescInfo.value[i]
dialogAddForm.value[field.key] = ''
dialogObjectForm.value[field.key] = ''
if (field.required == true) {
rules.value[field.key] = [{required: true, message: field.name + "不能为空", trigger: "blur"}]
}
if (field.type == "items") {
dialogAddForm.value[field.key] = []
dialogObjectForm.value[field.key] = []
for (let j = 0; j < rows.value.length; j++) {
rows.value[j].jsonValue = JSON.stringify(rows.value[j][field.key])
}
@ -128,19 +128,18 @@ const dialogEditVisible = ref(false)
const dialogAddFormRef = ref(null)
const dialogEditFormRef = ref(null)
const dialogAddForm = ref({
const dialogObjectForm = ref({
ServerIDs: [],
Attach: [],
})
const dialogEditForm = ref({})
const submitAdd = async () => {
try {
await dialogAddFormRef.value.validate(valid => {
if (valid) {
console.log("commit add form:", dialogAddForm.value)
resourcePost(resource_url, dialogAddForm.value).then((res) => {
console.log("commit add form:", dialogObjectForm.value)
resourcePost(resource_url, dialogObjectForm.value).then((res) => {
ElNotification({
title: "添加结果通知",
message: "添加成功!",
@ -154,7 +153,7 @@ const submitAdd = async () => {
}, (err) => {
console.log("添加报错:", err)
})
console.log("提交数据:", dialogAddForm.value)
console.log("提交数据:", dialogObjectForm.value)
}
})
} catch (error) {
@ -166,7 +165,7 @@ const submitEdit = async () => {
try {
await dialogEditFormRef.value.validate(valid => {
if (valid) {
resourcePut(resource_url, dialogEditForm.value).then((res) => {
resourcePut(resource_url, dialogObjectForm.value).then((res) => {
ElNotification({
title: "编辑结果通知",
message: "编辑成功!",
@ -175,12 +174,12 @@ const submitEdit = async () => {
"show-close": true,
})
dialogEditVisible.value = false
rows.value[dialogEditForm.value.oldIndex] = res.data.dto
rows.value[dialogObjectForm.value.oldIndex] = res.data.dto
handleCloseDialog()
}, (err) => {
console.log("添加报错:", err)
})
console.log("提交数据:", dialogEditForm.value)
console.log("提交数据:", dialogObjectForm.value)
}
})
} catch (error) {
@ -189,9 +188,9 @@ const submitEdit = async () => {
}
const handleEdit = (index, row) => {
dialogEditForm.value.oldData = row
dialogEditForm.value.oldIndex = index
dialogEditForm.value = row
dialogObjectForm.value = row
dialogObjectForm.value.oldData = row
dialogObjectForm.value.oldIndex = index
console.log("edit data:", row)
dialogEditVisible.value = true
}
@ -225,42 +224,41 @@ function addItem(fieldDescInfo) {
return;
}
let d = {id: item.value.id, num: Number(item.value.num)};
for (let i = 0; i < fieldDescInfo.choices.length; i++) {
const field = fieldDescInfo.choices[i]
if (field.value === item.value.id) {
d.item_type = field.type
break
}
}
let d = {id: item.value.id, num: Number(item.value.num), desc: item.value.desc, item_type: item.value.item_type};
console.log("add item:", d)
if (typeof dialogAddForm.value.Attach === typeof "") {
dialogAddForm.value.Attach = [];
if (typeof dialogObjectForm.value.Attach === typeof "") {
dialogObjectForm.value.Attach = [];
}
dialogAddForm.value.Attach.push(d);
dialogObjectForm.value.Attach.push(d);
}
function deleteItem(row) {
//
let number = form.value.Attach.findIndex(item => item === row);
dialogAddForm.value.Attach.splice(number, 1);
let number = dialogObjectForm.value.Attach.findIndex(item => item === row);
dialogObjectForm.value.Attach.splice(number, 1);
}
const handleCloseDialog = () => {
console.log("关闭添加/编辑弹窗")
dialogAddVisible.value = false
dialogEditVisible.value = false
dialogAddForm.value = {
dialogObjectForm.value = {
Attach: [],
}
dialogEditForm.value = {}
item.value.desc = ''
}
const loadingRemoteItems = ref(false)
const itemChoices = ref({})
const handleItemOnSelect = (itemOption) => {
console.log("选中:", itemOption)
item.value.id = itemOption.value
item.value.desc = itemOption.desc
}
const handleQueryItem = (itemQueryStr) => {
if (!itemQueryStr) {
itemChoices.value = []
@ -296,7 +294,7 @@ const resetConditionSearch = () => {
</template>
<template v-else>
<el-container v-if="listDataOK">
<el-header>
<el-header style="margin-bottom: 10px">
<el-row :gutter="20" v-if="(whereFieldsDescInfo.length !== 0)">
<template v-for="fieldDescInfo in whereFieldsDescInfo">
<template v-if="(fieldDescInfo.where === 'range')">
@ -344,7 +342,7 @@ const resetConditionSearch = () => {
<el-main>
<el-table :data="rows" style="width: 100%" table-layout="auto" stripe>
<template v-for="fieldDescInfo in fieldsDescInfo">
<el-table-column prop="jsonValue" :label="fieldDescInfo.name"
<el-table-column prop="jsonValue" :label="fieldDescInfo.name" show-overflow-tooltip
v-if="(fieldDescInfo.type === 'items')"></el-table-column>
<el-table-column :prop="fieldDescInfo.key" :label="fieldDescInfo.name"
v-else></el-table-column>
@ -384,7 +382,7 @@ const resetConditionSearch = () => {
<el-dialog v-model="dialogAddVisible" :mask="true" title="添加" :modal="true" :before-close="handleCloseDialog"
destroy-on-close>
<el-form ref="dialogAddFormRef" :model="dialogAddForm" :rules="rules" label-position="right"
<el-form ref="dialogAddFormRef" :model="dialogObjectForm" :rules="rules" label-position="right"
label-width="130px">
<template v-for="fieldDescInfo in fieldsDescInfo">
<!--如何是items类型就是物品下拉框+道具组合-->
@ -392,12 +390,15 @@ const resetConditionSearch = () => {
<el-form :inline="true" :model="item" label-position="right">
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key" label-width="130px">
<el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
<el-select v-model="item.id" placeholder="--搜索道具--" style="width: 150px"
<el-select v-model="item" placeholder="--搜索道具--" style="width: 150px"
filterable remote
:remote-method="handleQueryItem"
:loading="loadingRemoteItems">
:loading="loadingRemoteItems"
value-key="value"
@change="handleItemOnSelect"
>
<el-option v-for="info in itemChoices" :key="info.value" :label="info.desc"
:value="info.value"></el-option>
:value="info"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
@ -409,9 +410,10 @@ const resetConditionSearch = () => {
</el-form-item>
</el-form>
<el-form-item label="奖励列表" prop="Attach">
<el-table :data="dialogAddForm.Attach" border>
<el-table :data="dialogObjectForm.Attach" border>
<el-table-column label="道具id" prop="id"/>
<el-table-column label="数量" prop="num"/>
<el-table-column label="道具名" prop="desc"/>
<el-table-column label="操作">
<template #default="scope">
<el-button type="danger" size="small" @click="deleteItem(scope.row)">删除</el-button>
@ -427,7 +429,7 @@ const resetConditionSearch = () => {
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
<el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
v-model="dialogAddForm[fieldDescInfo.key]" style="width: 150px"
v-model="dialogObjectForm[fieldDescInfo.key]" style="width: 150px"
:multiple="(fieldDescInfo.multi_choice === true)">
<el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
:value="info.value"></el-option>
@ -439,7 +441,7 @@ const resetConditionSearch = () => {
<!-- 时间戳字段展示时间选择器 -->
<template v-else-if="(fieldDescInfo.type === 'Time')">
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-date-picker v-model="dialogAddForm[fieldDescInfo.key]" type="datetime"
<el-date-picker v-model="dialogObjectForm[fieldDescInfo.key]" type="datetime"
placeholder="选个时间" format="YYYY/MM/DD HH:mm:ss"
value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
</el-form-item>
@ -448,7 +450,7 @@ const resetConditionSearch = () => {
<!-- 否则就是普通字段 -->
<template v-else>
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-input v-model="dialogAddForm[fieldDescInfo.key]"
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text"></el-input>
</el-form-item>
</template>
@ -465,7 +467,7 @@ const resetConditionSearch = () => {
<el-dialog v-model="dialogEditVisible" :mask="true" title="编辑" :modal="true" :before-close="handleCloseDialog"
destroy-on-close>
<el-form ref="dialogEditFormRef" :model="dialogEditForm" :rules="rules" class="operation_form"
<el-form ref="dialogEditFormRef" :model="dialogObjectForm" :rules="rules" class="operation_form"
label-width="130px">
<template v-for="fieldDescInfo in fieldsDescInfo">
@ -475,10 +477,13 @@ const resetConditionSearch = () => {
label-width="130px">
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
<el-select placeholder="--搜索道具--" v-model="item.id" style="width: 150px"
filterable remote :remote-method="handleQueryItem" :loading="loadingRemoteItems">
<el-select placeholder="--搜索道具--" v-model="item" style="width: 150px"
filterable remote :remote-method="handleQueryItem"
:loading="loadingRemoteItems"
value-key="value"
>
<el-option v-for="info in itemChoices" :key="info.value" :label="info.desc"
:value="info.value"></el-option>
:value="info"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
@ -490,9 +495,10 @@ const resetConditionSearch = () => {
</el-form-item>
</el-form>
<el-form-item label="奖励列表" prop="attachmentsList">
<el-table :data="dialogEditForm.Attach" border>
<el-table :data="dialogObjectForm.Attach" border>
<el-table-column label="道具id" prop="id"/>
<el-table-column label="数量" prop="num"/>
<el-table-column label="道具名" prop="desc"/>
<el-table-column label="操作">
<template #default="scope">
<el-button type="danger" size="small" @click="deleteItem(scope.row)">删除</el-button>
@ -509,7 +515,7 @@ const resetConditionSearch = () => {
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
<el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
v-model="dialogEditForm[fieldDescInfo.key]" style="width: 150px"
v-model="dialogObjectForm[fieldDescInfo.key]" style="width: 150px"
:multiple="(fieldDescInfo.multi_choice === true)">
<el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
:value="info.value"></el-option>
@ -521,7 +527,7 @@ const resetConditionSearch = () => {
<!-- 时间戳字段展示时间选择器 -->
<template v-else-if="(fieldDescInfo.type === 'Time')">
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-date-picker v-model="dialogEditForm[fieldDescInfo.key]" type="datetime"
<el-date-picker v-model="dialogObjectForm[fieldDescInfo.key]" type="datetime"
placeholder="选个时间" format="YYYY/MM/DD HH:mm:ss"
value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
</el-form-item>
@ -530,7 +536,7 @@ const resetConditionSearch = () => {
<!-- 否则就是普通字段 -->
<template v-else>
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-input v-model="dialogEditForm[fieldDescInfo.key]"
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text"></el-input>
</el-form-item>
</template>
@ -538,7 +544,7 @@ const resetConditionSearch = () => {
<template v-else>
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-input v-model="dialogEditForm[fieldDescInfo.key]"
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text" disabled></el-input>
</el-form-item>
</template>

View File

@ -398,7 +398,7 @@ const handleGetUsedHistory = (index, row) => {
<el-main>
<el-table :data="rows" style="width: 100%" table-layout="auto" stripe>
<template v-for="fieldDescInfo in fieldsDescInfo">
<el-table-column prop="jsonValue" :label="fieldDescInfo.name"
<el-table-column prop="jsonValue" :label="fieldDescInfo.name" show-overflow-tooltip
v-if="(fieldDescInfo.type === 'items')"></el-table-column>
<el-table-column :prop="fieldDescInfo.key" :label="fieldDescInfo.name"
v-else></el-table-column>

View File

@ -71,7 +71,7 @@ const resInterceptor = (res) => {
})
} else {
console.log("interceptor err code", res)
ElMessageBox.alert("请求服务器成功,但是逻辑错误:" + res.data.msg, "服务器错误码[" + code + "]", {
ElMessageBox.alert(res.data.msg, "服务器错误码[" + code + "]", {
type: "warning",
confirmButtonText: '知道了',
})

View File

@ -8,4 +8,5 @@
- [x] 执行历史记录
- [ ] 执行历史查看和条件检索
- [ ] 公告发送游戏
- [ ] 奖励码接入
- [x] 奖励码接入
- [x] 统一错误码内容