Skip to content

Commit

Permalink
Use local ref. targets for each.* references
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Nov 22, 2022
1 parent f48e63d commit cb106f5
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 64 deletions.
86 changes: 80 additions & 6 deletions decoder/body_extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -693,15 +693,52 @@ variable "test" {
},
},
},
reference.Targets{},
reference.Targets{
{
LocalAddr: lang.Address{
lang.RootStep{Name: "each"},
lang.AttrStep{Name: "key"},
},
Type: cty.String,
Description: lang.Markdown("The map key (or set member) corresponding to this instance"),
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
},
DefRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
},
},
{
LocalAddr: lang.Address{
lang.RootStep{Name: "each"},
lang.AttrStep{Name: "value"},
},
Type: cty.DynamicPseudoType,
Description: lang.Markdown("The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
},
DefRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
},
},
},
`resource "aws_instance" "foo" {
for_each = {
a_group = "eastus"
another_group = "westus2"
}
thing =
}`,
hcl.Pos{Line: 6, Column: 8, Byte: 101},
hcl.Pos{Line: 6, Column: 9, Byte: 102},
lang.CompleteCandidates([]lang.Candidate{
{
Label: "each.key",
Expand All @@ -723,7 +760,7 @@ thing =
},
{
Label: "each.value",
Detail: "any type",
Detail: "dynamic",
Kind: lang.TraversalCandidateKind,
Description: lang.MarkupContent{
Value: "The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)",
Expand Down Expand Up @@ -880,7 +917,7 @@ for_each = {
IsOptional: true,
Expr: schema.ExprConstraints{
schema.TraversalExpr{
OfType: cty.Number,
OfType: cty.DynamicPseudoType,
},
},
},
Expand All @@ -892,7 +929,44 @@ for_each = {
},
},
},
reference.Targets{},
reference.Targets{
{
LocalAddr: lang.Address{
lang.RootStep{Name: "each"},
lang.AttrStep{Name: "key"},
},
Type: cty.String,
Description: lang.Markdown("The map key (or set member) corresponding to this instance"),
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
},
DefRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
},
},
{
LocalAddr: lang.Address{
lang.RootStep{Name: "each"},
lang.AttrStep{Name: "value"},
},
Type: cty.DynamicPseudoType,
Description: lang.Markdown("The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
},
DefRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
},
},
},
`resource "aws_instance" "foo" {
for_each = {
a_group = "eastus"
Expand Down Expand Up @@ -924,7 +998,7 @@ foo {
},
{
Label: "each.value",
Detail: "any type",
Detail: "dynamic",
Kind: lang.TraversalCandidateKind,
Description: lang.MarkupContent{
Value: "The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)",
Expand Down
56 changes: 18 additions & 38 deletions decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,49 +264,29 @@ func countIndexReferenceTarget(attr *hcl.Attribute, bodyRange hcl.Range) referen
}
}

func foreachEachCandidate(editRng hcl.Range) []lang.Candidate {
return []lang.Candidate{
func forEachReferenceTargets(attr *hcl.Attribute, bodyRange hcl.Range) reference.Targets {
return reference.Targets{
{
Label: "each.key",
Detail: "string",
Description: lang.MarkupContent{
Value: "The map key (or set member) corresponding to this instance",
Kind: lang.MarkdownKind,
},
Kind: lang.TraversalCandidateKind,
TextEdit: lang.TextEdit{
NewText: "each.key",
Snippet: "each.key",
Range: editRng,
LocalAddr: lang.Address{
lang.RootStep{Name: "each"},
lang.AttrStep{Name: "key"},
},
TargetableFromRangePtr: bodyRange.Ptr(),
Type: cty.String,
Description: lang.Markdown("The map key (or set member) corresponding to this instance"),
RangePtr: attr.Range.Ptr(),
DefRangePtr: attr.NameRange.Ptr(),
},
{
Label: "each.value",
Detail: "any type",
Description: lang.MarkupContent{
Value: "The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)",
Kind: lang.MarkdownKind,
},
Kind: lang.TraversalCandidateKind,
TextEdit: lang.TextEdit{
NewText: "each.value",
Snippet: "each.value",
Range: editRng,
LocalAddr: lang.Address{
lang.RootStep{Name: "each"},
lang.AttrStep{Name: "value"},
},
TargetableFromRangePtr: bodyRange.Ptr(),
Type: cty.DynamicPseudoType,
Description: lang.Markdown("The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
RangePtr: attr.Range.Ptr(),
DefRangePtr: attr.NameRange.Ptr(),
},
}
}

func eachKeyHoverData(rng hcl.Range) *lang.HoverData {
return &lang.HoverData{
Content: lang.Markdown("`each.key` _string_\n\nThe map key (or set member) corresponding to this instance"),
Range: rng,
}
}

func eachValueHoverData(rng hcl.Range) *lang.HoverData {
return &lang.HoverData{
Content: lang.Markdown("`each.value` _any type_\n\nThe map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
Range: rng,
}
}
4 changes: 0 additions & 4 deletions decoder/expression_candidates.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,6 @@ func (d *PathDecoder) constraintToCandidates(ctx context.Context, constraint sch
},
})
case schema.TraversalExpr:
if schema.ActiveForEachFromContext(ctx) && attr.Name != "for_each" {
candidates = append(candidates, foreachEachCandidate(editRng)...)
}

candidates = append(candidates, d.candidatesForTraversalConstraint(ctx, c, outerBodyRng, prefixRng, editRng)...)
case schema.TupleConsExpr:
candidates = append(candidates, lang.Candidate{
Expand Down
14 changes: 0 additions & 14 deletions decoder/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,20 +264,6 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression,
}, nil
}

address, err := lang.TraversalToAddress(e.AsTraversal())
if err != nil {
return nil, err
}

eachKeyAddr := lang.Address{lang.RootStep{Name: "each"}, lang.AttrStep{Name: "key"}}
eachValueAddr := lang.Address{lang.RootStep{Name: "each"}, lang.AttrStep{Name: "value"}}

if address.Equals(eachKeyAddr) && schema.ActiveForEachFromContext(ctx) {
return eachKeyHoverData(expr.Range()), nil
} else if address.Equals(eachValueAddr) && schema.ActiveForEachFromContext(ctx) {
return eachValueHoverData(expr.Range()), nil
}

tes, ok := constraints.TraversalExprs()
if ok {
content, err := d.hoverContentForTraversalExpr(ctx, e.AsTraversal(), tes, pos)
Expand Down
4 changes: 2 additions & 2 deletions decoder/hover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) {
`,
hcl.Pos{Line: 2, Column: 8, Byte: 30},
&lang.HoverData{
Content: lang.Markdown("`each.key` _string_\n\nThe map key (or set member) corresponding to this instance"),
Content: lang.Markdown("`each.key`\n_string_\n\nThe map key (or set member) corresponding to this instance"),
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 8, Byte: 29},
Expand Down Expand Up @@ -1356,7 +1356,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) {
`,
hcl.Pos{Line: 2, Column: 8, Byte: 30},
&lang.HoverData{
Content: lang.Markdown("`each.value` _any type_\n\nThe map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
Content: lang.Markdown("`each.value`\n_dynamic_\n\nThe map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 8, Byte: 29},
Expand Down
4 changes: 4 additions & 0 deletions decoder/reference_targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ func (d *PathDecoder) decodeReferenceTargetsForBody(body hcl.Body, parentBlock *
refs = append(refs, countIndexReferenceTarget(attr, *content.RangePtr))
continue
}
if bodySchema.Extensions.ForEach && attr.Name == "for_each" && content.RangePtr != nil {
refs = append(refs, forEachReferenceTargets(attr, *content.RangePtr)...)
continue
}
}
attrSchema, ok := bodySchema.Attributes[attr.Name]
if !ok {
Expand Down

0 comments on commit cb106f5

Please sign in to comment.