hclsyntax: Recovery of `FunctionCallExpr` with trailing open `[`
- Dominant language
- Go
- Stars
- 5.8k
- Forks
- 657
- Avg merge
- 20h 36m
- Merged PRs (30d)
- 6
Description
## Context
Two relatively common cases which come up when editing HCL in an editor are the following:
- `attr = func_call(var.foo.)`
- `attr = func_call(var.foo[)`
Where the expectation on the IDE is to provide completion of [object] attributes or [map] keys. This is currently only possible to do for the dotted attribute syntax.
**Why**
There is a difference in how the `hclsyntax` parser treats trailing `[` and trailing `.`.
### Trailing dot (recovery works as expected)
```go
package main
import (
"log"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)
func main() {
cfg := `attr = bar(var.foo.)`
f, diags := hclsyntax.ParseConfig([]byte(cfg), "", hcl.InitialPos)
if len(diags) > 0 {
log.Printf("diagnostics: %s", diags)
}
attrs, _ := f.Body.JustAttributes()
log.Printf("expression range: %#v", attrs["attr"].Expr.Range())
}
```
```
2009/11/10 23:00:00 diagnostics: :1,20-21: Invalid attribute name; An attribute name is required after a dot.
2009/11/10 23:00:00 expression range: hcl.Range{Filename:"", Start:hcl.Pos{Line:1, Column:8, Byte:7}, End:hcl.Pos{Line:1, Column:21, Byte:20}}
```
The parser produces relatively helpful diagnostic, recognising the assumption that there's an incomplete traversal.
### Trailing bracket
```go
// ...
cfg := `attr = bar(var.foo[)`
// ...
```
```
2009/11/10 23:00:00 diagnostics: :1,20-21: Invalid expression; Expected the start of an expression, but found an invalid expression token.
2009/11/10 23:00:00 expression range: hcl.Range{Filename:"", Start:hcl.Pos{Line:1, Column:8, Byte:7}, End:hcl.Pos{Line:0, Column:0, Byte:0}}
```
Here the parser produces less helpful diagnostic, referring to the whole expression being wrong. Relatedly it also leaves us with an empty `FunctionCallExpr` `CloseParenRange.End`, making it impossible or very hard to do further recovery downstream.
---
I also noticed the `ScopeTraversalExpr` in that snippet ends up eating the closing paranthesis, which may be the root cause of this:
```go
// ...
cfg := `attr = bar(var.foo[)`
// ...
attrs, _ := f.Body.JustAttributes()
funcExpr := attrs["attr"].Expr.(*hclsyntax.FunctionCallExpr)
log.Printf("expression range: %#v", funcExpr.Args[0].Range())
```
```
2009/11/10 23:00:00 expression range: hcl.Range{Filename:"", Start:hcl.Pos{Line:1, Column:12, Byte:11}, End:hcl.Pos{Line:1, Column:21, Byte:20}}
```
And similar problem exists for other variations with `[`, e.g.
```hcl
output "test" {
value = var.foo[
}
```
where parser ends up eating the closing `}` and produces equally unhelpful diagnostic:
```
Invalid expression: Expected the start of an expression, but found an invalid expression token.
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with hclsyntax.ParseConfig and inspect recovery around FunctionCallExpr, ScopeTraversalExpr, and trailing '[' tokens. Reproduce the examples in the issue, then verify that incomplete bracket expressions preserve the function and enclosing delimiters while producing a focused diagnostic and usable expression ranges.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100