test: add escape analysis tests for fields

False positives (var incorrectly escapes) are marked with BAD.

Change-Id: I3027b6e0f5b48325e6169599400cc59e1394809f
Reviewed-on: https://go-review.googlesource.com/5431
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/test/escape_field.go b/test/escape_field.go
new file mode 100644
index 0000000..0ad1144
--- /dev/null
+++ b/test/escape_field.go
@@ -0,0 +1,175 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis with respect to field assignments.
+
+package escape
+
+var sink interface{}
+
+type X struct {
+	p1 *int
+	p2 *int
+	a  [2]*int
+}
+
+type Y struct {
+	x X
+}
+
+func field0() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	sink = x.p1
+}
+
+func field1() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	sink = x.p2
+}
+
+func field3() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	sink = x
+}
+
+func field4() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	sink = x
+}
+
+func field5() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape here
+	x.a[0] = &i // ERROR "&i escapes to heap$"
+	sink = x.a[1]
+}
+
+// BAD: we are not leaking param x, only x.p2
+func field6(x *X) { // ERROR "leaking param: x$"
+	sink = x.p2
+}
+
+func field6a() {
+	i := 0  // ERROR "moved to heap: i$"
+	var x X // ERROR "moved to heap: x$"
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	// BAD: &x should not escape
+	field6(&x) // ERROR "&x escapes to heap$"
+}
+
+func field7() {
+	i := 0
+	var y Y
+	y.x.p1 = &i // ERROR "field7 &i does not escape$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	_ = y1.x.p1
+}
+
+func field8() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	sink = y1.x.p1
+}
+
+func field9() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	sink = y1.x
+}
+
+func field10() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	// BAD: &i should not escape
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	sink = y1.x.p2
+}
+
+func field11() {
+	i := 0         // ERROR "moved to heap: i$"
+	x := X{p1: &i} // ERROR "&i escapes to heap$"
+	sink = x.p1
+}
+
+func field12() {
+	i := 0 // ERROR "moved to heap: i$"
+	// BAD: &i should not escape
+	x := X{p1: &i} // ERROR "&i escapes to heap$"
+	sink = x.p2
+}
+
+func field13() {
+	i := 0          // ERROR "moved to heap: i$"
+	x := &X{p1: &i} // ERROR "&i escapes to heap$" "field13 &X literal does not escape$"
+	sink = x.p1
+}
+
+func field14() {
+	i := 0 // ERROR "moved to heap: i$"
+	// BAD: &i should not escape
+	x := &X{p1: &i} // ERROR "&i escapes to heap$" "field14 &X literal does not escape$"
+	sink = x.p2
+}
+
+func field15() {
+	i := 0          // ERROR "moved to heap: i$"
+	x := &X{p1: &i} // ERROR "&X literal escapes to heap$" "&i escapes to heap$"
+	sink = x
+}
+
+func field16() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	var iface interface{} = x
+	x1 := iface.(X)
+	sink = x1.p2
+}
+
+func field17() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	var iface interface{} = x
+	x1 := iface.(X)
+	sink = x1.p1
+}
+
+func field18() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	var iface interface{} = x
+	y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized.
+	sink = y
+}