Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / mvdan.cc / gofumpt@v0.0.0-20200802201014-ab5a8192947d / simplify.go
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
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                 // array, slice, and map composite literals may be simplified
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                                 // look at value of indexed/named elements
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                         // node was simplified - stop walk (there are no subnodes to simplify)
48                         return nil
49                 }
50
51         case *ast.SliceExpr:
52                 // a slice expression of the form: s[a:len(s)]
53                 // can be simplified to: s[a:]
54                 // if s is "simple enough" (for now we only accept identifiers)
55                 //
56                 // Note: This may not be correct because len may have been redeclared in another
57                 //       file belonging to the same package. However, this is extremely unlikely
58                 //       and so far (April 2016, after years of supporting this rewrite feature)
59                 //       has never come up, so let's keep it working as is (see also #15153).
60                 if n.Max != nil {
61                         // - 3-index slices always require the 2nd and 3rd index
62                         break
63                 }
64                 if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
65                         // the array/slice object is a single, resolved identifier
66                         if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
67                                 // the high expression is a function call with a single argument
68                                 if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
69                                         // the function called is "len" and it is not locally defined; and
70                                         // because we don't have dot imports, it must be the predefined len()
71                                         if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
72                                                 // the len argument is the array/slice object
73                                                 n.High = nil
74                                         }
75                                 }
76                         }
77                 }
78                 // Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
79                 //       but we leave them as is since sometimes we want to be very explicit
80                 //       about the lower bound.
81                 // An example where the 0 helps:
82                 //       x, y, z := b[0:2], b[2:4], b[4:6]
83                 // An example where it does not:
84                 //       x, y := b[:n], b[n:]
85
86         case *ast.RangeStmt:
87                 // - a range of the form: for x, _ = range v {...}
88                 // can be simplified to: for x = range v {...}
89                 // - a range of the form: for _ = range v {...}
90                 // can be simplified to: for range v {...}
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) // simplify x
104
105         // if the element is a composite literal and its literal type
106         // matches the outer literal's element type exactly, the inner
107         // literal type may be omitted
108         if inner, ok := x.(*ast.CompositeLit); ok {
109                 if match(nil, typ, reflect.ValueOf(inner.Type)) {
110                         inner.Type = nil
111                 }
112         }
113         // if the outer literal's element type is a pointer type *T
114         // and the element is & of a composite literal of type T,
115         // the inner &T may be omitted.
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 // drop T
121                                         *px = inner      // drop &
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         // remove empty declarations such as "const ()", etc
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                 // if there is a comment in the declaration, it is not considered empty
159                 if g.Pos() <= c.Pos() && c.End() <= g.End() {
160                         return false
161                 }
162         }
163
164         return true
165 }