Skip to content

Extend symbols with concrete *hcl.(Attribute/Block/Expression) #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions decoder/symbol.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)

type symbolImplSigil struct{}
Expand All @@ -27,6 +28,7 @@ type Symbol interface {
type BlockSymbol struct {
Type string
Labels []string
Block *hcl.Block

path lang.Path
rng hcl.Range
Expand Down Expand Up @@ -71,8 +73,9 @@ func (bs *BlockSymbol) Path() lang.Path {

// AttributeSymbol is Symbol implementation representing an attribute
type AttributeSymbol struct {
AttrName string
ExprKind lang.SymbolExprKind
AttrName string
ExprKind lang.SymbolExprKind
Attribute *hcl.Attribute

path lang.Path
rng hcl.Range
Expand Down Expand Up @@ -115,6 +118,11 @@ type ExprSymbol struct {
ExprName string
ExprKind lang.SymbolExprKind

// Expr is set if the parent Expression is a *hclsyntax.TupleConsExpr
Expr hcl.Expression
// Item is set if the parent Expression is a *hclsyntax.ObjectConsExpr
Item hclsyntax.ObjectConsItem

path lang.Path
rng hcl.Range
nestedSymbols []Symbol
Expand Down
4 changes: 4 additions & 0 deletions decoder/symbols.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func (d *PathDecoder) symbolsForBody(body hcl.Body, bodySchema *schema.BodySchem
symbols = append(symbols, &AttributeSymbol{
AttrName: name,
ExprKind: symbolExprKind(attr.Expr),
Attribute: attr,
path: d.path,
rng: attr.Range,
nestedSymbols: d.nestedSymbolsForExpr(attr.Expr),
Expand All @@ -124,6 +125,7 @@ func (d *PathDecoder) symbolsForBody(body hcl.Body, bodySchema *schema.BodySchem
symbols = append(symbols, &BlockSymbol{
Type: block.Type,
Labels: block.Labels,
Block: block.Block,
path: d.path,
rng: block.Range,
nestedSymbols: d.symbolsForBody(block.Body, bSchema),
Expand Down Expand Up @@ -171,6 +173,7 @@ func (d *PathDecoder) nestedSymbolsForExpr(expr hcl.Expression) []Symbol {
symbols = append(symbols, &ExprSymbol{
ExprName: fmt.Sprintf("%d", i),
ExprKind: symbolExprKind(item),
Expr: item,
path: d.path,
rng: item.Range(),
nestedSymbols: d.nestedSymbolsForExpr(item),
Expand All @@ -187,6 +190,7 @@ func (d *PathDecoder) nestedSymbolsForExpr(expr hcl.Expression) []Symbol {
symbols = append(symbols, &ExprSymbol{
ExprName: key.AsString(),
ExprKind: symbolExprKind(item.ValueExpr),
Item: item,
path: d.path,
rng: hcl.RangeBetween(item.KeyExpr.Range(), item.ValueExpr.Range()),
nestedSymbols: d.nestedSymbolsForExpr(item.ValueExpr),
Expand Down
119 changes: 80 additions & 39 deletions decoder/symbols_hcl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
Expand Down Expand Up @@ -81,17 +82,19 @@ provider "google" {
"aws_vpc",
"main",
},
path: lang.Path{Path: dirPath},
Block: f1.InnermostBlockAtPos(hcl.Pos{Byte: 1}),
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "first.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 1},
End: hcl.Pos{Line: 4, Column: 2, Byte: 59},
},
nestedSymbols: []Symbol{
&AttributeSymbol{
AttrName: "cidr_block",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
path: lang.Path{Path: dirPath},
AttrName: "cidr_block",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
Attribute: bodyMustJustAttributes(t, f1.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["cidr_block"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "first.tf",
Start: hcl.Pos{Line: 3, Column: 3, Byte: 31},
Expand All @@ -106,17 +109,19 @@ provider "google" {
Labels: []string{
"google",
},
path: lang.Path{Path: dirPath},
Block: f2.InnermostBlockAtPos(hcl.Pos{Byte: 1}),
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "second.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 1},
End: hcl.Pos{Line: 5, Column: 2, Byte: 84},
},
nestedSymbols: []Symbol{
&AttributeSymbol{
AttrName: "project",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
path: lang.Path{Path: dirPath},
AttrName: "project",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
Attribute: bodyMustJustAttributes(t, f2.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["project"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "second.tf",
Start: hcl.Pos{Line: 3, Column: 3, Byte: 23},
Expand All @@ -125,9 +130,10 @@ provider "google" {
nestedSymbols: []Symbol{},
},
&AttributeSymbol{
AttrName: "region",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
path: lang.Path{Path: dirPath},
AttrName: "region",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
Attribute: bodyMustJustAttributes(t, f2.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["region"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "second.tf",
Start: hcl.Pos{Line: 4, Column: 3, Byte: 55},
Expand All @@ -139,7 +145,7 @@ provider "google" {
},
}

diff := cmp.Diff(expectedSymbols, symbols)
diff := cmp.Diff(expectedSymbols, symbols, cmpopts.IgnoreFields(BlockSymbol{}, "Block"))
if diff != "" {
t.Fatalf("unexpected symbols: %s", diff)
}
Expand Down Expand Up @@ -189,17 +195,19 @@ resource "aws_instance" "test" {
"aws_instance",
"test",
},
path: lang.Path{Path: dirPath},
Block: f.InnermostBlockAtPos(hcl.Pos{Byte: 1}),
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 1},
End: hcl.Pos{Line: 11, Column: 2, Byte: 180},
},
nestedSymbols: []Symbol{
&AttributeSymbol{
AttrName: "subnet_ids",
ExprKind: lang.TupleConsExprKind{},
path: lang.Path{Path: dirPath},
AttrName: "subnet_ids",
ExprKind: lang.TupleConsExprKind{},
Attribute: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["subnet_ids"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand All @@ -219,6 +227,7 @@ resource "aws_instance" "test" {
ExprKind: lang.LiteralTypeKind{
Type: cty.String,
},
Expr: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["subnet_ids"].Expr.(*hclsyntax.TupleConsExpr).ExprList()[0],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -240,6 +249,7 @@ resource "aws_instance" "test" {
ExprKind: lang.LiteralTypeKind{
Type: cty.String,
},
Expr: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["subnet_ids"].Expr.(*hclsyntax.TupleConsExpr).ExprList()[1],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -259,9 +269,10 @@ resource "aws_instance" "test" {
},
},
&AttributeSymbol{
AttrName: "configuration",
ExprKind: lang.ObjectConsExprKind{},
path: lang.Path{Path: dirPath},
AttrName: "configuration",
ExprKind: lang.ObjectConsExprKind{},
Attribute: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["configuration"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand All @@ -281,6 +292,7 @@ resource "aws_instance" "test" {
ExprKind: lang.LiteralTypeKind{
Type: cty.String,
},
Item: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["configuration"].Expr.(*hclsyntax.ObjectConsExpr).Items[0],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -302,6 +314,7 @@ resource "aws_instance" "test" {
ExprKind: lang.LiteralTypeKind{
Type: cty.Number,
},
Item: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["configuration"].Expr.(*hclsyntax.ObjectConsExpr).Items[1],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -323,6 +336,7 @@ resource "aws_instance" "test" {
ExprKind: lang.LiteralTypeKind{
Type: cty.Bool,
},
Item: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["configuration"].Expr.(*hclsyntax.ObjectConsExpr).Items[2],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -342,9 +356,10 @@ resource "aws_instance" "test" {
},
},
&AttributeSymbol{
AttrName: "random_kw",
ExprKind: lang.ReferenceExprKind{},
path: lang.Path{Path: dirPath},
AttrName: "random_kw",
ExprKind: lang.ReferenceExprKind{},
Attribute: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["random_kw"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand Down Expand Up @@ -414,17 +429,19 @@ resource "aws_instance" "test" {
"aws_instance",
"test",
},
path: lang.Path{Path: dirPath},
path: lang.Path{Path: dirPath},
Block: f.InnermostBlockAtPos(hcl.Pos{Byte: 1}),
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 1},
End: hcl.Pos{Line: 11, Column: 2, Byte: 220},
},
nestedSymbols: []Symbol{
&AttributeSymbol{
AttrName: "subnet_ids",
ExprKind: lang.TupleConsExprKind{},
path: lang.Path{Path: dirPath},
AttrName: "subnet_ids",
ExprKind: lang.TupleConsExprKind{},
Attribute: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["subnet_ids"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand All @@ -442,6 +459,7 @@ resource "aws_instance" "test" {
&ExprSymbol{
ExprName: "0",
ExprKind: lang.ReferenceExprKind{},
Expr: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["subnet_ids"].Expr.(*hclsyntax.TupleConsExpr).ExprList()[0],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -463,6 +481,7 @@ resource "aws_instance" "test" {
ExprKind: lang.LiteralTypeKind{
Type: cty.String,
},
Expr: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["subnet_ids"].Expr.(*hclsyntax.TupleConsExpr).ExprList()[1],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Expand All @@ -482,9 +501,10 @@ resource "aws_instance" "test" {
},
},
&AttributeSymbol{
AttrName: "configuration",
ExprKind: lang.ObjectConsExprKind{},
path: lang.Path{Path: dirPath},
AttrName: "configuration",
ExprKind: lang.ObjectConsExprKind{},
path: lang.Path{Path: dirPath},
Attribute: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["configuration"],
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand All @@ -503,6 +523,7 @@ resource "aws_instance" "test" {
ExprName: "num",
ExprKind: lang.ReferenceExprKind{},
path: lang.Path{Path: dirPath},
Item: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["configuration"].Expr.(*hclsyntax.ObjectConsExpr).Items[1],
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand All @@ -521,9 +542,10 @@ resource "aws_instance" "test" {
},
},
&AttributeSymbol{
AttrName: "random_kw",
ExprKind: lang.ReferenceExprKind{},
path: lang.Path{Path: dirPath},
AttrName: "random_kw",
ExprKind: lang.ReferenceExprKind{},
Attribute: bodyMustJustAttributes(t, f.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["random_kw"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Expand Down Expand Up @@ -593,17 +615,19 @@ provider "google" {
Labels: []string{
"google",
},
path: lang.Path{Path: dirPath},
Block: f2.InnermostBlockAtPos(hcl.Pos{Byte: 1}),
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "second.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 1},
End: hcl.Pos{Line: 5, Column: 2, Byte: 84},
},
nestedSymbols: []Symbol{
&AttributeSymbol{
AttrName: "project",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
path: lang.Path{Path: dirPath},
AttrName: "project",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
Attribute: bodyMustJustAttributes(t, f2.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["project"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "second.tf",
Start: hcl.Pos{Line: 3, Column: 3, Byte: 23},
Expand All @@ -612,9 +636,10 @@ provider "google" {
nestedSymbols: []Symbol{},
},
&AttributeSymbol{
AttrName: "region",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
path: lang.Path{Path: dirPath},
AttrName: "region",
ExprKind: lang.LiteralTypeKind{Type: cty.String},
Attribute: bodyMustJustAttributes(t, f2.InnermostBlockAtPos(hcl.Pos{Byte: 1}).Body)["region"],
path: lang.Path{Path: dirPath},
rng: hcl.Range{
Filename: "second.tf",
Start: hcl.Pos{Line: 4, Column: 3, Byte: 55},
Expand All @@ -631,3 +656,19 @@ provider "google" {
t.Fatalf("unexpected symbols: %s", diff)
}
}

func bodyMustJustAttributes(t *testing.T, body hcl.Body) hcl.Attributes {
attrs, diags := body.JustAttributes()
if diags.HasErrors() {
t.Fatalf("failed to call JustAttributes: %v", diags.Error())
}
return attrs
}

func bodyMustContent(t *testing.T, body hcl.Body, schema *hcl.BodySchema) *hcl.BodyContent {
bc, diags := body.Content(schema)
if diags.HasErrors() {
t.Fatal(diags.Error())
}
return bc
}
Loading