Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(476)

Side by Side Diff: src/cmd/gofmt/simplify.go

Issue 6822059: code review 6822059: gofmt: simplify slices of the form s[a : len(s)] to s[a:] (Closed)
Patch Set: diff -r 6f1c5f14c594 https://code.google.com/p/go Created 11 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/cmd/gofmt/gofmt_test.go ('k') | src/cmd/gofmt/testdata/slices1.golden » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 The Go Authors. All rights reserved. 1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package main 5 package main
6 6
7 import ( 7 import (
8 "go/ast" 8 "go/ast"
9 "go/token" 9 "go/token"
10 "reflect" 10 "reflect"
11 ) 11 )
12 12
13 type simplifier struct{} 13 type simplifier struct {
14 » hasDotImport bool // package file contains: import . "some/import/path"
15 }
14 16
15 func (s *simplifier) Visit(node ast.Node) ast.Visitor { 17 func (s *simplifier) Visit(node ast.Node) ast.Visitor {
16 switch n := node.(type) { 18 switch n := node.(type) {
17 case *ast.CompositeLit: 19 case *ast.CompositeLit:
18 // array, slice, and map composite literals may be simplified 20 // array, slice, and map composite literals may be simplified
19 outer := n 21 outer := n
20 var eltType ast.Expr 22 var eltType ast.Expr
21 switch typ := outer.Type.(type) { 23 switch typ := outer.Type.(type) {
22 case *ast.ArrayType: 24 case *ast.ArrayType:
23 eltType = typ.Elt 25 eltType = typ.Elt
24 case *ast.MapType: 26 case *ast.MapType:
25 eltType = typ.Value 27 eltType = typ.Value
26 } 28 }
27 29
28 if eltType != nil { 30 if eltType != nil {
29 typ := reflect.ValueOf(eltType) 31 typ := reflect.ValueOf(eltType)
30 for i, x := range outer.Elts { 32 for i, x := range outer.Elts {
31 px := &outer.Elts[i] 33 px := &outer.Elts[i]
32 // look at value of indexed/named elements 34 // look at value of indexed/named elements
33 if t, ok := x.(*ast.KeyValueExpr); ok { 35 if t, ok := x.(*ast.KeyValueExpr); ok {
34 x = t.Value 36 x = t.Value
35 px = &t.Value 37 px = &t.Value
36 } 38 }
37 » » » » simplify(x) 39 » » » » ast.Walk(s, x) // simplify x
38 // if the element is a composite literal and its literal type 40 // if the element is a composite literal and its literal type
39 // matches the outer literal's element type exac tly, the inner 41 // matches the outer literal's element type exac tly, the inner
40 // literal type may be omitted 42 // literal type may be omitted
41 if inner, ok := x.(*ast.CompositeLit); ok { 43 if inner, ok := x.(*ast.CompositeLit); ok {
42 if match(nil, typ, reflect.ValueOf(inner .Type)) { 44 if match(nil, typ, reflect.ValueOf(inner .Type)) {
43 inner.Type = nil 45 inner.Type = nil
44 } 46 }
45 } 47 }
46 // if the outer literal's element type is a poin ter type *T 48 // if the outer literal's element type is a poin ter type *T
47 // and the element is & of a composite literal o f type T, 49 // and the element is & of a composite literal o f type T,
48 // the inner &T may be omitted. 50 // the inner &T may be omitted.
49 if ptr, ok := eltType.(*ast.StarExpr); ok { 51 if ptr, ok := eltType.(*ast.StarExpr); ok {
50 if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND { 52 if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
51 if inner, ok := addr.X.(*ast.Com positeLit); ok { 53 if inner, ok := addr.X.(*ast.Com positeLit); ok {
52 if match(nil, reflect.Va lueOf(ptr.X), reflect.ValueOf(inner.Type)) { 54 if match(nil, reflect.Va lueOf(ptr.X), reflect.ValueOf(inner.Type)) {
53 inner.Type = nil // drop T 55 inner.Type = nil // drop T
54 *px = inner // drop & 56 *px = inner // drop &
55 } 57 }
56 } 58 }
57 } 59 }
58 } 60 }
59 } 61 }
60 62
61 // node was simplified - stop walk (there are no subnode s to simplify) 63 // node was simplified - stop walk (there are no subnode s to simplify)
62 return nil 64 return nil
63 } 65 }
64 66
67 case *ast.SliceExpr:
68 // a slice expression of the form: s[a:len(s)]
69 // can be simplified to: s[a:]
70 // if s is "simple enough" (for now we only accept identifiers)
71 if s.hasDotImport {
72 // if dot imports are present, we cannot be certain that an
73 // unresolved "len" identifiers refers to the predefined len()
r 2012/10/31 18:38:19 s/identifiers/identifier/
74 break
75 }
76 if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
77 // the array/slice object is a single, resolved identifi er
78 if call, _ := n.High.(*ast.CallExpr); call != nil && len (call.Args) == 1 && !call.Ellipsis.IsValid() {
79 // the high expression is a function call with a single argument
80 if fun, _ := call.Fun.(*ast.Ident); fun != nil & & fun.Name == "len" && fun.Obj == nil {
81 // the function called is "len" and it i s not locally defined;
82 // because we don't have dot imports, it must be the predefined len()
83 if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
84 // the len argument is the array /slice object
85 n.High = nil
86 }
87 }
88 }
89 }
90 // Note: We could also simplify slice expressions of the form s[ 0:b] to s[:b]
91 // but we leave them as is since sometimes we want to be v ery explicit
92 // about the lower bound.
93
65 case *ast.RangeStmt: 94 case *ast.RangeStmt:
66 » » // range of the form: for x, _ = range v {...} 95 » » // a range of the form: for x, _ = range v {...}
67 // can be simplified to: for x = range v {...} 96 // can be simplified to: for x = range v {...}
68 » » if n.Value != nil { 97 » » if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" {
69 » » » if ident, ok := n.Value.(*ast.Ident); ok && ident.Name = = "_" { 98 » » » n.Value = nil
70 » » » » n.Value = nil
71 » » » }
72 } 99 }
73 } 100 }
74 101
75 return s 102 return s
76 } 103 }
77 104
78 func simplify(node ast.Node) { 105 func simplify(f *ast.File) {
79 var s simplifier 106 var s simplifier
80 » ast.Walk(&s, node) 107
108 » // determine if f contains dot imports
109 » for _, imp := range f.Imports {
110 » » if imp.Name != nil && imp.Name.Name == "." {
111 » » » s.hasDotImport = true
112 » » » break
113 » » }
114 » }
115
116 » ast.Walk(&s, f)
81 } 117 }
OLDNEW
« no previous file with comments | « src/cmd/gofmt/gofmt_test.go ('k') | src/cmd/gofmt/testdata/slices1.golden » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b