]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: make zero Template work again
authorRuss Cox <rsc@golang.org>
Wed, 24 Jun 2015 15:11:51 +0000 (11:11 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 24 Jun 2015 22:27:33 +0000 (22:27 +0000)
Fixes #11379.

Change-Id: Idbb5c3faad472b77e9867dd2d4551fef5e4ac5f1
Reviewed-on: https://go-review.googlesource.com/11421
Reviewed-by: Rob Pike <r@golang.org>
src/text/template/exec.go
src/text/template/exec_test.go
src/text/template/helper.go
src/text/template/option.go
src/text/template/template.go

index 8e9edcfbe99951ddb4ce499b1a3e1094c322a2c9..daba788b55bd56c111787d0b1372e7905aa1f5f5 100644 (file)
@@ -113,7 +113,10 @@ func errRecover(errp *error) {
 // the output writer.
 // A template may be executed safely in parallel.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
-       tmpl := t.tmpl[name]
+       var tmpl *Template
+       if t.common != nil {
+               tmpl = t.tmpl[name]
+       }
        if tmpl == nil {
                return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
        }
@@ -146,6 +149,9 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
 // it returns the empty string. For generating an error message here
 // and in html/template.
 func (t *Template) DefinedTemplates() string {
+       if t.common == nil {
+               return ""
+       }
        var b bytes.Buffer
        for name, tmpl := range t.tmpl {
                if tmpl.Tree == nil || tmpl.Root == nil {
index f083547ed8db79198f56c3d887dd1d68347a039d..ba0e434f98cfeb15647ee794af4d027492a86b7e 100644 (file)
@@ -882,7 +882,13 @@ func TestTree(t *testing.T) {
 
 func TestExecuteOnNewTemplate(t *testing.T) {
        // This is issue 3872.
-       _ = New("Name").Templates()
+       New("Name").Templates()
+       // This is issue 11379.
+       new(Template).Templates()
+       new(Template).Parse("")
+       new(Template).New("abc").Parse("")
+       new(Template).Execute(nil, nil)                // returns an error (but does not crash)
+       new(Template).ExecuteTemplate(nil, "XXX", nil) // returns an error (but does not crash)
 }
 
 const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}`
index 07d432bd3bdac00478a8505744db9375b4df841e..787ca62e5f39922e9630fce71e5d7837ff399af7 100644 (file)
@@ -42,6 +42,7 @@ func ParseFiles(filenames ...string) (*Template, error) {
 // contents before calling ParseFiles, t.Execute may fail. In that
 // case use t.ExecuteTemplate to execute a valid template.
 func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
+       t.init()
        return parseFiles(t, filenames...)
 }
 
@@ -97,6 +98,7 @@ func ParseGlob(pattern string) (*Template, error) {
 // equivalent to calling t.ParseFiles with the list of files matched by the
 // pattern.
 func (t *Template) ParseGlob(pattern string) (*Template, error) {
+       t.init()
        return parseGlob(t, pattern)
 }
 
index fcdd8714a611867d4e8f6fd9ca259c1959b5e038..addce2d890d6d842445dae44c8d140a90416c41a 100644 (file)
@@ -40,6 +40,7 @@ type option struct {
 //             Execution stops immediately with an error.
 //
 func (t *Template) Option(opt ...string) *Template {
+       t.init()
        for _, s := range opt {
                t.setOption(s)
        }
index de03a2e8a1e5427e9404ef23995dd210f2bd73c1..3e80982123af54136be2d705b2c6b75ebf71f45e 100644 (file)
@@ -52,6 +52,7 @@ func (t *Template) Name() string {
 // delimiters. The association, which is transitive, allows one template to
 // invoke another with a {{template}} action.
 func (t *Template) New(name string) *Template {
+       t.init()
        nt := &Template{
                name:       name,
                common:     t.common,
@@ -81,6 +82,9 @@ func (t *Template) init() {
 func (t *Template) Clone() (*Template, error) {
        nt := t.copy(nil)
        nt.init()
+       if t.common == nil {
+               return nt, nil
+       }
        for k, v := range t.tmpl {
                if k == t.name {
                        nt.tmpl[t.name] = nt
@@ -115,6 +119,7 @@ func (t *Template) copy(c *common) *Template {
 // If the template does not already exist, it will create a new one.
 // It is an error to reuse a name except to overwrite an empty template.
 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+       t.init()
        // If the name is the name of this template, overwrite this template.
        // The associate method checks it's not a redefinition.
        nt := t
@@ -132,6 +137,9 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error
 
 // Templates returns a slice of defined templates associated with t.
 func (t *Template) Templates() []*Template {
+       if t.common == nil {
+               return nil
+       }
        // Return a slice so we don't expose the map.
        m := make([]*Template, 0, len(t.tmpl))
        for _, v := range t.tmpl {
@@ -146,6 +154,7 @@ func (t *Template) Templates() []*Template {
 // corresponding default: {{ or }}.
 // The return value is the template, so calls can be chained.
 func (t *Template) Delims(left, right string) *Template {
+       t.init()
        t.leftDelim = left
        t.rightDelim = right
        return t
@@ -156,6 +165,7 @@ func (t *Template) Delims(left, right string) *Template {
 // type. However, it is legal to overwrite elements of the map. The return
 // value is the template, so calls can be chained.
 func (t *Template) Funcs(funcMap FuncMap) *Template {
+       t.init()
        t.muFuncs.Lock()
        defer t.muFuncs.Unlock()
        addValueFuncs(t.execFuncs, funcMap)
@@ -166,6 +176,9 @@ func (t *Template) Funcs(funcMap FuncMap) *Template {
 // Lookup returns the template with the given name that is associated with t.
 // It returns nil if there is no such template or the template has no definition.
 func (t *Template) Lookup(name string) *Template {
+       if t.common == nil {
+               return nil
+       }
        return t.tmpl[name]
 }
 
@@ -177,6 +190,7 @@ func (t *Template) Lookup(name string) *Template {
 // (In multiple calls to Parse with the same receiver template, only one call
 // can contain text other than space, comments, and template definitions.)
 func (t *Template) Parse(text string) (*Template, error) {
+       t.init()
        t.muFuncs.RLock()
        trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
        t.muFuncs.RUnlock()