Commit 180541b2 authored by Rob Pike's avatar Rob Pike

text/template: fix redefinition bugs

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5696087
parent 69015b6f
...@@ -265,6 +265,12 @@ func TestRedefinition(t *testing.T) { ...@@ -265,6 +265,12 @@ func TestRedefinition(t *testing.T) {
if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil { if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
t.Fatalf("parse 1: %v", err) t.Fatalf("parse 1: %v", err)
} }
if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err == nil {
t.Fatal("expected error")
}
if !strings.Contains(err.Error(), "redefinition") {
t.Fatalf("expected redefinition error; got %v", err)
}
if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil { if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil {
t.Fatal("expected error") t.Fatal("expected error")
} }
......
...@@ -193,6 +193,8 @@ func (t *Tree) add(treeSet map[string]*Tree) { ...@@ -193,6 +193,8 @@ func (t *Tree) add(treeSet map[string]*Tree) {
// IsEmptyTree reports whether this tree (node) is empty of everything but space. // IsEmptyTree reports whether this tree (node) is empty of everything but space.
func IsEmptyTree(n Node) bool { func IsEmptyTree(n Node) bool {
switch n := n.(type) { switch n := n.(type) {
case nil:
return true
case *ActionNode: case *ActionNode:
case *IfNode: case *IfNode:
case *ListNode: case *ListNode:
......
...@@ -287,6 +287,9 @@ var isEmptyTests = []isEmptyTest{ ...@@ -287,6 +287,9 @@ var isEmptyTests = []isEmptyTest{
} }
func TestIsEmpty(t *testing.T) { func TestIsEmpty(t *testing.T) {
if !IsEmptyTree(nil) {
t.Errorf("nil tree is not empty")
}
for _, test := range isEmptyTests { for _, test := range isEmptyTests {
tree, err := New("root").Parse(test.input, "", "", make(map[string]*Tree), nil) tree, err := New("root").Parse(test.input, "", "", make(map[string]*Tree), nil)
if err != nil { if err != nil {
......
...@@ -178,10 +178,11 @@ func (t *Template) Parse(text string) (*Template, error) { ...@@ -178,10 +178,11 @@ func (t *Template) Parse(text string) (*Template, error) {
tmpl = t.New(name) tmpl = t.New(name)
} }
// Even if t == tmpl, we need to install it in the common.tmpl map. // Even if t == tmpl, we need to install it in the common.tmpl map.
if err := t.associate(tmpl); err != nil { if replace, err := t.associate(tmpl, tree); err != nil {
return nil, err return nil, err
} else if replace {
tmpl.Tree = tree
} }
tmpl.Tree = tree
tmpl.leftDelim = t.leftDelim tmpl.leftDelim = t.leftDelim
tmpl.rightDelim = t.rightDelim tmpl.rightDelim = t.rightDelim
} }
...@@ -191,22 +192,23 @@ func (t *Template) Parse(text string) (*Template, error) { ...@@ -191,22 +192,23 @@ func (t *Template) Parse(text string) (*Template, error) {
// associate installs the new template into the group of templates associated // associate installs the new template into the group of templates associated
// with t. It is an error to reuse a name except to overwrite an empty // with t. It is an error to reuse a name except to overwrite an empty
// template. The two are already known to share the common structure. // template. The two are already known to share the common structure.
func (t *Template) associate(new *Template) error { // The boolean return value reports wither to store this tree as t.Tree.
func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
if new.common != t.common { if new.common != t.common {
panic("internal error: associate not common") panic("internal error: associate not common")
} }
name := new.name name := new.name
if old := t.tmpl[name]; old != nil { if old := t.tmpl[name]; old != nil {
oldIsEmpty := parse.IsEmptyTree(old.Root) oldIsEmpty := parse.IsEmptyTree(old.Root)
newIsEmpty := new.Tree != nil && parse.IsEmptyTree(new.Root) newIsEmpty := parse.IsEmptyTree(tree.Root)
if !oldIsEmpty && !newIsEmpty {
return fmt.Errorf("template: redefinition of template %q", name)
}
if newIsEmpty { if newIsEmpty {
// Whether old is empty or not, new is empty; no reason to replace old. // Whether old is empty or not, new is empty; no reason to replace old.
return nil return false, nil
}
if !oldIsEmpty {
return false, fmt.Errorf("template: redefinition of template %q", name)
} }
} }
t.tmpl[name] = new t.tmpl[name] = new
return nil return true, nil
} }
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