From 9d4ae0ae5cab63013aac9f7682292324f1951666 Mon Sep 17 00:00:00 2001
From: Gustavo Niemeyer <gustavo@niemeyer.net>
Date: Wed, 25 Jan 2012 21:07:00 -0200
Subject: [PATCH] gofix: handle xml.Unmarshal in xmlapi fix

This improves the handling of xml.Unmarshal in
the xmlapi fix by guessing some of the common
types used on it.

This also fixes a bug in the partial typechecker.
In an expression such as f(&a), it'd mark a as
having &T rather than *T.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5572058
---
 src/cmd/gofix/typecheck.go   |  2 +-
 src/cmd/gofix/xmlapi.go      | 27 +++++++++++++++++-----
 src/cmd/gofix/xmlapi_test.go | 44 ++++++++++++++++++++++++++++++++++--
 3 files changed, 64 insertions(+), 9 deletions(-)

diff --git a/src/cmd/gofix/typecheck.go b/src/cmd/gofix/typecheck.go
index 1614a90d33..8e54314d14 100644
--- a/src/cmd/gofix/typecheck.go
+++ b/src/cmd/gofix/typecheck.go
@@ -493,7 +493,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
 			// &x for x of type T has type *T.
 			t := typeof[n.X]
 			if t != "" && n.Op == token.AND {
-				typeof[n] = "&" + t
+				typeof[n] = "*" + t
 			}
 
 		case *ast.CompositeLit:
diff --git a/src/cmd/gofix/xmlapi.go b/src/cmd/gofix/xmlapi.go
index 5621d0107e..e74425914d 100644
--- a/src/cmd/gofix/xmlapi.go
+++ b/src/cmd/gofix/xmlapi.go
@@ -25,10 +25,24 @@ http://codereview.appspot.com/5574053
 
 var xmlapiTypeConfig = &TypeConfig{
 	Func: map[string]string{
-		"xml.NewParser": "xml.Parser",
+		"xml.NewParser":         "*xml.Parser",
+		"os.Open":               "*os.File",
+		"os.OpenFile":           "*os.File",
+		"bytes.NewBuffer":       "*bytes.Buffer",
+		"bytes.NewBufferString": "*bytes.Buffer",
+		"bufio.NewReader":       "*bufio.Reader",
+		"bufio.NewReadWriter":   "*bufio.ReadWriter",
 	},
 }
 
+var isReader = map[string]bool{
+	"*os.File":          true,
+	"*bytes.Buffer":     true,
+	"*bufio.Reader":     true,
+	"*bufio.ReadWriter": true,
+	"io.Reader":         true,
+}
+
 func xmlapi(f *ast.File) bool {
 	if !imports(f, "encoding/xml") {
 		return false
@@ -39,7 +53,7 @@ func xmlapi(f *ast.File) bool {
 	fixed := false
 	walk(f, func(n interface{}) {
 		s, ok := n.(*ast.SelectorExpr)
-		if ok && typeof[s.X] == "xml.Parser" && s.Sel.Name == "Unmarshal" {
+		if ok && typeof[s.X] == "*xml.Parser" && s.Sel.Name == "Unmarshal" {
 			s.Sel.Name = "DecodeElement"
 			fixed = true
 			return
@@ -58,10 +72,11 @@ func xmlapi(f *ast.File) bool {
 		case len(call.Args) == 2 && isPkgDot(call.Fun, "xml", "Marshal"):
 			*call = xmlMarshal(call.Args)
 			fixed = true
-		// Can't fix without further diving into the type of call.Args[0].
-		//case len(call.Args) == 2 && isPkgDot(call.Fun, "xml", "Unmarshal"):
-		//	*call = xmlUnmarshal(call.Args)
-		//	fixed = true
+		case len(call.Args) == 2 && isPkgDot(call.Fun, "xml", "Unmarshal"):
+			if isReader[typeof[call.Args[0]]] {
+				*call = xmlUnmarshal(call.Args)
+				fixed = true
+			}
 		case len(call.Args) == 1 && isPkgDot(call.Fun, "xml", "NewParser"):
 			sel := call.Fun.(*ast.SelectorExpr).Sel
 			sel.Name = "NewDecoder"
diff --git a/src/cmd/gofix/xmlapi_test.go b/src/cmd/gofix/xmlapi_test.go
index abf989c3e7..6486c81248 100644
--- a/src/cmd/gofix/xmlapi_test.go
+++ b/src/cmd/gofix/xmlapi_test.go
@@ -19,12 +19,32 @@ func f() {
 	xml.Marshal(a, b)
 	xml.Unmarshal(a, b)
 
+	var buf1 bytes.Buffer
+	buf2 := &bytes.Buffer{}
+	buf3 := bytes.NewBuffer(data)
+	buf4 := bytes.NewBufferString(data)
+	buf5 := bufio.NewReader(r)
+	xml.Unmarshal(&buf1, v)
+	xml.Unmarshal(buf2, v)
+	xml.Unmarshal(buf3, v)
+	xml.Unmarshal(buf4, v)
+	xml.Unmarshal(buf5, v)
+
+	f := os.Open("foo.xml")
+	xml.Unmarshal(f, v)
+
 	p1 := xml.NewParser(stream)
 	p1.Unmarshal(v, start)
 
-	var p2 xml.Parser
+	var p2 *xml.Parser
 	p2.Unmarshal(v, start)
 }
+
+func g(r io.Reader, f *os.File, b []byte) {
+	xml.Unmarshal(r, v)
+	xml.Unmarshal(f, v)
+	xml.Unmarshal(b, v)
+}
 `,
 		Out: `package main
 
@@ -34,12 +54,32 @@ func f() {
 	xml.NewEncoder(a).Encode(b)
 	xml.Unmarshal(a, b)
 
+	var buf1 bytes.Buffer
+	buf2 := &bytes.Buffer{}
+	buf3 := bytes.NewBuffer(data)
+	buf4 := bytes.NewBufferString(data)
+	buf5 := bufio.NewReader(r)
+	xml.NewDecoder(&buf1).Decode(v)
+	xml.NewDecoder(buf2).Decode(v)
+	xml.NewDecoder(buf3).Decode(v)
+	xml.NewDecoder(buf4).Decode(v)
+	xml.NewDecoder(buf5).Decode(v)
+
+	f := os.Open("foo.xml")
+	xml.NewDecoder(f).Decode(v)
+
 	p1 := xml.NewDecoder(stream)
 	p1.DecodeElement(v, start)
 
-	var p2 xml.Decoder
+	var p2 *xml.Decoder
 	p2.DecodeElement(v, start)
 }
+
+func g(r io.Reader, f *os.File, b []byte) {
+	xml.NewDecoder(r).Decode(v)
+	xml.NewDecoder(f).Decode(v)
+	xml.Unmarshal(b, v)
+}
 `,
 	},
 }
-- 
2.30.9