From d58c873a08f1431cba860fb66f572d053837c192 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Wed, 13 May 2020 16:02:20 -0400 Subject: [PATCH] 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. --- hclsyntax/parser.go | 1 + hclwrite/parser_test.go | 216 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) diff --git a/hclsyntax/parser.go b/hclsyntax/parser.go index 83efd9a..858bb7c 100644 --- a/hclsyntax/parser.go +++ b/hclsyntax/parser.go @@ -670,6 +670,7 @@ Traversal: trav := make(hcl.Traversal, 0, 1) var firstRange, lastRange hcl.Range firstRange = p.NextRange() + lastRange = marker.Range for p.Peek().Type == TokenDot { dot := p.Read() diff --git a/hclwrite/parser_test.go b/hclwrite/parser_test.go index 9c57c6c..9a4339f 100644 --- a/hclwrite/parser_test.go +++ b/hclwrite/parser_test.go @@ -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", TestTreeNode{