Skip to content

Commit

Permalink
decoder: Implement reference targets for Object
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Mar 14, 2023
1 parent bf3a9c5 commit ece2ea1
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 8 deletions.
8 changes: 0 additions & 8 deletions decoder/expr_object.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package decoder

import (
"context"

"github.com/hashicorp/hcl-lang/reference"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
)
Expand All @@ -13,8 +10,3 @@ type Object struct {
cons schema.Object
pathCtx *PathContext
}

func (obj Object) ReferenceTargets(ctx context.Context, targetCtx *TargetContext) reference.Targets {
// TODO
return nil
}
103 changes: 103 additions & 0 deletions decoder/expr_object_ref_targets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package decoder

import (
"context"

"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/reference"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
)

func (obj Object) ReferenceTargets(ctx context.Context, targetCtx *TargetContext) reference.Targets {
eType, ok := obj.expr.(*hclsyntax.ObjectConsExpr)
if !ok {
return reference.Targets{}
}

if len(eType.Items) == 0 || len(obj.cons.Attributes) == 0 {
return reference.Targets{}
}

attrTargets := make(reference.Targets, 0)

for _, item := range eType.Items {
keyName, _, ok := rawObjectKey(item.KeyExpr)
if !ok {
// avoid collecting item w/ invalid key
continue
}

aSchema, ok := obj.cons.Attributes[keyName]
if !ok {
// avoid collecting for unknown attribute
continue
}

expr := newExpression(obj.pathCtx, item.ValueExpr, aSchema.Constraint)
if e, ok := expr.(ReferenceTargetsExpression); ok {
if targetCtx == nil {
// collect any targets inside the expression
// if attribute itself isn't targetable
attrTargets = append(attrTargets, e.ReferenceTargets(ctx, nil)...)
continue
}

elemCtx := targetCtx.Copy()
elemCtx.ParentAddress = append(elemCtx.ParentAddress, lang.IndexStep{
Key: cty.StringVal(keyName),
})
if elemCtx.ParentLocalAddress != nil {
elemCtx.ParentLocalAddress = append(elemCtx.ParentLocalAddress, lang.IndexStep{
Key: cty.StringVal(keyName),
})
}

attrTargets = append(attrTargets, e.ReferenceTargets(ctx, elemCtx)...)
}
}

// TODO: targets for undeclared attributes w/out range

targets := make(reference.Targets, 0)

if targetCtx != nil {
// collect target for the whole object

// type-aware
if targetCtx.AsExprType {
objType, ok := obj.cons.ConstraintType()
if ok {
targets = append(targets, reference.Target{
Addr: targetCtx.ParentAddress,
Name: targetCtx.FriendlyName,
Type: objType,
ScopeId: targetCtx.ScopeId,
RangePtr: obj.expr.Range().Ptr(),
NestedTargets: attrTargets,
LocalAddr: targetCtx.ParentLocalAddress,
TargetableFromRangePtr: targetCtx.TargetableFromRangePtr,
})
}
}

// type-unaware
if targetCtx.AsReference {
targets = append(targets, reference.Target{
Addr: targetCtx.ParentAddress,
Name: targetCtx.FriendlyName,
ScopeId: targetCtx.ScopeId,
RangePtr: obj.expr.Range().Ptr(),
NestedTargets: attrTargets,
LocalAddr: targetCtx.ParentLocalAddress,
TargetableFromRangePtr: targetCtx.TargetableFromRangePtr,
})
}
} else {
// treat element targets as 1st class ones
// if the object itself isn't targetable
targets = attrTargets
}

return targets
}

0 comments on commit ece2ea1

Please sign in to comment.