diff options
Diffstat (limited to 'src/cmd/gofmt/simplify.go')
-rw-r--r-- | src/cmd/gofmt/simplify.go | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go index 470c00625..e9a67a73a 100644 --- a/src/cmd/gofmt/simplify.go +++ b/src/cmd/gofmt/simplify.go @@ -10,7 +10,9 @@ import ( "reflect" ) -type simplifier struct{} +type simplifier struct { + hasDotImport bool // package file contains: import . "some/import/path" +} func (s *simplifier) Visit(node ast.Node) ast.Visitor { switch n := node.(type) { @@ -34,7 +36,7 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor { x = t.Value px = &t.Value } - simplify(x) + ast.Walk(s, x) // simplify x // if the element is a composite literal and its literal type // matches the outer literal's element type exactly, the inner // literal type may be omitted @@ -62,20 +64,54 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor { return nil } + case *ast.SliceExpr: + // a slice expression of the form: s[a:len(s)] + // can be simplified to: s[a:] + // if s is "simple enough" (for now we only accept identifiers) + if s.hasDotImport { + // if dot imports are present, we cannot be certain that an + // unresolved "len" identifier refers to the predefined len() + break + } + if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil { + // the array/slice object is a single, resolved identifier + if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() { + // the high expression is a function call with a single argument + if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil { + // the function called is "len" and it is not locally defined; and + // because we don't have dot imports, it must be the predefined len() + if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj { + // the len argument is the array/slice object + n.High = nil + } + } + } + } + // Note: We could also simplify slice expressions of the form s[0:b] to s[:b] + // but we leave them as is since sometimes we want to be very explicit + // about the lower bound. + case *ast.RangeStmt: - // range of the form: for x, _ = range v {...} + // a range of the form: for x, _ = range v {...} // can be simplified to: for x = range v {...} - if n.Value != nil { - if ident, ok := n.Value.(*ast.Ident); ok && ident.Name == "_" { - n.Value = nil - } + if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" { + n.Value = nil } } return s } -func simplify(node ast.Node) { +func simplify(f *ast.File) { var s simplifier - ast.Walk(&s, node) + + // determine if f contains dot imports + for _, imp := range f.Imports { + if imp.Name != nil && imp.Name.Name == "." { + s.hasDotImport = true + break + } + } + + ast.Walk(&s, f) } |