]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: check for literals in chain of terms
authorDidier Spezia <didier.06@gmail.com>
Sat, 2 May 2015 11:03:35 +0000 (11:03 +0000)
committerRob Pike <r@golang.org>
Sat, 2 May 2015 18:48:56 +0000 (18:48 +0000)
The current parser ignores obvious errors such as:
{{0.1.E}}
{{true.any}}
{{"hello".wrong}}
{{nil.E}}

The common problem is that a chain is built from
a literal value. It then panics at execution time.

Furthermore, a double dot triggers the same behavior:
{{..E}}

Addresses a TODO left in Tree.operand to catch these
errors at parsing time.

Note that identifiers can include a '.', and pipelines
could return an object which a field can be derived
from (like a variable), so they are excluded from the check.

Fixes #10615

Change-Id: I903706d1c17861b5a8354632c291e73c9c0bc4e1
Reviewed-on: https://go-review.googlesource.com/9621
Reviewed-by: Rob Pike <r@golang.org>
src/text/template/exec_test.go
src/text/template/parse/parse.go
src/text/template/parse/parse_test.go

index 27c74eb44d7e2959c76e92dd9fece2582bc27268..abce27ff3dcbd9da2e55eb9c2188217329501b30 100644 (file)
@@ -527,8 +527,10 @@ var execTests = []execTest{
        {"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
        // Chained nodes did not work as arguments. Issue 8473.
        {"bug13", "{{print (.Copy).I}}", "17", tVal, true},
-       // Didn't protect against explicit nil in field chains.
-       {"bug14", "{{nil.True}}", "", tVal, false},
+       // Didn't protect against nil or literal values in field chains.
+       {"bug14a", "{{(nil).True}}", "", tVal, false},
+       {"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
+       {"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
 }
 
 func zeroArgs() string {
index d0efcbf60960119b6ac2b0725cb9d6ff545197f2..f4daa379547ef2f0e31e71ff73ea3999a315e61b 100644 (file)
@@ -554,7 +554,7 @@ func (t *Tree) command() *CommandNode {
                        t.backup()
                case itemPipe:
                default:
-                       t.errorf("unexpected %s in operand; missing space?", token)
+                       t.errorf("unexpected %s in operand", token)
                }
                break
        }
@@ -582,12 +582,15 @@ func (t *Tree) operand() Node {
                // Compatibility with original API: If the term is of type NodeField
                // or NodeVariable, just put more fields on the original.
                // Otherwise, keep the Chain node.
-               // TODO: Switch to Chains always when we can.
+               // Obvious parsing errors involving literal values are detected here.
+               // More complex error cases will have to be handled at execution time.
                switch node.Type() {
                case NodeField:
                        node = t.newField(chain.Position(), chain.String())
                case NodeVariable:
                        node = t.newVariable(chain.Position(), chain.String())
+               case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
+                       t.errorf("unexpected . after term %q", node.String())
                default:
                        node = chain
                }
index faac06fe5a62fd2f7ac262a6116df68d97068e92..a2ca98b0b126b7640e75c0300b55fa5ff04bce03 100644 (file)
@@ -260,6 +260,14 @@ var parseTests = []parseTest{
        {"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""},                     // ! is just illegal here.
        {"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""},                     // $x+2 should not parse as ($x) (+2).
        {"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
+       // dot following a literal value
+       {"dot after integer", "{{1.E}}", hasError, ""},
+       {"dot after float", "{{0.1.E}}", hasError, ""},
+       {"dot after boolean", "{{true.E}}", hasError, ""},
+       {"dot after char", "{{'a'.any}}", hasError, ""},
+       {"dot after string", `{{"hello".guys}}`, hasError, ""},
+       {"dot after dot", "{{..E}}", hasError, ""},
+       {"dot after nil", "{{nil.E}}", hasError, ""},
 }
 
 var builtins = map[string]interface{}{
@@ -378,7 +386,7 @@ var errorTests = []parseTest{
                hasError, `unexpected ")"`},
        {"space",
                "{{`x`3}}",
-               hasError, `missing space?`},
+               hasError, `in operand`},
        {"idchar",
                "{{a#}}",
                hasError, `'#'`},
@@ -410,6 +418,9 @@ var errorTests = []parseTest{
        {"undefvar",
                "{{$a}}",
                hasError, `undefined variable`},
+       {"wrongdot",
+               "{{true.any}}",
+               hasError, `unexpected . after term`},
 }
 
 func TestErrors(t *testing.T) {