diff options
Diffstat (limited to 'src/cmd/gofmt')
-rw-r--r-- | src/cmd/gofmt/doc.go | 26 | ||||
-rw-r--r-- | src/cmd/gofmt/gofmt.go | 46 | ||||
-rw-r--r-- | src/cmd/gofmt/gofmt_test.go | 1 | ||||
-rw-r--r-- | src/cmd/gofmt/rewrite.go | 39 | ||||
-rw-r--r-- | src/cmd/gofmt/simplify.go | 4 | ||||
-rwxr-xr-x | src/cmd/gofmt/test.sh | 2 | ||||
-rw-r--r-- | src/cmd/gofmt/testdata/rewrite1.golden | 4 | ||||
-rw-r--r-- | src/cmd/gofmt/testdata/rewrite1.input | 4 | ||||
-rw-r--r-- | src/cmd/gofmt/testdata/rewrite2.golden | 10 | ||||
-rw-r--r-- | src/cmd/gofmt/testdata/rewrite2.input | 10 |
10 files changed, 122 insertions, 24 deletions
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go index e44030eee..1373b2657 100644 --- a/src/cmd/gofmt/doc.go +++ b/src/cmd/gofmt/doc.go @@ -8,29 +8,37 @@ Gofmt formats Go programs. Without an explicit path, it processes the standard input. Given a file, it operates on that file; given a directory, it operates on all .go files in that directory, recursively. (Files starting with a period are ignored.) +By default, gofmt prints the reformatted sources to standard output. Usage: gofmt [flags] [path ...] The flags are: + -d + Do not print reformatted sources to standard output. + If a file's formatting is different than gofmt's, print diffs + to standard output. -l - just list files whose formatting differs from gofmt's; - generate no other output unless -w is also set. + Do not print reformatted sources to standard output. + If a file's formatting is different from gofmt's, print its name + to standard output. -r rule - apply the rewrite rule to the source before reformatting. + Apply the rewrite rule to the source before reformatting. -s - try to simplify code (after applying the rewrite rule, if any). + Try to simplify code (after applying the rewrite rule, if any). -w - if set, overwrite each input file with its output. + Do not print reformatted sources to standard output. + If a file's formatting is different from gofmt's, overwrite it + with gofmt's version. -comments=true - print comments; if false, all comments are elided from the output. + Print comments; if false, all comments are elided from the output. -spaces - align with spaces instead of tabs. + Align with spaces instead of tabs. -tabindent - indent with tabs independent of -spaces. + Indent with tabs independent of -spaces. -tabwidth=8 - tab width in spaces. + Tab width in spaces. The rewrite rule specified with the -r flag must be a string of the form: diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index ce274aa21..5dd801d90 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -6,6 +6,7 @@ package main import ( "bytes" + "exec" "flag" "fmt" "go/ast" @@ -28,6 +29,7 @@ var ( write = flag.Bool("w", false, "write result to (source) file instead of stdout") rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')") simplifyAST = flag.Bool("s", false, "simplify code") + doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") // layout control comments = flag.Bool("comments", true, "print comments") @@ -134,9 +136,17 @@ func processFile(filename string, in io.Reader, out io.Writer) os.Error { return err } } + if *doDiff { + data, err := diff(src, res) + if err != nil { + return fmt.Errorf("computing diff: %s", err) + } + fmt.Printf("diff %s gofmt/%s\n", filename, filename) + out.Write(data) + } } - if !*list && !*write { + if !*list && !*write && !*doDiff { _, err = out.Write(res) } @@ -230,3 +240,37 @@ func gofmtMain() { } } } + + +func diff(b1, b2 []byte) (data []byte, err os.Error) { + f1, err := ioutil.TempFile("", "gofmt") + if err != nil { + return nil, err + } + defer os.Remove(f1.Name()) + defer f1.Close() + + f2, err := ioutil.TempFile("", "gofmt") + if err != nil { + return nil, err + } + defer os.Remove(f2.Name()) + defer f2.Close() + + f1.Write(b1) + f2.Write(b2) + + diffcmd, err := exec.LookPath("diff") + if err != nil { + return nil, err + } + + c, err := exec.Run(diffcmd, []string{"diff", "-u", f1.Name(), f2.Name()}, + nil, "", exec.DevNull, exec.Pipe, exec.MergeWithStdout) + if err != nil { + return nil, err + } + defer c.Close() + + return ioutil.ReadAll(c.Stdout) +} diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index 4ec94e293..a72530307 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -71,6 +71,7 @@ var tests = []struct { {".", "gofmt_test.go", "gofmt_test.go", ""}, {"testdata", "composites.input", "composites.golden", "-s"}, {"testdata", "rewrite1.input", "rewrite1.golden", "-r=Foo->Bar"}, + {"testdata", "rewrite2.input", "rewrite2.golden", "-r=int->bool"}, } diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go index 93643dced..4c24282f3 100644 --- a/src/cmd/gofmt/rewrite.go +++ b/src/cmd/gofmt/rewrite.go @@ -19,6 +19,7 @@ import ( func initRewrite() { if *rewriteRule == "" { + rewrite = nil // disable any previous rewrite return } f := strings.Split(*rewriteRule, "->", -1) @@ -59,26 +60,34 @@ func dump(msg string, val reflect.Value) { // rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file. func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { m := make(map[string]reflect.Value) - pat := reflect.NewValue(pattern) - repl := reflect.NewValue(replace) + pat := reflect.ValueOf(pattern) + repl := reflect.ValueOf(replace) var f func(val reflect.Value) reflect.Value // f is recursive f = func(val reflect.Value) reflect.Value { + // don't bother if val is invalid to start with + if !val.IsValid() { + return reflect.Value{} + } for k := range m { m[k] = reflect.Value{}, false } val = apply(f, val) if match(m, pat, val) { - val = subst(m, repl, reflect.NewValue(val.Interface().(ast.Node).Pos())) + val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos())) } return val } - return apply(f, reflect.NewValue(p)).Interface().(*ast.File) + return apply(f, reflect.ValueOf(p)).Interface().(*ast.File) } // setValue is a wrapper for x.SetValue(y); it protects // the caller from panics if x cannot be changed to y. func setValue(x, y reflect.Value) { + // don't bother if y is invalid to start with + if !y.IsValid() { + return + } defer func() { if x := recover(); x != nil { if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") { @@ -94,11 +103,13 @@ func setValue(x, y reflect.Value) { // Values/types for special cases. var ( - objectPtrNil = reflect.NewValue((*ast.Object)(nil)) + 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) + identType = reflect.TypeOf((*ast.Ident)(nil)) + objectPtrType = reflect.TypeOf((*ast.Object)(nil)) + positionType = reflect.TypeOf(token.NoPos) + scopePtrType = reflect.TypeOf((*ast.Scope)(nil)) ) @@ -115,6 +126,12 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value 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++ { @@ -259,21 +276,21 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) return v case reflect.Struct: - v := reflect.Zero(p.Type()) + v := reflect.New(p.Type()).Elem() for i := 0; i < p.NumField(); i++ { v.Field(i).Set(subst(m, p.Field(i), pos)) } return v case reflect.Ptr: - v := reflect.Zero(p.Type()) + 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.Zero(p.Type()) + v := reflect.New(p.Type()).Elem() if elem := p.Elem(); elem.IsValid() { v.Set(subst(m, elem, pos)) } diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go index bcc67c4a6..40a9f8f17 100644 --- a/src/cmd/gofmt/simplify.go +++ b/src/cmd/gofmt/simplify.go @@ -26,7 +26,7 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor { } if eltType != nil { - typ := reflect.NewValue(eltType) + typ := reflect.ValueOf(eltType) for _, x := range outer.Elts { // look at value of indexed/named elements if t, ok := x.(*ast.KeyValueExpr); ok { @@ -37,7 +37,7 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor { // 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.NewValue(inner.Type)) { + if match(nil, typ, reflect.ValueOf(inner.Type)) { inner.Type = nil } } diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh index 3340c48f0..99ec76932 100755 --- a/src/cmd/gofmt/test.sh +++ b/src/cmd/gofmt/test.sh @@ -36,7 +36,7 @@ apply1() { # the following files are skipped because they are test cases # for syntax errors and thus won't parse in the first place: case `basename "$F"` in - func3.go | const2.go | char_lit1.go | \ + func3.go | const2.go | char_lit1.go | blank1.go | \ bug014.go | bug050.go | bug068.go | bug083.go | bug088.go | \ bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \ bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \ diff --git a/src/cmd/gofmt/testdata/rewrite1.golden b/src/cmd/gofmt/testdata/rewrite1.golden index 3f909ff4a..d9beb3705 100644 --- a/src/cmd/gofmt/testdata/rewrite1.golden +++ b/src/cmd/gofmt/testdata/rewrite1.golden @@ -1,3 +1,7 @@ +// 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 diff --git a/src/cmd/gofmt/testdata/rewrite1.input b/src/cmd/gofmt/testdata/rewrite1.input index 1f10e3601..bdb894320 100644 --- a/src/cmd/gofmt/testdata/rewrite1.input +++ b/src/cmd/gofmt/testdata/rewrite1.input @@ -1,3 +1,7 @@ +// 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 diff --git a/src/cmd/gofmt/testdata/rewrite2.golden b/src/cmd/gofmt/testdata/rewrite2.golden new file mode 100644 index 000000000..64c67ffa6 --- /dev/null +++ b/src/cmd/gofmt/testdata/rewrite2.golden @@ -0,0 +1,10 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +// Slices have nil Len values in the corresponding ast.ArrayType +// node and reflect.NewValue(slice.Len) is an invalid reflect.Value. +// The rewriter must not crash in that case. Was issue 1696. +func f() []bool {} diff --git a/src/cmd/gofmt/testdata/rewrite2.input b/src/cmd/gofmt/testdata/rewrite2.input new file mode 100644 index 000000000..21171447a --- /dev/null +++ b/src/cmd/gofmt/testdata/rewrite2.input @@ -0,0 +1,10 @@ +// 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 {} |