]> Cypherpunks repositories - gostls13.git/commitdiff
template: give "unexported" error when accessing an unexported field.
authorRob Pike <r@golang.org>
Wed, 12 Jan 2011 08:25:17 +0000 (00:25 -0800)
committerRob Pike <r@golang.org>
Wed, 12 Jan 2011 08:25:17 +0000 (00:25 -0800)
R=adg, rsc
CC=golang-dev
https://golang.org/cl/3903043

src/pkg/template/template.go
src/pkg/template/template_test.go

index 3abfc2eaec16ae7b88e0380fab27671842a50578..a67dbf8ad2442b4b94f49e09db807396f99fd407 100644 (file)
@@ -596,7 +596,7 @@ func (t *Template) parse() {
 
 // 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.
-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 {
                typ := v.Type()
                if n := v.Type().NumMethod(); n > 0 {
@@ -605,7 +605,7 @@ func lookup(v reflect.Value, name string) reflect.Value {
                                mtyp := m.Type
                                if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
                                        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]
                                }
@@ -618,7 +618,7 @@ func lookup(v reflect.Value, name string) reflect.Value {
                        v = av.Elem()
                case *reflect.StructValue:
                        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)
                case *reflect.MapValue:
@@ -652,14 +652,14 @@ loop:
 // The value coming in (st.data) might need indirecting to reach
 // a struct while the return value is not indirected - that is,
 // 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 == "@" {
                return st.data
        }
        data := st.data
        for _, elem := range strings.Split(s, ".", -1) {
                // Look up field; data must be a struct or map.
-               data = lookup(data, elem)
+               data = t.lookup(st, data, elem)
                if data == nil {
                        return nil
                }
@@ -692,7 +692,7 @@ func empty(v reflect.Value) bool {
 
 // Look up a variable or method, up through the parent if necessary.
 func (t *Template) varValue(name string, st *state) reflect.Value {
-       field := st.findVar(name)
+       field := t.findVar(st, name)
        if field == nil {
                if st.parent == nil {
                        t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
index f60c0127e2dea301095f7d51a62c9eaf0c50d6ef..57f297e8f0a0bbc4964ac3443b7d366d669b0160 100644 (file)
@@ -12,6 +12,7 @@ import (
        "io/ioutil"
        "json"
        "os"
+       "strings"
        "testing"
 )
 
@@ -635,3 +636,25 @@ func TestHTMLFormatterWithByte(t *testing.T) {
                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)
+       }
+}