| | |
| | |
| | |
| |
|
| | package main |
| |
|
| | import ( |
| | "go/ast" |
| | "go/token" |
| | "reflect" |
| | ) |
| |
|
| | type simplifier struct{} |
| |
|
| | func (s simplifier) Visit(node ast.Node) ast.Visitor { |
| | switch n := node.(type) { |
| | case *ast.CompositeLit: |
| | |
| | outer := n |
| | var keyType, eltType ast.Expr |
| | switch typ := outer.Type.(type) { |
| | case *ast.ArrayType: |
| | eltType = typ.Elt |
| | case *ast.MapType: |
| | keyType = typ.Key |
| | eltType = typ.Value |
| | } |
| |
|
| | if eltType != nil { |
| | var ktyp reflect.Value |
| | if keyType != nil { |
| | ktyp = reflect.ValueOf(keyType) |
| | } |
| | typ := reflect.ValueOf(eltType) |
| | for i, x := range outer.Elts { |
| | px := &outer.Elts[i] |
| | |
| | if t, ok := x.(*ast.KeyValueExpr); ok { |
| | if keyType != nil { |
| | s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key) |
| | } |
| | x = t.Value |
| | px = &t.Value |
| | } |
| | s.simplifyLiteral(typ, eltType, x, px) |
| | } |
| | |
| | return nil |
| | } |
| |
|
| | case *ast.SliceExpr: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if n.Max != nil { |
| | |
| | break |
| | } |
| | if s, _ := n.X.(*ast.Ident); s != nil { |
| | |
| | if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() { |
| | |
| | if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" { |
| | |
| | if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Name == s.Name { |
| | |
| | n.High = nil |
| | } |
| | } |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | case *ast.RangeStmt: |
| | |
| | |
| | |
| | |
| | if isBlank(n.Value) { |
| | n.Value = nil |
| | } |
| | if isBlank(n.Key) && n.Value == nil { |
| | n.Key = nil |
| | } |
| | } |
| |
|
| | return s |
| | } |
| |
|
| | func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) { |
| | ast.Walk(s, x) |
| |
|
| | |
| | |
| | |
| | if inner, ok := x.(*ast.CompositeLit); ok { |
| | if match(nil, typ, reflect.ValueOf(inner.Type)) { |
| | inner.Type = nil |
| | } |
| | } |
| | |
| | |
| | |
| | if ptr, ok := astType.(*ast.StarExpr); ok { |
| | if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND { |
| | if inner, ok := addr.X.(*ast.CompositeLit); ok { |
| | if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) { |
| | inner.Type = nil |
| | *px = inner |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func isBlank(x ast.Expr) bool { |
| | ident, ok := x.(*ast.Ident) |
| | return ok && ident.Name == "_" |
| | } |
| |
|
| | func simplify(f *ast.File) { |
| | |
| | removeEmptyDeclGroups(f) |
| |
|
| | var s simplifier |
| | ast.Walk(s, f) |
| | } |
| |
|
| | func removeEmptyDeclGroups(f *ast.File) { |
| | i := 0 |
| | for _, d := range f.Decls { |
| | if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) { |
| | f.Decls[i] = d |
| | i++ |
| | } |
| | } |
| | f.Decls = f.Decls[:i] |
| | } |
| |
|
| | func isEmpty(f *ast.File, g *ast.GenDecl) bool { |
| | if g.Doc != nil || g.Specs != nil { |
| | return false |
| | } |
| |
|
| | for _, c := range f.Comments { |
| | |
| | if g.Pos() <= c.Pos() && c.End() <= g.End() { |
| | return false |
| | } |
| | } |
| |
|
| | return true |
| | } |
| |
|