hashicorp / hashicorp/hcl

hclsyntax: Recovery of `FunctionCallExpr` with trailing open `[`

Open
#604 1 comment 0 reactions 0 assignees View on GitHub
enhancement
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.