aboutsummaryrefslogtreecommitdiff
path: root/src/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/text')
-rw-r--r--src/text/template/exec.go12
-rw-r--r--src/text/template/exec_test.go17
-rw-r--r--src/text/template/helper.go14
3 files changed, 38 insertions, 5 deletions
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index a169e62ab0..22881c6852 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -538,14 +538,14 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
return s.evalCall(dot, method, node, fieldName, args, final)
}
hasArgs := len(args) > 1 || final.IsValid()
- // It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil.
- if isNil {
- s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
- }
+ // It's not a method; must be a field of a struct or an element of a map.
switch receiver.Kind() {
case reflect.Struct:
tField, ok := receiver.Type().FieldByName(fieldName)
if ok {
+ if isNil {
+ s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+ }
field := receiver.FieldByIndex(tField.Index)
if tField.PkgPath != "" { // field is unexported
s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
@@ -556,8 +556,10 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
}
return field
}
- s.errorf("%s is not a field of struct type %s", fieldName, typ)
case reflect.Map:
+ if isNil {
+ s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+ }
// If it's a map, attempt to use the field name as a key.
nameVal := reflect.ValueOf(fieldName)
if nameVal.Type().AssignableTo(receiver.Type().Key()) {
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index e507e917fe..bc2aa683ec 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -1280,3 +1280,20 @@ func TestBlock(t *testing.T) {
t.Errorf("got %q, want %q", got, want2)
}
}
+
+// Check that calling an invalid field on nil pointer prints
+// a field error instead of a distracting nil pointer error.
+// https://golang.org/issue/15125
+func TestMissingFieldOnNil(t *testing.T) {
+ tmpl := Must(New("tmpl").Parse("{{.MissingField}}"))
+ var d *T
+ err := tmpl.Execute(ioutil.Discard, d)
+ got := "<nil>"
+ if err != nil {
+ got = err.Error()
+ }
+ want := "can't evaluate field MissingField in type *template.T"
+ if !strings.HasSuffix(got, want) {
+ t.Errorf("got error %q, want %q", got, want)
+ }
+}
diff --git a/src/text/template/helper.go b/src/text/template/helper.go
index 787ca62e5f..9e0200c352 100644
--- a/src/text/template/helper.go
+++ b/src/text/template/helper.go
@@ -29,6 +29,11 @@ func Must(t *Template, err error) *Template {
// the named files. The returned template's name will have the base name and
// parsed contents of the first file. There must be at least one file.
// If an error occurs, parsing stops and the returned *Template is nil.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
+// named "foo", while "a/foo" is unavailable.
func ParseFiles(filenames ...string) (*Template, error) {
return parseFiles(nil, filenames...)
}
@@ -41,6 +46,9 @@ func ParseFiles(filenames ...string) (*Template, error) {
// of the (base) names of the files. If it does not, depending on t's
// contents before calling ParseFiles, t.Execute may fail. In that
// case use t.ExecuteTemplate to execute a valid template.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
t.init()
return parseFiles(t, filenames...)
@@ -88,6 +96,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) {
// returned template will have the (base) name and (parsed) contents of the
// first file matched by the pattern. ParseGlob is equivalent to calling
// ParseFiles with the list of files matched by the pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func ParseGlob(pattern string) (*Template, error) {
return parseGlob(nil, pattern)
}
@@ -97,6 +108,9 @@ func ParseGlob(pattern string) (*Template, error) {
// processed by filepath.Glob and must match at least one file. ParseGlob is
// equivalent to calling t.ParseFiles with the list of files matched by the
// pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
func (t *Template) ParseGlob(pattern string) (*Template, error) {
t.init()
return parseGlob(t, pattern)