From 2d0d3d8f9efadcad71537b046e31f45a4b0a7844 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 12 Apr 2012 15:57:09 +1000 Subject: [PATCH] text/template: catch unexported fields during parse It's a common error to reference unexported field names in templates, especially for newcomers. This catches the error at parse time rather than execute time so the rare few who check errors will notice right away. These were always an error, so the net behavior is unchanged. Should break no existing code, just identify the error earlier. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/6009048 --- src/pkg/text/template/parse/lex.go | 2 +- src/pkg/text/template/parse/parse.go | 10 ++++++++++ src/pkg/text/template/parse/parse_test.go | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pkg/text/template/parse/lex.go b/src/pkg/text/template/parse/lex.go index 7705c0b88f..5674a940b1 100644 --- a/src/pkg/text/template/parse/lex.go +++ b/src/pkg/text/template/parse/lex.go @@ -348,7 +348,7 @@ Loop: l.backup() word := l.input[l.start:l.pos] if !l.atTerminator() { - return l.errorf("unexpected character %+U", r) + return l.errorf("bad character %+U", r) } switch { case key[word] > itemKeyword: diff --git a/src/pkg/text/template/parse/parse.go b/src/pkg/text/template/parse/parse.go index c0087b2785..fd8cf433fa 100644 --- a/src/pkg/text/template/parse/parse.go +++ b/src/pkg/text/template/parse/parse.go @@ -14,6 +14,7 @@ import ( "runtime" "strconv" "unicode" + "unicode/utf8" ) // Tree is the representation of a single parsed template. @@ -473,6 +474,9 @@ Loop: case itemVariable: cmd.append(t.useVar(token.val)) case itemField: + if !isExported(token.val) { + t.errorf("field %q not exported; cannot be evaluated", token.val) + } cmd.append(newField(token.val)) case itemBool: cmd.append(newBool(token.val == "true")) @@ -498,6 +502,12 @@ Loop: return cmd } +// isExported reports whether the field name (which starts with a period) can be accessed. +func isExported(fieldName string) bool { + r, _ := utf8.DecodeRuneInString(fieldName[1:]) // drop the period + return unicode.IsUpper(r) +} + // hasFunction reports if a function name exists in the Tree's maps. func (t *Tree) hasFunction(name string) bool { for _, funcMap := range t.funcs { diff --git a/src/pkg/text/template/parse/parse_test.go b/src/pkg/text/template/parse/parse_test.go index b2e788238d..fb98613fe1 100644 --- a/src/pkg/text/template/parse/parse_test.go +++ b/src/pkg/text/template/parse/parse_test.go @@ -230,6 +230,7 @@ var parseTests = []parseTest{ {"invalid punctuation", "{{printf 3, 4}}", hasError, ""}, {"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""}, {"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""}, + {"unexported field", "{{.local}}", hasError, ""}, // Equals (and other chars) do not assignments make (yet). {"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"}, {"bug0b", "{{$x = 1}}{{$x}}", hasError, ""}, -- 2.48.1