hclwrite: Fix panic for dotted full splat (foo.*)

The following expression caused a panic in hclwrite:

  a = foo.*

This was due to the unusual dotted form of a full splat (where the splat
operator is at the end of the expression) being generated with an
invalid source range. In the full splat case, the end of the range was
uninitialized, which caused the token slice to be empty, and thus the
panic.

This commit fixes the bug, adds test coverage, and includes some bonus
tests for other splat expression cases.
This commit is contained in:
Alisdair McDiarmid 2020-05-13 16:02:20 -04:00
parent fff0a094cc
commit d58c873a08
2 changed files with 217 additions and 0 deletions

View File

@ -670,6 +670,7 @@ Traversal:
trav := make(hcl.Traversal, 0, 1) trav := make(hcl.Traversal, 0, 1)
var firstRange, lastRange hcl.Range var firstRange, lastRange hcl.Range
firstRange = p.NextRange() firstRange = p.NextRange()
lastRange = marker.Range
for p.Peek().Type == TokenDot { for p.Peek().Type == TokenDot {
dot := p.Read() dot := p.Read()

View File

@ -618,6 +618,222 @@ func TestParse(t *testing.T) {
}, },
}, },
}, },
{
"a = foo.*\n",
TestTreeNode{
Type: "Body",
Children: []TestTreeNode{
{
Type: "Attribute",
Children: []TestTreeNode{
{
Type: "comments",
},
{
Type: "identifier",
Val: "a",
},
{
Type: "Tokens",
Val: " =",
},
{
Type: "Expression",
Children: []TestTreeNode{
{
Type: "Traversal",
Children: []TestTreeNode{
{
Type: "TraverseName",
Children: []TestTreeNode{
{
Type: "identifier",
Val: " foo",
},
},
},
},
},
{
Type: "Tokens",
Val: ".*",
},
},
},
{
Type: "comments",
},
{
Type: "Tokens",
Val: "\n",
},
},
},
},
},
},
{
"a = foo.*.bar\n",
TestTreeNode{
Type: "Body",
Children: []TestTreeNode{
{
Type: "Attribute",
Children: []TestTreeNode{
{
Type: "comments",
},
{
Type: "identifier",
Val: "a",
},
{
Type: "Tokens",
Val: " =",
},
{
Type: "Expression",
Children: []TestTreeNode{
{
Type: "Traversal",
Children: []TestTreeNode{
{
Type: "TraverseName",
Children: []TestTreeNode{
{
Type: "identifier",
Val: " foo",
},
},
},
},
},
{
Type: "Tokens",
Val: ".*.bar",
},
},
},
{
Type: "comments",
},
{
Type: "Tokens",
Val: "\n",
},
},
},
},
},
},
{
"a = foo[*]\n",
TestTreeNode{
Type: "Body",
Children: []TestTreeNode{
{
Type: "Attribute",
Children: []TestTreeNode{
{
Type: "comments",
},
{
Type: "identifier",
Val: "a",
},
{
Type: "Tokens",
Val: " =",
},
{
Type: "Expression",
Children: []TestTreeNode{
{
Type: "Traversal",
Children: []TestTreeNode{
{
Type: "TraverseName",
Children: []TestTreeNode{
{
Type: "identifier",
Val: " foo",
},
},
},
},
},
{
Type: "Tokens",
Val: "[*]",
},
},
},
{
Type: "comments",
},
{
Type: "Tokens",
Val: "\n",
},
},
},
},
},
},
{
"a = foo[*].bar\n",
TestTreeNode{
Type: "Body",
Children: []TestTreeNode{
{
Type: "Attribute",
Children: []TestTreeNode{
{
Type: "comments",
},
{
Type: "identifier",
Val: "a",
},
{
Type: "Tokens",
Val: " =",
},
{
Type: "Expression",
Children: []TestTreeNode{
{
Type: "Traversal",
Children: []TestTreeNode{
{
Type: "TraverseName",
Children: []TestTreeNode{
{
Type: "identifier",
Val: " foo",
},
},
},
},
},
{
Type: "Tokens",
Val: "[*].bar",
},
},
},
{
Type: "comments",
},
{
Type: "Tokens",
Val: "\n",
},
},
},
},
},
},
{ {
"a = foo[bar]\n", "a = foo[bar]\n",
TestTreeNode{ TestTreeNode{