summaryrefslogtreecommitdiff
path: root/src/cmd/gofmt/simplify.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gofmt/simplify.go')
-rw-r--r--src/cmd/gofmt/simplify.go54
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)
}