统一错误码
This commit is contained in:
parent
aea644c553
commit
9d2f572c35
@ -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
|
||||
}
|
||||
|
@ -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": "",
|
||||
})
|
||||
}
|
||||
|
||||
|
14
admin/cmd/tools/generator/errcode.go
Normal file
14
admin/cmd/tools/generator/errcode.go
Normal 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()
|
||||
}
|
195
admin/cmd/tools/generator/errcode/gen.go
Normal file
195
admin/cmd/tools/generator/errcode/gen.go
Normal 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
|
||||
}
|
69
admin/cmd/tools/generator/errcode/tpl.go
Normal file
69
admin/cmd/tools/generator/errcode/tpl.go
Normal 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)
|
||||
}
|
||||
}
|
12
admin/go.mod
12
admin/go.mod
@ -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
|
||||
)
|
||||
|
24
admin/go.sum
24
admin/go.sum
@ -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=
|
||||
|
@ -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
|
||||
|
@ -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返回
|
||||
|
41
admin/internal/errcode/code_content.gen.go
Normal file
41
admin/internal/errcode/code_content.gen.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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()))
|
||||
}
|
||||
|
62
admin/lib/gofmt/counter/counter.go
Normal file
62
admin/lib/gofmt/counter/counter.go
Normal 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()
|
||||
}
|
||||
})
|
||||
}
|
20
admin/lib/gofmt/counter/counter_bootstrap.go
Normal file
20
admin/lib/gofmt/counter/counter_bootstrap.go
Normal 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
515
admin/lib/gofmt/gofmt.go
Normal 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
|
||||
}
|
195
admin/lib/gofmt/gofmt_test.go
Normal file
195
admin/lib/gofmt/gofmt_test.go
Normal file
@ -0,0 +1,195 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package 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)
|
||||
}
|
67
admin/lib/gofmt/gofmt_unix_test.go
Normal file
67
admin/lib/gofmt/gofmt_unix_test.go
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package 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
176
admin/lib/gofmt/internal.go
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// TODO(gri): This file and the file src/go/format/internal.go are
|
||||
// the same (but for this comment and the package name). Do not modify
|
||||
// one without the other. Determine if we can factor out functionality
|
||||
// in a public API. See also #11844 for context.
|
||||
|
||||
package 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'
|
||||
}
|
172
admin/lib/gofmt/long_test.go
Normal file
172
admin/lib/gofmt/long_test.go
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This test applies gofmt to all Go files under -root.
|
||||
// To test specific files provide a list of comma-separated
|
||||
// filenames via the -files flag: go test -files=gofmt.go .
|
||||
|
||||
package 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
309
admin/lib/gofmt/rewrite.go
Normal file
@ -0,0 +1,309 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package 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
169
admin/lib/gofmt/simplify.go
Normal file
@ -0,0 +1,169 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package 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
|
||||
}
|
9
admin/lib/gofmt/testdata/comments.golden
vendored
Normal file
9
admin/lib/gofmt/testdata/comments.golden
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
// comment here
|
||||
|
||||
func f() {}
|
||||
|
||||
//line foo.go:1
|
9
admin/lib/gofmt/testdata/comments.input
vendored
Normal file
9
admin/lib/gofmt/testdata/comments.input
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
// comment here
|
||||
|
||||
func f() {}
|
||||
|
||||
//line foo.go:1
|
218
admin/lib/gofmt/testdata/composites.golden
vendored
Normal file
218
admin/lib/gofmt/testdata/composites.golden
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
//gofmt -s
|
||||
|
||||
package P
|
||||
|
||||
type T struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
w, z int
|
||||
}
|
||||
|
||||
var _ = [42]T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []struct {
|
||||
x, y int
|
||||
}{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
T{},
|
||||
10: T{1, 2},
|
||||
20: T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
([]int{}),
|
||||
([]int{1, 2}),
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][][]int{
|
||||
{},
|
||||
{
|
||||
{},
|
||||
{0, 1, 2, 3},
|
||||
{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]T{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": T{},
|
||||
"bar": T{1, 2},
|
||||
"bal": T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": ([]int{}),
|
||||
"bar": ([]int{1, 2}),
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
// from exp/4s/data.go
|
||||
var pieces4 = []Piece{
|
||||
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
}
|
||||
|
||||
var _ = [42]*T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]*T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []*struct {
|
||||
x, y int
|
||||
}{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
&T{},
|
||||
10: &T{1, 2},
|
||||
20: &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
(&[]int{}),
|
||||
(&[]int{1, 2}),
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]*[]int{
|
||||
{},
|
||||
{
|
||||
{},
|
||||
{0, 1, 2, 3},
|
||||
{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]*T{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": &T{},
|
||||
"bar": &T{1, 2},
|
||||
"bal": &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": (&[]int{}),
|
||||
"bar": (&[]int{1, 2}),
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var pieces4 = []*Piece{
|
||||
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
}
|
||||
|
||||
var _ = map[T]T2{
|
||||
{1, 2}: {3, 4},
|
||||
{5, 6}: {7, 8},
|
||||
}
|
||||
|
||||
var _ = map[*T]*T2{
|
||||
{1, 2}: {3, 4},
|
||||
{5, 6}: {7, 8},
|
||||
}
|
218
admin/lib/gofmt/testdata/composites.input
vendored
Normal file
218
admin/lib/gofmt/testdata/composites.input
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
//gofmt -s
|
||||
|
||||
package P
|
||||
|
||||
type T struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
w, z int
|
||||
}
|
||||
|
||||
var _ = [42]T{
|
||||
T{},
|
||||
T{1, 2},
|
||||
T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]T{
|
||||
T{},
|
||||
T{1, 2},
|
||||
T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
T{},
|
||||
T{1, 2},
|
||||
T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
T{},
|
||||
10: T{1, 2},
|
||||
20: T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []struct {
|
||||
x, y int
|
||||
}{
|
||||
struct{ x, y int }{},
|
||||
10: struct{ x, y int }{1, 2},
|
||||
20: struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
T{},
|
||||
10: T{1, 2},
|
||||
20: T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
[]int{},
|
||||
[]int{1, 2},
|
||||
[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
([]int{}),
|
||||
([]int{1, 2}),
|
||||
[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][][]int{
|
||||
[][]int{},
|
||||
[][]int{
|
||||
[]int{},
|
||||
[]int{0, 1, 2, 3},
|
||||
[]int{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]T{
|
||||
"foo": T{},
|
||||
"bar": T{1, 2},
|
||||
"bal": T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": struct{ x, y int }{},
|
||||
"bar": struct{ x, y int }{1, 2},
|
||||
"bal": struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": T{},
|
||||
"bar": T{1, 2},
|
||||
"bal": T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": []int{},
|
||||
"bar": []int{1, 2},
|
||||
"bal": []int{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": ([]int{}),
|
||||
"bar": ([]int{1, 2}),
|
||||
"bal": []int{3, 4},
|
||||
}
|
||||
|
||||
// from exp/4s/data.go
|
||||
var pieces4 = []Piece{
|
||||
Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
}
|
||||
|
||||
var _ = [42]*T{
|
||||
&T{},
|
||||
&T{1, 2},
|
||||
&T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]*T{
|
||||
&T{},
|
||||
&T{1, 2},
|
||||
&T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
&T{},
|
||||
&T{1, 2},
|
||||
&T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
&T{},
|
||||
10: &T{1, 2},
|
||||
20: &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*struct {
|
||||
x, y int
|
||||
}{
|
||||
&struct{ x, y int }{},
|
||||
10: &struct{ x, y int }{1, 2},
|
||||
20: &struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
&T{},
|
||||
10: &T{1, 2},
|
||||
20: &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
&[]int{},
|
||||
&[]int{1, 2},
|
||||
&[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
(&[]int{}),
|
||||
(&[]int{1, 2}),
|
||||
&[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]*[]int{
|
||||
&[]*[]int{},
|
||||
&[]*[]int{
|
||||
&[]int{},
|
||||
&[]int{0, 1, 2, 3},
|
||||
&[]int{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]*T{
|
||||
"foo": &T{},
|
||||
"bar": &T{1, 2},
|
||||
"bal": &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": &struct{ x, y int }{},
|
||||
"bar": &struct{ x, y int }{1, 2},
|
||||
"bal": &struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": &T{},
|
||||
"bar": &T{1, 2},
|
||||
"bal": &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": &[]int{},
|
||||
"bar": &[]int{1, 2},
|
||||
"bal": &[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": (&[]int{}),
|
||||
"bar": (&[]int{1, 2}),
|
||||
"bal": &[]int{3, 4},
|
||||
}
|
||||
|
||||
var pieces4 = []*Piece{
|
||||
&Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
&Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
}
|
||||
|
||||
var _ = map[T]T2{
|
||||
T{1, 2}: T2{3, 4},
|
||||
T{5, 6}: T2{7, 8},
|
||||
}
|
||||
|
||||
var _ = map[*T]*T2{
|
||||
&T{1, 2}: &T2{3, 4},
|
||||
&T{5, 6}: &T2{7, 8},
|
||||
}
|
13
admin/lib/gofmt/testdata/crlf.golden
vendored
Normal file
13
admin/lib/gofmt/testdata/crlf.golden
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
Source containing CR/LF line endings.
|
||||
The gofmt'ed output must only have LF
|
||||
line endings.
|
||||
Test case for issue 3961.
|
||||
*/
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// line comment
|
||||
println("hello, world!") // another line comment
|
||||
println()
|
||||
}
|
13
admin/lib/gofmt/testdata/crlf.input
vendored
Normal file
13
admin/lib/gofmt/testdata/crlf.input
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
Source containing CR/LF line endings.
|
||||
The gofmt'ed output must only have LF
|
||||
line endings.
|
||||
Test case for issue 3961.
|
||||
*/
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// line comment
|
||||
println("hello, world!") // another line comment
|
||||
println()
|
||||
}
|
14
admin/lib/gofmt/testdata/emptydecl.golden
vendored
Normal file
14
admin/lib/gofmt/testdata/emptydecl.golden
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test case for issue 7631.
|
||||
|
||||
package main
|
||||
|
||||
// Keep this declaration
|
||||
var ()
|
||||
|
||||
const (
|
||||
// Keep this declaration
|
||||
)
|
||||
|
||||
func main() {}
|
16
admin/lib/gofmt/testdata/emptydecl.input
vendored
Normal file
16
admin/lib/gofmt/testdata/emptydecl.input
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test case for issue 7631.
|
||||
|
||||
package main
|
||||
|
||||
// Keep this declaration
|
||||
var ()
|
||||
|
||||
const (
|
||||
// Keep this declaration
|
||||
)
|
||||
|
||||
type ()
|
||||
|
||||
func main() {}
|
186
admin/lib/gofmt/testdata/go2numbers.golden
vendored
Normal file
186
admin/lib/gofmt/testdata/go2numbers.golden
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
package p
|
||||
|
||||
const (
|
||||
// 0-octals
|
||||
_ = 0
|
||||
_ = 0123
|
||||
_ = 0123456
|
||||
|
||||
_ = 0_123
|
||||
_ = 0123_456
|
||||
|
||||
// decimals
|
||||
_ = 1
|
||||
_ = 1234
|
||||
_ = 1234567
|
||||
|
||||
_ = 1_234
|
||||
_ = 1_234_567
|
||||
|
||||
// hexadecimals
|
||||
_ = 0x0
|
||||
_ = 0x1234
|
||||
_ = 0xcafef00d
|
||||
|
||||
_ = 0x0
|
||||
_ = 0x1234
|
||||
_ = 0xCAFEf00d
|
||||
|
||||
_ = 0x_0
|
||||
_ = 0x_1234
|
||||
_ = 0x_CAFE_f00d
|
||||
|
||||
// octals
|
||||
_ = 0o0
|
||||
_ = 0o1234
|
||||
_ = 0o01234567
|
||||
|
||||
_ = 0o0
|
||||
_ = 0o1234
|
||||
_ = 0o01234567
|
||||
|
||||
_ = 0o_0
|
||||
_ = 0o_1234
|
||||
_ = 0o0123_4567
|
||||
|
||||
_ = 0o_0
|
||||
_ = 0o_1234
|
||||
_ = 0o0123_4567
|
||||
|
||||
// binaries
|
||||
_ = 0b0
|
||||
_ = 0b1011
|
||||
_ = 0b00101101
|
||||
|
||||
_ = 0b0
|
||||
_ = 0b1011
|
||||
_ = 0b00101101
|
||||
|
||||
_ = 0b_0
|
||||
_ = 0b10_11
|
||||
_ = 0b_0010_1101
|
||||
|
||||
// decimal floats
|
||||
_ = 0.
|
||||
_ = 123.
|
||||
_ = 0123.
|
||||
|
||||
_ = .0
|
||||
_ = .123
|
||||
_ = .0123
|
||||
|
||||
_ = 0e0
|
||||
_ = 123e+0
|
||||
_ = 0123e-1
|
||||
|
||||
_ = 0e-0
|
||||
_ = 123e+0
|
||||
_ = 0123e123
|
||||
|
||||
_ = 0.e+1
|
||||
_ = 123.e-10
|
||||
_ = 0123.e123
|
||||
|
||||
_ = .0e-1
|
||||
_ = .123e+10
|
||||
_ = .0123e123
|
||||
|
||||
_ = 0.0
|
||||
_ = 123.123
|
||||
_ = 0123.0123
|
||||
|
||||
_ = 0.0e1
|
||||
_ = 123.123e-10
|
||||
_ = 0123.0123e+456
|
||||
|
||||
_ = 1_2_3.
|
||||
_ = 0_123.
|
||||
|
||||
_ = 0_0e0
|
||||
_ = 1_2_3e0
|
||||
_ = 0_123e0
|
||||
|
||||
_ = 0e-0_0
|
||||
_ = 1_2_3e+0
|
||||
_ = 0123e1_2_3
|
||||
|
||||
_ = 0.e+1
|
||||
_ = 123.e-1_0
|
||||
_ = 01_23.e123
|
||||
|
||||
_ = .0e-1
|
||||
_ = .123e+10
|
||||
_ = .0123e123
|
||||
|
||||
_ = 1_2_3.123
|
||||
_ = 0123.01_23
|
||||
|
||||
// hexadecimal floats
|
||||
_ = 0x0.p+0
|
||||
_ = 0xdeadcafe.p-10
|
||||
_ = 0x1234.p123
|
||||
|
||||
_ = 0x.1p-0
|
||||
_ = 0x.deadcafep2
|
||||
_ = 0x.1234p+10
|
||||
|
||||
_ = 0x0p0
|
||||
_ = 0xdeadcafep+1
|
||||
_ = 0x1234p-10
|
||||
|
||||
_ = 0x0.0p0
|
||||
_ = 0xdead.cafep+1
|
||||
_ = 0x12.34p-10
|
||||
|
||||
_ = 0xdead_cafep+1
|
||||
_ = 0x_1234p-10
|
||||
|
||||
_ = 0x_dead_cafe.p-10
|
||||
_ = 0x12_34.p1_2_3
|
||||
_ = 0x1_2_3_4.p-1_2_3
|
||||
|
||||
// imaginaries
|
||||
_ = 0i
|
||||
_ = 0i
|
||||
_ = 8i
|
||||
_ = 0i
|
||||
_ = 123i
|
||||
_ = 123i
|
||||
_ = 56789i
|
||||
_ = 1234i
|
||||
_ = 1234567i
|
||||
|
||||
_ = 0i
|
||||
_ = 0i
|
||||
_ = 8i
|
||||
_ = 0i
|
||||
_ = 123i
|
||||
_ = 123i
|
||||
_ = 56_789i
|
||||
_ = 1_234i
|
||||
_ = 1_234_567i
|
||||
|
||||
_ = 0.i
|
||||
_ = 123.i
|
||||
_ = 0123.i
|
||||
_ = 000123.i
|
||||
|
||||
_ = 0e0i
|
||||
_ = 123e0i
|
||||
_ = 0123e0i
|
||||
_ = 000123e0i
|
||||
|
||||
_ = 0.e+1i
|
||||
_ = 123.e-1_0i
|
||||
_ = 01_23.e123i
|
||||
_ = 00_01_23.e123i
|
||||
|
||||
_ = 0b1010i
|
||||
_ = 0b1010i
|
||||
_ = 0o660i
|
||||
_ = 0o660i
|
||||
_ = 0xabcDEFi
|
||||
_ = 0xabcDEFi
|
||||
_ = 0xabcDEFp0i
|
||||
_ = 0xabcDEFp0i
|
||||
)
|
186
admin/lib/gofmt/testdata/go2numbers.input
vendored
Normal file
186
admin/lib/gofmt/testdata/go2numbers.input
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
package p
|
||||
|
||||
const (
|
||||
// 0-octals
|
||||
_ = 0
|
||||
_ = 0123
|
||||
_ = 0123456
|
||||
|
||||
_ = 0_123
|
||||
_ = 0123_456
|
||||
|
||||
// decimals
|
||||
_ = 1
|
||||
_ = 1234
|
||||
_ = 1234567
|
||||
|
||||
_ = 1_234
|
||||
_ = 1_234_567
|
||||
|
||||
// hexadecimals
|
||||
_ = 0x0
|
||||
_ = 0x1234
|
||||
_ = 0xcafef00d
|
||||
|
||||
_ = 0X0
|
||||
_ = 0X1234
|
||||
_ = 0XCAFEf00d
|
||||
|
||||
_ = 0X_0
|
||||
_ = 0X_1234
|
||||
_ = 0X_CAFE_f00d
|
||||
|
||||
// octals
|
||||
_ = 0o0
|
||||
_ = 0o1234
|
||||
_ = 0o01234567
|
||||
|
||||
_ = 0O0
|
||||
_ = 0O1234
|
||||
_ = 0O01234567
|
||||
|
||||
_ = 0o_0
|
||||
_ = 0o_1234
|
||||
_ = 0o0123_4567
|
||||
|
||||
_ = 0O_0
|
||||
_ = 0O_1234
|
||||
_ = 0O0123_4567
|
||||
|
||||
// binaries
|
||||
_ = 0b0
|
||||
_ = 0b1011
|
||||
_ = 0b00101101
|
||||
|
||||
_ = 0B0
|
||||
_ = 0B1011
|
||||
_ = 0B00101101
|
||||
|
||||
_ = 0b_0
|
||||
_ = 0b10_11
|
||||
_ = 0b_0010_1101
|
||||
|
||||
// decimal floats
|
||||
_ = 0.
|
||||
_ = 123.
|
||||
_ = 0123.
|
||||
|
||||
_ = .0
|
||||
_ = .123
|
||||
_ = .0123
|
||||
|
||||
_ = 0e0
|
||||
_ = 123e+0
|
||||
_ = 0123E-1
|
||||
|
||||
_ = 0e-0
|
||||
_ = 123E+0
|
||||
_ = 0123E123
|
||||
|
||||
_ = 0.e+1
|
||||
_ = 123.E-10
|
||||
_ = 0123.e123
|
||||
|
||||
_ = .0e-1
|
||||
_ = .123E+10
|
||||
_ = .0123E123
|
||||
|
||||
_ = 0.0
|
||||
_ = 123.123
|
||||
_ = 0123.0123
|
||||
|
||||
_ = 0.0e1
|
||||
_ = 123.123E-10
|
||||
_ = 0123.0123e+456
|
||||
|
||||
_ = 1_2_3.
|
||||
_ = 0_123.
|
||||
|
||||
_ = 0_0e0
|
||||
_ = 1_2_3e0
|
||||
_ = 0_123e0
|
||||
|
||||
_ = 0e-0_0
|
||||
_ = 1_2_3E+0
|
||||
_ = 0123E1_2_3
|
||||
|
||||
_ = 0.e+1
|
||||
_ = 123.E-1_0
|
||||
_ = 01_23.e123
|
||||
|
||||
_ = .0e-1
|
||||
_ = .123E+10
|
||||
_ = .0123E123
|
||||
|
||||
_ = 1_2_3.123
|
||||
_ = 0123.01_23
|
||||
|
||||
// hexadecimal floats
|
||||
_ = 0x0.p+0
|
||||
_ = 0Xdeadcafe.p-10
|
||||
_ = 0x1234.P123
|
||||
|
||||
_ = 0x.1p-0
|
||||
_ = 0X.deadcafep2
|
||||
_ = 0x.1234P+10
|
||||
|
||||
_ = 0x0p0
|
||||
_ = 0Xdeadcafep+1
|
||||
_ = 0x1234P-10
|
||||
|
||||
_ = 0x0.0p0
|
||||
_ = 0Xdead.cafep+1
|
||||
_ = 0x12.34P-10
|
||||
|
||||
_ = 0Xdead_cafep+1
|
||||
_ = 0x_1234P-10
|
||||
|
||||
_ = 0X_dead_cafe.p-10
|
||||
_ = 0x12_34.P1_2_3
|
||||
_ = 0X1_2_3_4.P-1_2_3
|
||||
|
||||
// imaginaries
|
||||
_ = 0i
|
||||
_ = 00i
|
||||
_ = 08i
|
||||
_ = 0000000000i
|
||||
_ = 0123i
|
||||
_ = 0000000123i
|
||||
_ = 0000056789i
|
||||
_ = 1234i
|
||||
_ = 1234567i
|
||||
|
||||
_ = 0i
|
||||
_ = 0_0i
|
||||
_ = 0_8i
|
||||
_ = 0_000_000_000i
|
||||
_ = 0_123i
|
||||
_ = 0_000_000_123i
|
||||
_ = 0_000_056_789i
|
||||
_ = 1_234i
|
||||
_ = 1_234_567i
|
||||
|
||||
_ = 0.i
|
||||
_ = 123.i
|
||||
_ = 0123.i
|
||||
_ = 000123.i
|
||||
|
||||
_ = 0e0i
|
||||
_ = 123e0i
|
||||
_ = 0123E0i
|
||||
_ = 000123E0i
|
||||
|
||||
_ = 0.e+1i
|
||||
_ = 123.E-1_0i
|
||||
_ = 01_23.e123i
|
||||
_ = 00_01_23.e123i
|
||||
|
||||
_ = 0b1010i
|
||||
_ = 0B1010i
|
||||
_ = 0o660i
|
||||
_ = 0O660i
|
||||
_ = 0xabcDEFi
|
||||
_ = 0XabcDEFi
|
||||
_ = 0xabcDEFP0i
|
||||
_ = 0XabcDEFp0i
|
||||
)
|
194
admin/lib/gofmt/testdata/import.golden
vendored
Normal file
194
admin/lib/gofmt/testdata/import.golden
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
// package comment
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
// We reset the line numbering to test that
|
||||
// the formatting works independent of line directives
|
||||
//line :19
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
// a block with comments
|
||||
"errors"
|
||||
"fmt" // for Printf
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
// for Printf
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
// for Fatal
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
// for Reader
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt" // for Printf
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
|
||||
"errors"
|
||||
"fmt" // for Printf
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
)
|
||||
|
||||
// Test deduping and extended sorting
|
||||
import (
|
||||
a "A" // aA
|
||||
b "A" // bA1
|
||||
b "A" // bA2
|
||||
"B" // B
|
||||
. "B" // .B
|
||||
_ "B" // _b
|
||||
"C"
|
||||
a "D" // aD
|
||||
)
|
||||
|
||||
import (
|
||||
"dedup_by_group"
|
||||
|
||||
"dedup_by_group"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
/* comment */ io1 "io"
|
||||
/* comment */ io2 "io"
|
||||
/* comment */ "log"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
/* comment */ io1 "io"
|
||||
/* comment */ io2 "io" // hello
|
||||
"math" /* right side */
|
||||
// end
|
||||
)
|
||||
|
||||
import (
|
||||
"errors" // for New
|
||||
"fmt"
|
||||
/* comment */ io1 "io" /* before */ // after
|
||||
io2 "io" // another
|
||||
// end
|
||||
)
|
||||
|
||||
import (
|
||||
"errors" // for New
|
||||
/* left */ "fmt" /* right */
|
||||
"log" // for Fatal
|
||||
/* left */ "math" /* right */
|
||||
)
|
||||
|
||||
import /* why */ /* comment here? */ (
|
||||
/* comment */ "fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Reset it again
|
||||
//line :100
|
||||
|
||||
// Dedup with different import styles
|
||||
import (
|
||||
"path"
|
||||
. "path"
|
||||
_ "path"
|
||||
pathpkg "path"
|
||||
)
|
||||
|
||||
/* comment */
|
||||
import (
|
||||
"fmt"
|
||||
"math" // for Abs
|
||||
// This is a new run
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// End an import declaration in the same line
|
||||
// as the last import. See golang.org/issue/33538.
|
||||
// Note: Must be the last (or 2nd last) line of the file.
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
199
admin/lib/gofmt/testdata/import.input
vendored
Normal file
199
admin/lib/gofmt/testdata/import.input
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
// package comment
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"log"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
// We reset the line numbering to test that
|
||||
// the formatting works independent of line directives
|
||||
//line :19
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"log"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
// a block with comments
|
||||
"fmt" // for Printf
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
// for Printf
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
// for Fatal
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
// for Reader
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
|
||||
"fmt" // for Printf
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
// Test deduping and extended sorting
|
||||
import (
|
||||
"B" // B
|
||||
a "A" // aA
|
||||
b "A" // bA2
|
||||
b "A" // bA1
|
||||
. "B" // .B
|
||||
. "B"
|
||||
"C"
|
||||
"C"
|
||||
"C"
|
||||
a "D" // aD
|
||||
"B"
|
||||
_ "B" // _b
|
||||
)
|
||||
|
||||
import (
|
||||
"dedup_by_group"
|
||||
"dedup_by_group"
|
||||
|
||||
"dedup_by_group"
|
||||
)
|
||||
|
||||
import (
|
||||
/* comment */ io1 "io"
|
||||
"fmt" // for Printf
|
||||
/* comment */ "log"
|
||||
/* comment */ io2 "io"
|
||||
)
|
||||
|
||||
import (
|
||||
/* comment */ io2 "io" // hello
|
||||
/* comment */ io1 "io"
|
||||
"math" /* right side */
|
||||
"fmt"
|
||||
// end
|
||||
)
|
||||
|
||||
import (
|
||||
/* comment */ io1 "io" /* before */ // after
|
||||
"fmt"
|
||||
"errors" // for New
|
||||
io2 "io" // another
|
||||
// end
|
||||
)
|
||||
|
||||
import (
|
||||
/* left */ "fmt" /* right */
|
||||
"errors" // for New
|
||||
/* left */ "math" /* right */
|
||||
"log" // for Fatal
|
||||
)
|
||||
|
||||
import /* why */ /* comment here? */ (
|
||||
/* comment */ "fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Reset it again
|
||||
//line :100
|
||||
|
||||
// Dedup with different import styles
|
||||
import (
|
||||
"path"
|
||||
. "path"
|
||||
_ "path"
|
||||
"path"
|
||||
pathpkg "path"
|
||||
)
|
||||
|
||||
/* comment */
|
||||
import (
|
||||
"math" // for Abs
|
||||
"fmt"
|
||||
// This is a new run
|
||||
"errors"
|
||||
"fmt"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// End an import declaration in the same line
|
||||
// as the last import. See golang.org/issue/33538.
|
||||
// Note: Must be the last (or 2nd last) line of the file.
|
||||
import("fmt"
|
||||
"math")
|
13
admin/lib/gofmt/testdata/issue28082.golden
vendored
Normal file
13
admin/lib/gofmt/testdata/issue28082.golden
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// testcase for issue #28082
|
||||
|
||||
func foo() {}
|
||||
|
||||
func main() {}
|
||||
|
||||
func bar() {}
|
13
admin/lib/gofmt/testdata/issue28082.input
vendored
Normal file
13
admin/lib/gofmt/testdata/issue28082.input
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// testcase for issue #28082
|
||||
|
||||
func foo( ) {}
|
||||
|
||||
func main( ) {}
|
||||
|
||||
func bar() {}
|
30
admin/lib/gofmt/testdata/ranges.golden
vendored
Normal file
30
admin/lib/gofmt/testdata/ranges.golden
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test cases for range simplification.
|
||||
package p
|
||||
|
||||
func _() {
|
||||
for a, b = range x {
|
||||
}
|
||||
for a = range x {
|
||||
}
|
||||
for _, b = range x {
|
||||
}
|
||||
for range x {
|
||||
}
|
||||
|
||||
for a = range x {
|
||||
}
|
||||
for range x {
|
||||
}
|
||||
|
||||
for a, b := range x {
|
||||
}
|
||||
for a := range x {
|
||||
}
|
||||
for _, b := range x {
|
||||
}
|
||||
|
||||
for a := range x {
|
||||
}
|
||||
}
|
20
admin/lib/gofmt/testdata/ranges.input
vendored
Normal file
20
admin/lib/gofmt/testdata/ranges.input
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test cases for range simplification.
|
||||
package p
|
||||
|
||||
func _() {
|
||||
for a, b = range x {}
|
||||
for a, _ = range x {}
|
||||
for _, b = range x {}
|
||||
for _, _ = range x {}
|
||||
|
||||
for a = range x {}
|
||||
for _ = range x {}
|
||||
|
||||
for a, b := range x {}
|
||||
for a, _ := range x {}
|
||||
for _, b := range x {}
|
||||
|
||||
for a := range x {}
|
||||
}
|
14
admin/lib/gofmt/testdata/rewrite1.golden
vendored
Normal file
14
admin/lib/gofmt/testdata/rewrite1.golden
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//gofmt -r=Foo->Bar
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type Bar int
|
||||
|
||||
func main() {
|
||||
var a Bar
|
||||
println(a)
|
||||
}
|
14
admin/lib/gofmt/testdata/rewrite1.input
vendored
Normal file
14
admin/lib/gofmt/testdata/rewrite1.input
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//gofmt -r=Foo->Bar
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type Foo int
|
||||
|
||||
func main() {
|
||||
var a Foo
|
||||
println(a)
|
||||
}
|
19
admin/lib/gofmt/testdata/rewrite10.golden
vendored
Normal file
19
admin/lib/gofmt/testdata/rewrite10.golden
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//gofmt -r=a->a
|
||||
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 33103, 33104, and 33105.
|
||||
|
||||
package pkg
|
||||
|
||||
func fn() {
|
||||
_ = func() {
|
||||
switch {
|
||||
default:
|
||||
}
|
||||
}
|
||||
_ = func() string {}
|
||||
_ = func() { var ptr *string; println(ptr) }
|
||||
}
|
19
admin/lib/gofmt/testdata/rewrite10.input
vendored
Normal file
19
admin/lib/gofmt/testdata/rewrite10.input
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//gofmt -r=a->a
|
||||
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 33103, 33104, and 33105.
|
||||
|
||||
package pkg
|
||||
|
||||
func fn() {
|
||||
_ = func() {
|
||||
switch {
|
||||
default:
|
||||
}
|
||||
}
|
||||
_ = func() string {}
|
||||
_ = func() { var ptr *string; println(ptr) }
|
||||
}
|
12
admin/lib/gofmt/testdata/rewrite2.golden
vendored
Normal file
12
admin/lib/gofmt/testdata/rewrite2.golden
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//gofmt -r=int->bool
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
// Slices have nil Len values in the corresponding ast.ArrayType
|
||||
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
|
||||
// The rewriter must not crash in that case. Was issue 1696.
|
||||
func f() []bool {}
|
12
admin/lib/gofmt/testdata/rewrite2.input
vendored
Normal file
12
admin/lib/gofmt/testdata/rewrite2.input
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//gofmt -r=int->bool
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
// Slices have nil Len values in the corresponding ast.ArrayType
|
||||
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
|
||||
// The rewriter must not crash in that case. Was issue 1696.
|
||||
func f() []int {}
|
14
admin/lib/gofmt/testdata/rewrite3.golden
vendored
Normal file
14
admin/lib/gofmt/testdata/rewrite3.golden
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//gofmt -r=x->x
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// Field tags are *ast.BasicLit nodes that are nil when the tag is
|
||||
// absent. These nil nodes must not be mistaken for expressions,
|
||||
// the rewriter should not try to dereference them. Was issue 2410.
|
||||
type Foo struct {
|
||||
Field int
|
||||
}
|
14
admin/lib/gofmt/testdata/rewrite3.input
vendored
Normal file
14
admin/lib/gofmt/testdata/rewrite3.input
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//gofmt -r=x->x
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// Field tags are *ast.BasicLit nodes that are nil when the tag is
|
||||
// absent. These nil nodes must not be mistaken for expressions,
|
||||
// the rewriter should not try to dereference them. Was issue 2410.
|
||||
type Foo struct {
|
||||
Field int
|
||||
}
|
76
admin/lib/gofmt/testdata/rewrite4.golden
vendored
Normal file
76
admin/lib/gofmt/testdata/rewrite4.golden
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
//gofmt -r=(x)->x
|
||||
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of parenthesized expressions (x) -> x
|
||||
// must not drop parentheses if that would lead to
|
||||
// wrong association of the operands.
|
||||
// Was issue 1847.
|
||||
|
||||
package main
|
||||
|
||||
// From example 1 of issue 1847.
|
||||
func _() {
|
||||
var t = (&T{1000}).Id()
|
||||
}
|
||||
|
||||
// From example 2 of issue 1847.
|
||||
func _() {
|
||||
fmt.Println((*xpp).a)
|
||||
}
|
||||
|
||||
// Some more test cases.
|
||||
func _() {
|
||||
_ = (-x).f
|
||||
_ = (*x).f
|
||||
_ = (&x).f
|
||||
_ = (!x).f
|
||||
_ = -x.f
|
||||
_ = *x.f
|
||||
_ = &x.f
|
||||
_ = !x.f
|
||||
(-x).f()
|
||||
(*x).f()
|
||||
(&x).f()
|
||||
(!x).f()
|
||||
_ = -x.f()
|
||||
_ = *x.f()
|
||||
_ = &x.f()
|
||||
_ = !x.f()
|
||||
|
||||
_ = (-x).f
|
||||
_ = (*x).f
|
||||
_ = (&x).f
|
||||
_ = (!x).f
|
||||
_ = -x.f
|
||||
_ = *x.f
|
||||
_ = &x.f
|
||||
_ = !x.f
|
||||
(-x).f()
|
||||
(*x).f()
|
||||
(&x).f()
|
||||
(!x).f()
|
||||
_ = -x.f()
|
||||
_ = *x.f()
|
||||
_ = &x.f()
|
||||
_ = !x.f()
|
||||
|
||||
_ = -x.f
|
||||
_ = *x.f
|
||||
_ = &x.f
|
||||
_ = !x.f
|
||||
_ = -x.f
|
||||
_ = *x.f
|
||||
_ = &x.f
|
||||
_ = !x.f
|
||||
_ = -x.f()
|
||||
_ = *x.f()
|
||||
_ = &x.f()
|
||||
_ = !x.f()
|
||||
_ = -x.f()
|
||||
_ = *x.f()
|
||||
_ = &x.f()
|
||||
_ = !x.f()
|
||||
}
|
76
admin/lib/gofmt/testdata/rewrite4.input
vendored
Normal file
76
admin/lib/gofmt/testdata/rewrite4.input
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
//gofmt -r=(x)->x
|
||||
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of parenthesized expressions (x) -> x
|
||||
// must not drop parentheses if that would lead to
|
||||
// wrong association of the operands.
|
||||
// Was issue 1847.
|
||||
|
||||
package main
|
||||
|
||||
// From example 1 of issue 1847.
|
||||
func _() {
|
||||
var t = (&T{1000}).Id()
|
||||
}
|
||||
|
||||
// From example 2 of issue 1847.
|
||||
func _() {
|
||||
fmt.Println((*xpp).a)
|
||||
}
|
||||
|
||||
// Some more test cases.
|
||||
func _() {
|
||||
_ = (-x).f
|
||||
_ = (*x).f
|
||||
_ = (&x).f
|
||||
_ = (!x).f
|
||||
_ = (-x.f)
|
||||
_ = (*x.f)
|
||||
_ = (&x.f)
|
||||
_ = (!x.f)
|
||||
(-x).f()
|
||||
(*x).f()
|
||||
(&x).f()
|
||||
(!x).f()
|
||||
_ = (-x.f())
|
||||
_ = (*x.f())
|
||||
_ = (&x.f())
|
||||
_ = (!x.f())
|
||||
|
||||
_ = ((-x)).f
|
||||
_ = ((*x)).f
|
||||
_ = ((&x)).f
|
||||
_ = ((!x)).f
|
||||
_ = ((-x.f))
|
||||
_ = ((*x.f))
|
||||
_ = ((&x.f))
|
||||
_ = ((!x.f))
|
||||
((-x)).f()
|
||||
((*x)).f()
|
||||
((&x)).f()
|
||||
((!x)).f()
|
||||
_ = ((-x.f()))
|
||||
_ = ((*x.f()))
|
||||
_ = ((&x.f()))
|
||||
_ = ((!x.f()))
|
||||
|
||||
_ = -(x).f
|
||||
_ = *(x).f
|
||||
_ = &(x).f
|
||||
_ = !(x).f
|
||||
_ = -x.f
|
||||
_ = *x.f
|
||||
_ = &x.f
|
||||
_ = !x.f
|
||||
_ = -(x).f()
|
||||
_ = *(x).f()
|
||||
_ = &(x).f()
|
||||
_ = !(x).f()
|
||||
_ = -x.f()
|
||||
_ = *x.f()
|
||||
_ = &x.f()
|
||||
_ = !x.f()
|
||||
}
|
17
admin/lib/gofmt/testdata/rewrite5.golden
vendored
Normal file
17
admin/lib/gofmt/testdata/rewrite5.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//gofmt -r=x+x->2*x
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of expressions containing nodes with associated comments to
|
||||
// expressions without those nodes must also eliminate the associated
|
||||
// comments.
|
||||
|
||||
package p
|
||||
|
||||
func f(x int) int {
|
||||
_ = 2 * x // this comment remains in the rewrite
|
||||
_ = 2 * x
|
||||
return 2 * x
|
||||
}
|
17
admin/lib/gofmt/testdata/rewrite5.input
vendored
Normal file
17
admin/lib/gofmt/testdata/rewrite5.input
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//gofmt -r=x+x->2*x
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of expressions containing nodes with associated comments to
|
||||
// expressions without those nodes must also eliminate the associated
|
||||
// comments.
|
||||
|
||||
package p
|
||||
|
||||
func f(x int) int {
|
||||
_ = x + x // this comment remains in the rewrite
|
||||
_ = x /* this comment must not be in the rewrite */ + x
|
||||
return x /* this comment must not be in the rewrite */ + x
|
||||
}
|
17
admin/lib/gofmt/testdata/rewrite6.golden
vendored
Normal file
17
admin/lib/gofmt/testdata/rewrite6.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//gofmt -r=fun(x)->Fun(x)
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of calls must take the ... (ellipsis)
|
||||
// attribute for the last argument into account.
|
||||
|
||||
package p
|
||||
|
||||
func fun(x []int) {}
|
||||
|
||||
func g(x []int) {
|
||||
Fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
|
||||
fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
|
||||
}
|
17
admin/lib/gofmt/testdata/rewrite6.input
vendored
Normal file
17
admin/lib/gofmt/testdata/rewrite6.input
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//gofmt -r=fun(x)->Fun(x)
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of calls must take the ... (ellipsis)
|
||||
// attribute for the last argument into account.
|
||||
|
||||
package p
|
||||
|
||||
func fun(x []int) {}
|
||||
|
||||
func g(x []int) {
|
||||
fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
|
||||
fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
|
||||
}
|
17
admin/lib/gofmt/testdata/rewrite7.golden
vendored
Normal file
17
admin/lib/gofmt/testdata/rewrite7.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//gofmt -r=fun(x...)->Fun(x)
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of calls must take the ... (ellipsis)
|
||||
// attribute for the last argument into account.
|
||||
|
||||
package p
|
||||
|
||||
func fun(x []int) {}
|
||||
|
||||
func g(x []int) {
|
||||
fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
|
||||
Fun(x) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
|
||||
}
|
17
admin/lib/gofmt/testdata/rewrite7.input
vendored
Normal file
17
admin/lib/gofmt/testdata/rewrite7.input
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//gofmt -r=fun(x...)->Fun(x)
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Rewriting of calls must take the ... (ellipsis)
|
||||
// attribute for the last argument into account.
|
||||
|
||||
package p
|
||||
|
||||
func fun(x []int) {}
|
||||
|
||||
func g(x []int) {
|
||||
fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
|
||||
fun(x...) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
|
||||
}
|
12
admin/lib/gofmt/testdata/rewrite8.golden
vendored
Normal file
12
admin/lib/gofmt/testdata/rewrite8.golden
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//gofmt -r=interface{}->int
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Check that literal type expression rewrites are accepted.
|
||||
// Was issue 4406.
|
||||
|
||||
package p
|
||||
|
||||
type T int
|
12
admin/lib/gofmt/testdata/rewrite8.input
vendored
Normal file
12
admin/lib/gofmt/testdata/rewrite8.input
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
//gofmt -r=interface{}->int
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Check that literal type expression rewrites are accepted.
|
||||
// Was issue 4406.
|
||||
|
||||
package p
|
||||
|
||||
type T interface{}
|
11
admin/lib/gofmt/testdata/rewrite9.golden
vendored
Normal file
11
admin/lib/gofmt/testdata/rewrite9.golden
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//gofmt -r=a&&b!=2->a
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 18987.
|
||||
|
||||
package p
|
||||
|
||||
const _ = x != 1
|
11
admin/lib/gofmt/testdata/rewrite9.input
vendored
Normal file
11
admin/lib/gofmt/testdata/rewrite9.input
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//gofmt -r=a&&b!=2->a
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 18987.
|
||||
|
||||
package p
|
||||
|
||||
const _ = x != 1 && x != 2
|
66
admin/lib/gofmt/testdata/slices1.golden
vendored
Normal file
66
admin/lib/gofmt/testdata/slices1.golden
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test cases for slice expression simplification.
|
||||
package p
|
||||
|
||||
var (
|
||||
a [10]byte
|
||||
b [20]float32
|
||||
s []int
|
||||
t struct {
|
||||
s []byte
|
||||
}
|
||||
|
||||
_ = a[0:]
|
||||
_ = a[1:10]
|
||||
_ = a[2:]
|
||||
_ = a[3:(len(a))]
|
||||
_ = a[len(a) : len(a)-1]
|
||||
_ = a[0:len(b)]
|
||||
_ = a[2:len(a):len(a)]
|
||||
|
||||
_ = a[:]
|
||||
_ = a[:10]
|
||||
_ = a[:]
|
||||
_ = a[:(len(a))]
|
||||
_ = a[:len(a)-1]
|
||||
_ = a[:len(b)]
|
||||
_ = a[:len(a):len(a)]
|
||||
|
||||
_ = s[0:]
|
||||
_ = s[1:10]
|
||||
_ = s[2:]
|
||||
_ = s[3:(len(s))]
|
||||
_ = s[len(a) : len(s)-1]
|
||||
_ = s[0:len(b)]
|
||||
_ = s[2:len(s):len(s)]
|
||||
|
||||
_ = s[:]
|
||||
_ = s[:10]
|
||||
_ = s[:]
|
||||
_ = s[:(len(s))]
|
||||
_ = s[:len(s)-1]
|
||||
_ = s[:len(b)]
|
||||
_ = s[:len(s):len(s)]
|
||||
|
||||
_ = t.s[0:]
|
||||
_ = t.s[1:10]
|
||||
_ = t.s[2:len(t.s)]
|
||||
_ = t.s[3:(len(t.s))]
|
||||
_ = t.s[len(a) : len(t.s)-1]
|
||||
_ = t.s[0:len(b)]
|
||||
_ = t.s[2:len(t.s):len(t.s)]
|
||||
|
||||
_ = t.s[:]
|
||||
_ = t.s[:10]
|
||||
_ = t.s[:len(t.s)]
|
||||
_ = t.s[:(len(t.s))]
|
||||
_ = t.s[:len(t.s)-1]
|
||||
_ = t.s[:len(b)]
|
||||
_ = t.s[:len(t.s):len(t.s)]
|
||||
)
|
||||
|
||||
func _() {
|
||||
s := s[0:]
|
||||
_ = s
|
||||
}
|
66
admin/lib/gofmt/testdata/slices1.input
vendored
Normal file
66
admin/lib/gofmt/testdata/slices1.input
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
//gofmt -s
|
||||
|
||||
// Test cases for slice expression simplification.
|
||||
package p
|
||||
|
||||
var (
|
||||
a [10]byte
|
||||
b [20]float32
|
||||
s []int
|
||||
t struct {
|
||||
s []byte
|
||||
}
|
||||
|
||||
_ = a[0:]
|
||||
_ = a[1:10]
|
||||
_ = a[2:len(a)]
|
||||
_ = a[3:(len(a))]
|
||||
_ = a[len(a) : len(a)-1]
|
||||
_ = a[0:len(b)]
|
||||
_ = a[2:len(a):len(a)]
|
||||
|
||||
_ = a[:]
|
||||
_ = a[:10]
|
||||
_ = a[:len(a)]
|
||||
_ = a[:(len(a))]
|
||||
_ = a[:len(a)-1]
|
||||
_ = a[:len(b)]
|
||||
_ = a[:len(a):len(a)]
|
||||
|
||||
_ = s[0:]
|
||||
_ = s[1:10]
|
||||
_ = s[2:len(s)]
|
||||
_ = s[3:(len(s))]
|
||||
_ = s[len(a) : len(s)-1]
|
||||
_ = s[0:len(b)]
|
||||
_ = s[2:len(s):len(s)]
|
||||
|
||||
_ = s[:]
|
||||
_ = s[:10]
|
||||
_ = s[:len(s)]
|
||||
_ = s[:(len(s))]
|
||||
_ = s[:len(s)-1]
|
||||
_ = s[:len(b)]
|
||||
_ = s[:len(s):len(s)]
|
||||
|
||||
_ = t.s[0:]
|
||||
_ = t.s[1:10]
|
||||
_ = t.s[2:len(t.s)]
|
||||
_ = t.s[3:(len(t.s))]
|
||||
_ = t.s[len(a) : len(t.s)-1]
|
||||
_ = t.s[0:len(b)]
|
||||
_ = t.s[2:len(t.s):len(t.s)]
|
||||
|
||||
_ = t.s[:]
|
||||
_ = t.s[:10]
|
||||
_ = t.s[:len(t.s)]
|
||||
_ = t.s[:(len(t.s))]
|
||||
_ = t.s[:len(t.s)-1]
|
||||
_ = t.s[:len(b)]
|
||||
_ = t.s[:len(t.s):len(t.s)]
|
||||
)
|
||||
|
||||
func _() {
|
||||
s := s[0:len(s)]
|
||||
_ = s
|
||||
}
|
5
admin/lib/gofmt/testdata/stdin1.golden
vendored
Normal file
5
admin/lib/gofmt/testdata/stdin1.golden
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if x {
|
||||
y
|
||||
}
|
5
admin/lib/gofmt/testdata/stdin1.input
vendored
Normal file
5
admin/lib/gofmt/testdata/stdin1.input
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if x {
|
||||
y
|
||||
}
|
11
admin/lib/gofmt/testdata/stdin2.golden
vendored
Normal file
11
admin/lib/gofmt/testdata/stdin2.golden
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//gofmt -stdin
|
||||
|
||||
var x int
|
||||
|
||||
func f() {
|
||||
y := z
|
||||
/* this is a comment */
|
||||
// this is a comment too
|
||||
}
|
||||
|
||||
|
11
admin/lib/gofmt/testdata/stdin2.input
vendored
Normal file
11
admin/lib/gofmt/testdata/stdin2.input
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//gofmt -stdin
|
||||
|
||||
var x int
|
||||
|
||||
|
||||
func f() { y := z
|
||||
/* this is a comment */
|
||||
// this is a comment too
|
||||
}
|
||||
|
||||
|
7
admin/lib/gofmt/testdata/stdin3.golden
vendored
Normal file
7
admin/lib/gofmt/testdata/stdin3.golden
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
//gofmt -stdin
|
||||
|
||||
/* note: no newline at end of file */
|
||||
for i := 0; i < 10; i++ {
|
||||
s += i
|
||||
}
|
||||
|
5
admin/lib/gofmt/testdata/stdin3.input
vendored
Normal file
5
admin/lib/gofmt/testdata/stdin3.input
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
/* note: no newline at end of file */
|
||||
for i := 0; i < 10; i++ { s += i }
|
||||
|
5
admin/lib/gofmt/testdata/stdin4.golden
vendored
Normal file
5
admin/lib/gofmt/testdata/stdin4.golden
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
// comment
|
||||
|
||||
i := 0
|
5
admin/lib/gofmt/testdata/stdin4.input
vendored
Normal file
5
admin/lib/gofmt/testdata/stdin4.input
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
//gofmt -stdin
|
||||
|
||||
// comment
|
||||
|
||||
i := 0
|
3
admin/lib/gofmt/testdata/stdin5.golden
vendored
Normal file
3
admin/lib/gofmt/testdata/stdin5.golden
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
//gofmt -stdin
|
||||
|
||||
i := 5 // Line comment without newline.
|
3
admin/lib/gofmt/testdata/stdin5.input
vendored
Normal file
3
admin/lib/gofmt/testdata/stdin5.input
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
//gofmt -stdin
|
||||
|
||||
i :=5// Line comment without newline.
|
19
admin/lib/gofmt/testdata/stdin6.golden
vendored
Normal file
19
admin/lib/gofmt/testdata/stdin6.golden
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if err != nil {
|
||||
source := strings.NewReader(`line 1.
|
||||
line 2.
|
||||
`)
|
||||
return source
|
||||
}
|
||||
|
||||
f := func(hat, tail string) {
|
||||
|
||||
fmt.Println(hat+`
|
||||
foo
|
||||
|
||||
|
||||
`+tail,
|
||||
"more",
|
||||
"and more")
|
||||
}
|
21
admin/lib/gofmt/testdata/stdin6.input
vendored
Normal file
21
admin/lib/gofmt/testdata/stdin6.input
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if err != nil {
|
||||
source := strings.NewReader(`line 1.
|
||||
line 2.
|
||||
`)
|
||||
return source
|
||||
}
|
||||
|
||||
f:=func( hat, tail string){
|
||||
|
||||
|
||||
|
||||
fmt. Println ( hat+ `
|
||||
foo
|
||||
|
||||
|
||||
`+ tail ,
|
||||
"more" ,
|
||||
"and more" )
|
||||
}
|
19
admin/lib/gofmt/testdata/stdin7.golden
vendored
Normal file
19
admin/lib/gofmt/testdata/stdin7.golden
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if err != nil {
|
||||
source := strings.NewReader(`line 1.
|
||||
line 2.
|
||||
`)
|
||||
return source
|
||||
}
|
||||
|
||||
f := func(hat, tail string) {
|
||||
|
||||
fmt.Println(hat+`
|
||||
foo
|
||||
|
||||
|
||||
`+tail,
|
||||
"more",
|
||||
"and more")
|
||||
}
|
21
admin/lib/gofmt/testdata/stdin7.input
vendored
Normal file
21
admin/lib/gofmt/testdata/stdin7.input
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
//gofmt -stdin
|
||||
|
||||
if err != nil {
|
||||
source := strings.NewReader(`line 1.
|
||||
line 2.
|
||||
`)
|
||||
return source
|
||||
}
|
||||
|
||||
f:=func( hat, tail string){
|
||||
|
||||
|
||||
|
||||
fmt. Println ( hat+ `
|
||||
foo
|
||||
|
||||
|
||||
`+ tail ,
|
||||
"more" ,
|
||||
"and more" )
|
||||
}
|
33
admin/lib/gofmt/testdata/tabs.golden
vendored
Normal file
33
admin/lib/gofmt/testdata/tabs.golden
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//gofmt
|
||||
|
||||
package main
|
||||
|
||||
var _ = []struct {
|
||||
S string
|
||||
Integer int
|
||||
}{
|
||||
{
|
||||
S: "Hello World",
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: "\t",
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: " ", // an actual <tab>
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: ` `, // an actual <tab>
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: "\u0009",
|
||||
Integer: 42,
|
||||
},
|
||||
}
|
33
admin/lib/gofmt/testdata/tabs.input
vendored
Normal file
33
admin/lib/gofmt/testdata/tabs.input
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//gofmt
|
||||
|
||||
package main
|
||||
|
||||
var _ = []struct{
|
||||
S string
|
||||
Integer int
|
||||
}{
|
||||
{
|
||||
S: "Hello World",
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: "\t",
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: " ", // an actual <tab>
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: ` `, // an actual <tab>
|
||||
Integer: 42,
|
||||
},
|
||||
{
|
||||
S: "\u0009",
|
||||
Integer: 42,
|
||||
},
|
||||
}
|
24
admin/lib/gofmt/testdata/typealias.golden
vendored
Normal file
24
admin/lib/gofmt/testdata/typealias.golden
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package q
|
||||
|
||||
import "p"
|
||||
|
||||
type _ = int
|
||||
type a = struct{ x int }
|
||||
type b = p.B
|
||||
|
||||
type (
|
||||
_ = chan<- int
|
||||
aa = interface{}
|
||||
bb = p.BB
|
||||
)
|
||||
|
||||
// TODO(gri) We may want to put the '=' into a separate column if
|
||||
// we have mixed (regular and alias) type declarations in a group.
|
||||
type (
|
||||
_ chan<- int
|
||||
_ = chan<- int
|
||||
aa0 interface{}
|
||||
aaa = interface{}
|
||||
bb0 p.BB
|
||||
bbb = p.BB
|
||||
)
|
24
admin/lib/gofmt/testdata/typealias.input
vendored
Normal file
24
admin/lib/gofmt/testdata/typealias.input
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package q
|
||||
|
||||
import "p"
|
||||
|
||||
type _ = int
|
||||
type a = struct{ x int }
|
||||
type b = p.B
|
||||
|
||||
type (
|
||||
_ = chan<- int
|
||||
aa = interface{}
|
||||
bb = p.BB
|
||||
)
|
||||
|
||||
// TODO(gri) We may want to put the '=' into a separate column if
|
||||
// we have mixed (regular and alias) type declarations in a group.
|
||||
type (
|
||||
_ chan<- int
|
||||
_ = chan<- int
|
||||
aa0 interface{}
|
||||
aaa = interface{}
|
||||
bb0 p.BB
|
||||
bbb = p.BB
|
||||
)
|
35
admin/lib/gofmt/testdata/typeparams.golden
vendored
Normal file
35
admin/lib/gofmt/testdata/typeparams.golden
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//gofmt
|
||||
|
||||
package typeparams
|
||||
|
||||
type T[P any] struct{}
|
||||
type T[P1, P2, P3 any] struct{}
|
||||
|
||||
type T[P C] struct{}
|
||||
type T[P1, P2, P3 C] struct{}
|
||||
|
||||
type T[P C[P]] struct{}
|
||||
type T[P1, P2, P3 C[P1, P2, P3]] struct{}
|
||||
|
||||
func f[P any](x P)
|
||||
func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
|
||||
|
||||
func f[P interface{}](x P)
|
||||
func f[P1, P2, P3 interface {
|
||||
m1(P1)
|
||||
~P2 | ~P3
|
||||
}](x1 P1, x2 P2, x3 P3) struct{}
|
||||
func f[P any](T1[P], T2[P]) T3[P]
|
||||
|
||||
func (x T[P]) m()
|
||||
func (T[P]) m(x T[P]) P
|
||||
|
||||
func _() {
|
||||
type _ []T[P]
|
||||
var _ []T[P]
|
||||
_ = []T[P]{}
|
||||
}
|
32
admin/lib/gofmt/testdata/typeparams.input
vendored
Normal file
32
admin/lib/gofmt/testdata/typeparams.input
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//gofmt
|
||||
|
||||
package typeparams
|
||||
|
||||
type T[ P any] struct{}
|
||||
type T[P1, P2, P3 any] struct{}
|
||||
|
||||
type T[P C] struct{}
|
||||
type T[P1,P2, P3 C] struct{}
|
||||
|
||||
type T[P C[P]] struct{}
|
||||
type T[P1, P2, P3 C[P1,P2,P3]] struct{}
|
||||
|
||||
func f[P any](x P)
|
||||
func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
|
||||
|
||||
func f[P interface{}](x P)
|
||||
func f[P1, P2, P3 interface{ m1(P1); ~P2|~P3 }](x1 P1, x2 P2, x3 P3) struct{}
|
||||
func f[P any](T1[P], T2[P]) T3[P]
|
||||
|
||||
func (x T[P]) m()
|
||||
func ((T[P])) m(x T[P]) P
|
||||
|
||||
func _() {
|
||||
type _ []T[P]
|
||||
var _ []T[P]
|
||||
_ = []T[P]{}
|
||||
}
|
60
admin/lib/gofmt/testdata/typeswitch.golden
vendored
Normal file
60
admin/lib/gofmt/testdata/typeswitch.golden
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Parenthesized type switch expressions originally
|
||||
accepted by gofmt must continue to be rewritten
|
||||
into the correct unparenthesized form.
|
||||
|
||||
Only type-switches that didn't declare a variable
|
||||
in the type switch type assertion and which
|
||||
contained only "expression-like" (named) types in their
|
||||
cases were permitted to have their type assertion parenthesized
|
||||
by go/parser (due to a weak predicate in the parser). All others
|
||||
were rejected always, either with a syntax error in the
|
||||
type switch header or in the case.
|
||||
|
||||
See also issue 4470.
|
||||
*/
|
||||
package p
|
||||
|
||||
func f() {
|
||||
var x interface{}
|
||||
switch x.(type) { // should remain the same
|
||||
}
|
||||
switch x.(type) { // should become: switch x.(type) {
|
||||
}
|
||||
|
||||
switch x.(type) { // should remain the same
|
||||
case int:
|
||||
}
|
||||
switch x.(type) { // should become: switch x.(type) {
|
||||
case int:
|
||||
}
|
||||
|
||||
switch x.(type) { // should remain the same
|
||||
case []int:
|
||||
}
|
||||
|
||||
// Parenthesized (x.(type)) in type switches containing cases
|
||||
// with unnamed (literal) types were never permitted by gofmt;
|
||||
// thus there won't be any code in the wild using this style if
|
||||
// the code was gofmt-ed.
|
||||
/*
|
||||
switch (x.(type)) {
|
||||
case []int:
|
||||
}
|
||||
*/
|
||||
|
||||
switch t := x.(type) { // should remain the same
|
||||
default:
|
||||
_ = t
|
||||
}
|
||||
|
||||
// Parenthesized (x.(type)) in type switches declaring a variable
|
||||
// were never permitted by gofmt; thus there won't be any code in
|
||||
// the wild using this style if the code was gofmt-ed.
|
||||
/*
|
||||
switch t := (x.(type)) {
|
||||
default:
|
||||
_ = t
|
||||
}
|
||||
*/
|
||||
}
|
60
admin/lib/gofmt/testdata/typeswitch.input
vendored
Normal file
60
admin/lib/gofmt/testdata/typeswitch.input
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Parenthesized type switch expressions originally
|
||||
accepted by gofmt must continue to be rewritten
|
||||
into the correct unparenthesized form.
|
||||
|
||||
Only type-switches that didn't declare a variable
|
||||
in the type switch type assertion and which
|
||||
contained only "expression-like" (named) types in their
|
||||
cases were permitted to have their type assertion parenthesized
|
||||
by go/parser (due to a weak predicate in the parser). All others
|
||||
were rejected always, either with a syntax error in the
|
||||
type switch header or in the case.
|
||||
|
||||
See also issue 4470.
|
||||
*/
|
||||
package p
|
||||
|
||||
func f() {
|
||||
var x interface{}
|
||||
switch x.(type) { // should remain the same
|
||||
}
|
||||
switch (x.(type)) { // should become: switch x.(type) {
|
||||
}
|
||||
|
||||
switch x.(type) { // should remain the same
|
||||
case int:
|
||||
}
|
||||
switch (x.(type)) { // should become: switch x.(type) {
|
||||
case int:
|
||||
}
|
||||
|
||||
switch x.(type) { // should remain the same
|
||||
case []int:
|
||||
}
|
||||
|
||||
// Parenthesized (x.(type)) in type switches containing cases
|
||||
// with unnamed (literal) types were never permitted by gofmt;
|
||||
// thus there won't be any code in the wild using this style if
|
||||
// the code was gofmt-ed.
|
||||
/*
|
||||
switch (x.(type)) {
|
||||
case []int:
|
||||
}
|
||||
*/
|
||||
|
||||
switch t := x.(type) { // should remain the same
|
||||
default:
|
||||
_ = t
|
||||
}
|
||||
|
||||
// Parenthesized (x.(type)) in type switches declaring a variable
|
||||
// were never permitted by gofmt; thus there won't be any code in
|
||||
// the wild using this style if the code was gofmt-ed.
|
||||
/*
|
||||
switch t := (x.(type)) {
|
||||
default:
|
||||
_ = t
|
||||
}
|
||||
*/
|
||||
}
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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: '知道了',
|
||||
})
|
||||
|
@ -8,4 +8,5 @@
|
||||
- [x] 执行历史记录
|
||||
- [ ] 执行历史查看和条件检索
|
||||
- [ ] 公告发送游戏
|
||||
- [ ] 奖励码接入
|
||||
- [x] 奖励码接入
|
||||
- [x] 统一错误码内容
|
Loading…
x
Reference in New Issue
Block a user