Skip to content

Commit

Permalink
decoder: Provide reference origins for ForExpr
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Jan 26, 2024
1 parent 9f4a7b1 commit 8a1486e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
60 changes: 60 additions & 0 deletions decoder/expr_any_for.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"

"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/reference"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
Expand Down Expand Up @@ -155,6 +156,65 @@ func (a Any) semanticTokensForForExpr(ctx context.Context) ([]lang.SemanticToken
return tokens, false
}

func (a Any) refOriginsForForExpr(ctx context.Context, allowSelfRefs bool) (reference.Origins, bool) {
origins := make(reference.Origins, 0)

// There is currently no way of decoding for expressions in JSON
// so we just collect them using the fallback logic assuming "any"
// constraint and focus on collecting expressions in HCL with more
// accurate constraints below.

switch eType := a.expr.(type) {
case *hclsyntax.ForExpr:
if !isTypeIterable(a.cons.OfType) {
return nil, false
}

// TODO: eType.KeyVarExpr.Range() to collect key as origin
// TODO: eType.ValVarExpr.Range() to collect value as origin

if collExpr, ok := newExpression(a.pathCtx, eType.CollExpr, a.cons).(ReferenceOriginsExpression); ok {
origins = append(origins, collExpr.ReferenceOrigins(ctx, allowSelfRefs)...)
}

if eType.KeyExpr != nil {
typ, ok := iterableKeyType(a.cons.OfType)
if !ok {
return nil, false
}
cons := schema.AnyExpression{
OfType: typ,
}
if keyExpr, ok := newExpression(a.pathCtx, eType.KeyExpr, cons).(ReferenceOriginsExpression); ok {
origins = append(origins, keyExpr.ReferenceOrigins(ctx, allowSelfRefs)...)
}
}

typ, ok := iterableValueType(a.cons.OfType)
if !ok {
return nil, false
}
cons := schema.AnyExpression{
OfType: typ,
}
if valExpr, ok := newExpression(a.pathCtx, eType.ValExpr, cons).(ReferenceOriginsExpression); ok {
origins = append(origins, valExpr.ReferenceOrigins(ctx, allowSelfRefs)...)
}

if eType.CondExpr != nil {
cons := schema.AnyExpression{
OfType: cty.Bool,
}

if condExpr, ok := newExpression(a.pathCtx, eType.CondExpr, cons).(ReferenceOriginsExpression); ok {
origins = append(origins, condExpr.ReferenceOrigins(ctx, allowSelfRefs)...)
}
}
}

return origins, false
}

func isTypeIterable(typ cty.Type) bool {
if typ == cty.DynamicPseudoType {
return true
Expand Down
5 changes: 4 additions & 1 deletion decoder/expr_any_ref_origins.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ func (a Any) ReferenceOrigins(ctx context.Context, allowSelfRefs bool) reference

func (a Any) refOriginsForNonComplexExpr(ctx context.Context, allowSelfRefs bool) reference.Origins {
// TODO: Support splat expression https://github.com/hashicorp/terraform-ls/issues/526
// TODO: Support for-in-if expression https://github.com/hashicorp/terraform-ls/issues/527
// TODO: Support relative traversals https://github.com/hashicorp/terraform-ls/issues/532

if origins, ok := a.refOriginsForOperatorExpr(ctx, allowSelfRefs); ok {
Expand All @@ -132,6 +131,10 @@ func (a Any) refOriginsForNonComplexExpr(ctx context.Context, allowSelfRefs bool
return origins
}

if origins, ok := a.refOriginsForForExpr(ctx, allowSelfRefs); ok {
return origins
}

// attempt to get accurate constraint for the origins
// if we recognise the given expression
funcExpr := functionExpr{
Expand Down

0 comments on commit 8a1486e

Please sign in to comment.