Commit 29cbad6c authored by Rob Pike's avatar Rob Pike

template: give "unexported" error when accessing an unexported field.

R=adg, rsc
CC=golang-dev
https://golang.org/cl/3903043
parent e3c9565b
...@@ -596,7 +596,7 @@ func (t *Template) parse() { ...@@ -596,7 +596,7 @@ func (t *Template) parse() {
// Evaluate interfaces and pointers looking for a value that can look up the name, via a // Evaluate interfaces and pointers looking for a value that can look up the name, via a
// struct field, method, or map key, and return the result of the lookup. // struct field, method, or map key, and return the result of the lookup.
func lookup(v reflect.Value, name string) reflect.Value { func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
for v != nil { for v != nil {
typ := v.Type() typ := v.Type()
if n := v.Type().NumMethod(); n > 0 { if n := v.Type().NumMethod(); n > 0 {
...@@ -605,7 +605,7 @@ func lookup(v reflect.Value, name string) reflect.Value { ...@@ -605,7 +605,7 @@ func lookup(v reflect.Value, name string) reflect.Value {
mtyp := m.Type mtyp := m.Type
if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 { if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
if !isExported(name) { if !isExported(name) {
return nil t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
} }
return v.Method(i).Call(nil)[0] return v.Method(i).Call(nil)[0]
} }
...@@ -618,7 +618,7 @@ func lookup(v reflect.Value, name string) reflect.Value { ...@@ -618,7 +618,7 @@ func lookup(v reflect.Value, name string) reflect.Value {
v = av.Elem() v = av.Elem()
case *reflect.StructValue: case *reflect.StructValue:
if !isExported(name) { if !isExported(name) {
return nil t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
} }
return av.FieldByName(name) return av.FieldByName(name)
case *reflect.MapValue: case *reflect.MapValue:
...@@ -652,14 +652,14 @@ loop: ...@@ -652,14 +652,14 @@ loop:
// The value coming in (st.data) might need indirecting to reach // The value coming in (st.data) might need indirecting to reach
// a struct while the return value is not indirected - that is, // a struct while the return value is not indirected - that is,
// it represents the actual named field. // it represents the actual named field.
func (st *state) findVar(s string) reflect.Value { func (t *Template) findVar(st *state, s string) reflect.Value {
if s == "@" { if s == "@" {
return st.data return st.data
} }
data := st.data data := st.data
for _, elem := range strings.Split(s, ".", -1) { for _, elem := range strings.Split(s, ".", -1) {
// Look up field; data must be a struct or map. // Look up field; data must be a struct or map.
data = lookup(data, elem) data = t.lookup(st, data, elem)
if data == nil { if data == nil {
return nil return nil
} }
...@@ -692,7 +692,7 @@ func empty(v reflect.Value) bool { ...@@ -692,7 +692,7 @@ func empty(v reflect.Value) bool {
// Look up a variable or method, up through the parent if necessary. // Look up a variable or method, up through the parent if necessary.
func (t *Template) varValue(name string, st *state) reflect.Value { func (t *Template) varValue(name string, st *state) reflect.Value {
field := st.findVar(name) field := t.findVar(st, name)
if field == nil { if field == nil {
if st.parent == nil { if st.parent == nil {
t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type()) t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"io/ioutil" "io/ioutil"
"json" "json"
"os" "os"
"strings"
"testing" "testing"
) )
...@@ -635,3 +636,25 @@ func TestHTMLFormatterWithByte(t *testing.T) { ...@@ -635,3 +636,25 @@ func TestHTMLFormatterWithByte(t *testing.T) {
t.Errorf("munged []byte, expected: %s got: %s", s, bs) t.Errorf("munged []byte, expected: %s got: %s", s, bs)
} }
} }
type UF struct {
I int
s string
}
func TestReferenceToUnexported(t *testing.T) {
u := &UF{3, "hello"}
var buf bytes.Buffer
input := "{.section @}{I}{s}{.end}"
tmpl, err := Parse(input, nil)
if err != nil {
t.Fatal("unexpected parse error:", err)
}
err = tmpl.Execute(u, &buf)
if err == nil {
t.Fatal("expected execute error, got none")
}
if strings.Index(err.String(), "not exported") < 0 {
t.Fatal("expected unexported error; got", err)
}
}
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