...
Source file
src/cmd/gofmt/simplify.go
1
2
3
4
5 package main
6
7 import (
8 "go/ast"
9 "go/token"
10 "reflect"
11 )
12
13 type simplifier struct{}
14
15 func (s simplifier) Visit(node ast.Node) ast.Visitor {
16 switch n := node.(type) {
17 case *ast.CompositeLit:
18
19 outer := n
20 var keyType, eltType ast.Expr
21 switch typ := outer.Type.(type) {
22 case *ast.ArrayType:
23 eltType = typ.Elt
24 case *ast.MapType:
25 keyType = typ.Key
26 eltType = typ.Value
27 }
28
29 if eltType != nil {
30 var ktyp reflect.Value
31 if keyType != nil {
32 ktyp = reflect.ValueOf(keyType)
33 }
34 typ := reflect.ValueOf(eltType)
35 for i, x := range outer.Elts {
36 px := &outer.Elts[i]
37
38 if t, ok := x.(*ast.KeyValueExpr); ok {
39 if keyType != nil {
40 s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key)
41 }
42 x = t.Value
43 px = &t.Value
44 }
45 s.simplifyLiteral(typ, eltType, x, px)
46 }
47
48 return nil
49 }
50
51 case *ast.SliceExpr:
52
53
54
55
56
57
58
59
60
61
62
63
64
65 if n.Max != nil {
66
67 break
68 }
69 if s, _ := n.X.(*ast.Ident); s != nil {
70
71 if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
72
73 if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" {
74
75 if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Name == s.Name {
76
77 n.High = nil
78 }
79 }
80 }
81 }
82
83
84
85
86
87
88
89
90 case *ast.RangeStmt:
91
92
93
94
95 if isBlank(n.Value) {
96 n.Value = nil
97 }
98 if isBlank(n.Key) && n.Value == nil {
99 n.Key = nil
100 }
101 }
102
103 return s
104 }
105
106 func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) {
107 ast.Walk(s, x)
108
109
110
111
112 if inner, ok := x.(*ast.CompositeLit); ok {
113 if match(nil, typ, reflect.ValueOf(inner.Type)) {
114 inner.Type = nil
115 }
116 }
117
118
119
120 if ptr, ok := astType.(*ast.StarExpr); ok {
121 if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
122 if inner, ok := addr.X.(*ast.CompositeLit); ok {
123 if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
124 inner.Type = nil
125 *px = inner
126 }
127 }
128 }
129 }
130 }
131
132 func isBlank(x ast.Expr) bool {
133 ident, ok := x.(*ast.Ident)
134 return ok && ident.Name == "_"
135 }
136
137 func simplify(f *ast.File) {
138
139 removeEmptyDeclGroups(f)
140
141 var s simplifier
142 ast.Walk(s, f)
143 }
144
145 func removeEmptyDeclGroups(f *ast.File) {
146 i := 0
147 for _, d := range f.Decls {
148 if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
149 f.Decls[i] = d
150 i++
151 }
152 }
153 f.Decls = f.Decls[:i]
154 }
155
156 func isEmpty(f *ast.File, g *ast.GenDecl) bool {
157 if g.Doc != nil || g.Specs != nil {
158 return false
159 }
160
161 for _, c := range f.Comments {
162
163 if g.Pos() <= c.Pos() && c.End() <= g.End() {
164 return false
165 }
166 }
167
168 return true
169 }
170
View as plain text