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 if n.Max != nil {
61
62 break
63 }
64 if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
65
66 if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
67
68 if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
69
70
71 if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
72
73 n.High = nil
74 }
75 }
76 }
77 }
78
79
80
81
82
83
84
85
86 case *ast.RangeStmt:
87
88
89
90
91 if isBlank(n.Value) {
92 n.Value = nil
93 }
94 if isBlank(n.Key) && n.Value == nil {
95 n.Key = nil
96 }
97 }
98
99 return s
100 }
101
102 func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) {
103 ast.Walk(s, x)
104
105
106
107
108 if inner, ok := x.(*ast.CompositeLit); ok {
109 if match(nil, typ, reflect.ValueOf(inner.Type)) {
110 inner.Type = nil
111 }
112 }
113
114
115
116 if ptr, ok := astType.(*ast.StarExpr); ok {
117 if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
118 if inner, ok := addr.X.(*ast.CompositeLit); ok {
119 if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
120 inner.Type = nil
121 *px = inner
122 }
123 }
124 }
125 }
126 }
127
128 func isBlank(x ast.Expr) bool {
129 ident, ok := x.(*ast.Ident)
130 return ok && ident.Name == "_"
131 }
132
133 func simplify(f *ast.File) {
134
135 removeEmptyDeclGroups(f)
136
137 var s simplifier
138 ast.Walk(s, f)
139 }
140
141 func removeEmptyDeclGroups(f *ast.File) {
142 i := 0
143 for _, d := range f.Decls {
144 if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
145 f.Decls[i] = d
146 i++
147 }
148 }
149 f.Decls = f.Decls[:i]
150 }
151
152 func isEmpty(f *ast.File, g *ast.GenDecl) bool {
153 if g.Doc != nil || g.Specs != nil {
154 return false
155 }
156
157 for _, c := range f.Comments {
158
159 if g.Pos() <= c.Pos() && c.End() <= g.End() {
160 return false
161 }
162 }
163
164 return true
165 }
166
View as plain text