Commit a49e7f39 authored by Robert Griesemer's avatar Robert Griesemer

gofmt: don't crash when rewriting nil interfaces in AST.

The new reflection API makes it an error to call value.Set(x)
if x is invalid. Guard for it.

Added corresponding test case.

Fixes #1696.

R=rsc, r
CC=golang-dev
https://golang.org/cl/4398047
parent 881b1b4a
...@@ -71,6 +71,7 @@ var tests = []struct { ...@@ -71,6 +71,7 @@ var tests = []struct {
{".", "gofmt_test.go", "gofmt_test.go", ""}, {".", "gofmt_test.go", "gofmt_test.go", ""},
{"testdata", "composites.input", "composites.golden", "-s"}, {"testdata", "composites.input", "composites.golden", "-s"},
{"testdata", "rewrite1.input", "rewrite1.golden", "-r=Foo->Bar"}, {"testdata", "rewrite1.input", "rewrite1.golden", "-r=Foo->Bar"},
{"testdata", "rewrite2.input", "rewrite2.golden", "-r=int->bool"},
} }
......
...@@ -63,6 +63,10 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { ...@@ -63,6 +63,10 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
repl := reflect.NewValue(replace) repl := reflect.NewValue(replace)
var f func(val reflect.Value) reflect.Value // f is recursive var f func(val reflect.Value) reflect.Value // f is recursive
f = func(val reflect.Value) reflect.Value { f = func(val reflect.Value) reflect.Value {
// don't bother if val is invalid to start with
if !val.IsValid() {
return reflect.Value{}
}
for k := range m { for k := range m {
m[k] = reflect.Value{}, false m[k] = reflect.Value{}, false
} }
...@@ -79,6 +83,10 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { ...@@ -79,6 +83,10 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
// setValue is a wrapper for x.SetValue(y); it protects // setValue is a wrapper for x.SetValue(y); it protects
// the caller from panics if x cannot be changed to y. // the caller from panics if x cannot be changed to y.
func setValue(x, y reflect.Value) { func setValue(x, y reflect.Value) {
// don't bother if y is invalid to start with
if !y.IsValid() {
return
}
defer func() { defer func() {
if x := recover(); x != nil { if x := recover(); x != nil {
if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") { if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
...@@ -95,10 +103,12 @@ func setValue(x, y reflect.Value) { ...@@ -95,10 +103,12 @@ func setValue(x, y reflect.Value) {
// Values/types for special cases. // Values/types for special cases.
var ( var (
objectPtrNil = reflect.NewValue((*ast.Object)(nil)) objectPtrNil = reflect.NewValue((*ast.Object)(nil))
scopePtrNil = reflect.NewValue((*ast.Scope)(nil))
identType = reflect.Typeof((*ast.Ident)(nil)) identType = reflect.Typeof((*ast.Ident)(nil))
objectPtrType = reflect.Typeof((*ast.Object)(nil)) objectPtrType = reflect.Typeof((*ast.Object)(nil))
positionType = reflect.Typeof(token.NoPos) positionType = reflect.Typeof(token.NoPos)
scopePtrType = reflect.Typeof((*ast.Scope)(nil))
) )
...@@ -115,6 +125,12 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value ...@@ -115,6 +125,12 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value
return objectPtrNil return objectPtrNil
} }
// similarly for scopes: they are likely incorrect after a rewrite;
// replace them with nil
if val.Type() == scopePtrType {
return scopePtrNil
}
switch v := reflect.Indirect(val); v.Kind() { switch v := reflect.Indirect(val); v.Kind() {
case reflect.Slice: case reflect.Slice:
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {
......
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main package main
type Bar int type Bar int
......
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main package main
type Foo int type Foo int
......
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
// Slices have nil Len values in the corresponding ast.ArrayType
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
// The rewriter must not crash in that case. Was issue 1696.
func f() []bool {}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
// Slices have nil Len values in the corresponding ast.ArrayType
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
// The rewriter must not crash in that case. Was issue 1696.
func f() []int {}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment