...

Source file src/pkg/cmd/gofmt/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	}
   166	

View as plain text