Skip to content

Commit 4ad2560

Browse files
authored
Use local ref. targets for each.* references (#162)
1 parent f48e63d commit 4ad2560

File tree

6 files changed

+104
-64
lines changed

6 files changed

+104
-64
lines changed

decoder/body_extensions_test.go

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -693,15 +693,52 @@ variable "test" {
693693
},
694694
},
695695
},
696-
reference.Targets{},
696+
reference.Targets{
697+
{
698+
LocalAddr: lang.Address{
699+
lang.RootStep{Name: "each"},
700+
lang.AttrStep{Name: "key"},
701+
},
702+
Type: cty.String,
703+
Description: lang.Markdown("The map key (or set member) corresponding to this instance"),
704+
RangePtr: &hcl.Range{
705+
Filename: "test.tf",
706+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
707+
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
708+
},
709+
DefRangePtr: &hcl.Range{
710+
Filename: "test.tf",
711+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
712+
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
713+
},
714+
},
715+
{
716+
LocalAddr: lang.Address{
717+
lang.RootStep{Name: "each"},
718+
lang.AttrStep{Name: "value"},
719+
},
720+
Type: cty.DynamicPseudoType,
721+
Description: lang.Markdown("The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
722+
RangePtr: &hcl.Range{
723+
Filename: "test.tf",
724+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
725+
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
726+
},
727+
DefRangePtr: &hcl.Range{
728+
Filename: "test.tf",
729+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
730+
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
731+
},
732+
},
733+
},
697734
`resource "aws_instance" "foo" {
698735
for_each = {
699736
a_group = "eastus"
700737
another_group = "westus2"
701738
}
702739
thing =
703740
}`,
704-
hcl.Pos{Line: 6, Column: 8, Byte: 101},
741+
hcl.Pos{Line: 6, Column: 9, Byte: 102},
705742
lang.CompleteCandidates([]lang.Candidate{
706743
{
707744
Label: "each.key",
@@ -723,7 +760,7 @@ thing =
723760
},
724761
{
725762
Label: "each.value",
726-
Detail: "any type",
763+
Detail: "dynamic",
727764
Kind: lang.TraversalCandidateKind,
728765
Description: lang.MarkupContent{
729766
Value: "The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)",
@@ -880,7 +917,7 @@ for_each = {
880917
IsOptional: true,
881918
Expr: schema.ExprConstraints{
882919
schema.TraversalExpr{
883-
OfType: cty.Number,
920+
OfType: cty.DynamicPseudoType,
884921
},
885922
},
886923
},
@@ -892,7 +929,44 @@ for_each = {
892929
},
893930
},
894931
},
895-
reference.Targets{},
932+
reference.Targets{
933+
{
934+
LocalAddr: lang.Address{
935+
lang.RootStep{Name: "each"},
936+
lang.AttrStep{Name: "key"},
937+
},
938+
Type: cty.String,
939+
Description: lang.Markdown("The map key (or set member) corresponding to this instance"),
940+
RangePtr: &hcl.Range{
941+
Filename: "test.tf",
942+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
943+
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
944+
},
945+
DefRangePtr: &hcl.Range{
946+
Filename: "test.tf",
947+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
948+
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
949+
},
950+
},
951+
{
952+
LocalAddr: lang.Address{
953+
lang.RootStep{Name: "each"},
954+
lang.AttrStep{Name: "value"},
955+
},
956+
Type: cty.DynamicPseudoType,
957+
Description: lang.Markdown("The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
958+
RangePtr: &hcl.Range{
959+
Filename: "test.tf",
960+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
961+
End: hcl.Pos{Line: 5, Column: 2, Byte: 93},
962+
},
963+
DefRangePtr: &hcl.Range{
964+
Filename: "test.tf",
965+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 32},
966+
End: hcl.Pos{Line: 2, Column: 9, Byte: 40},
967+
},
968+
},
969+
},
896970
`resource "aws_instance" "foo" {
897971
for_each = {
898972
a_group = "eastus"
@@ -924,7 +998,7 @@ foo {
924998
},
925999
{
9261000
Label: "each.value",
927-
Detail: "any type",
1001+
Detail: "dynamic",
9281002
Kind: lang.TraversalCandidateKind,
9291003
Description: lang.MarkupContent{
9301004
Value: "The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)",

decoder/decoder.go

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -264,49 +264,29 @@ func countIndexReferenceTarget(attr *hcl.Attribute, bodyRange hcl.Range) referen
264264
}
265265
}
266266

267-
func foreachEachCandidate(editRng hcl.Range) []lang.Candidate {
268-
return []lang.Candidate{
267+
func forEachReferenceTargets(attr *hcl.Attribute, bodyRange hcl.Range) reference.Targets {
268+
return reference.Targets{
269269
{
270-
Label: "each.key",
271-
Detail: "string",
272-
Description: lang.MarkupContent{
273-
Value: "The map key (or set member) corresponding to this instance",
274-
Kind: lang.MarkdownKind,
275-
},
276-
Kind: lang.TraversalCandidateKind,
277-
TextEdit: lang.TextEdit{
278-
NewText: "each.key",
279-
Snippet: "each.key",
280-
Range: editRng,
270+
LocalAddr: lang.Address{
271+
lang.RootStep{Name: "each"},
272+
lang.AttrStep{Name: "key"},
281273
},
274+
TargetableFromRangePtr: bodyRange.Ptr(),
275+
Type: cty.String,
276+
Description: lang.Markdown("The map key (or set member) corresponding to this instance"),
277+
RangePtr: attr.Range.Ptr(),
278+
DefRangePtr: attr.NameRange.Ptr(),
282279
},
283280
{
284-
Label: "each.value",
285-
Detail: "any type",
286-
Description: lang.MarkupContent{
287-
Value: "The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)",
288-
Kind: lang.MarkdownKind,
289-
},
290-
Kind: lang.TraversalCandidateKind,
291-
TextEdit: lang.TextEdit{
292-
NewText: "each.value",
293-
Snippet: "each.value",
294-
Range: editRng,
281+
LocalAddr: lang.Address{
282+
lang.RootStep{Name: "each"},
283+
lang.AttrStep{Name: "value"},
295284
},
285+
TargetableFromRangePtr: bodyRange.Ptr(),
286+
Type: cty.DynamicPseudoType,
287+
Description: lang.Markdown("The map value corresponding to this instance. (If a set was provided, this is the same as `each.key`.)"),
288+
RangePtr: attr.Range.Ptr(),
289+
DefRangePtr: attr.NameRange.Ptr(),
296290
},
297291
}
298292
}
299-
300-
func eachKeyHoverData(rng hcl.Range) *lang.HoverData {
301-
return &lang.HoverData{
302-
Content: lang.Markdown("`each.key` _string_\n\nThe map key (or set member) corresponding to this instance"),
303-
Range: rng,
304-
}
305-
}
306-
307-
func eachValueHoverData(rng hcl.Range) *lang.HoverData {
308-
return &lang.HoverData{
309-
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`.)"),
310-
Range: rng,
311-
}
312-
}

decoder/expression_candidates.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,6 @@ func (d *PathDecoder) constraintToCandidates(ctx context.Context, constraint sch
328328
},
329329
})
330330
case schema.TraversalExpr:
331-
if schema.ActiveForEachFromContext(ctx) && attr.Name != "for_each" {
332-
candidates = append(candidates, foreachEachCandidate(editRng)...)
333-
}
334-
335331
candidates = append(candidates, d.candidatesForTraversalConstraint(ctx, c, outerBodyRng, prefixRng, editRng)...)
336332
case schema.TupleConsExpr:
337333
candidates = append(candidates, lang.Candidate{

decoder/hover.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -264,20 +264,6 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression,
264264
}, nil
265265
}
266266

267-
address, err := lang.TraversalToAddress(e.AsTraversal())
268-
if err != nil {
269-
return nil, err
270-
}
271-
272-
eachKeyAddr := lang.Address{lang.RootStep{Name: "each"}, lang.AttrStep{Name: "key"}}
273-
eachValueAddr := lang.Address{lang.RootStep{Name: "each"}, lang.AttrStep{Name: "value"}}
274-
275-
if address.Equals(eachKeyAddr) && schema.ActiveForEachFromContext(ctx) {
276-
return eachKeyHoverData(expr.Range()), nil
277-
} else if address.Equals(eachValueAddr) && schema.ActiveForEachFromContext(ctx) {
278-
return eachValueHoverData(expr.Range()), nil
279-
}
280-
281267
tes, ok := constraints.TraversalExprs()
282268
if ok {
283269
content, err := d.hoverContentForTraversalExpr(ctx, e.AsTraversal(), tes, pos)

decoder/hover_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) {
12521252
`,
12531253
hcl.Pos{Line: 2, Column: 8, Byte: 30},
12541254
&lang.HoverData{
1255-
Content: lang.Markdown("`each.key` _string_\n\nThe map key (or set member) corresponding to this instance"),
1255+
Content: lang.Markdown("`each.key`\n_string_\n\nThe map key (or set member) corresponding to this instance"),
12561256
Range: hcl.Range{
12571257
Filename: "test.tf",
12581258
Start: hcl.Pos{Line: 2, Column: 8, Byte: 29},
@@ -1356,7 +1356,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) {
13561356
`,
13571357
hcl.Pos{Line: 2, Column: 8, Byte: 30},
13581358
&lang.HoverData{
1359-
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`.)"),
1359+
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`.)"),
13601360
Range: hcl.Range{
13611361
Filename: "test.tf",
13621362
Start: hcl.Pos{Line: 2, Column: 8, Byte: 29},

decoder/reference_targets.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ func (d *PathDecoder) decodeReferenceTargetsForBody(body hcl.Body, parentBlock *
112112
refs = append(refs, countIndexReferenceTarget(attr, *content.RangePtr))
113113
continue
114114
}
115+
if bodySchema.Extensions.ForEach && attr.Name == "for_each" && content.RangePtr != nil {
116+
refs = append(refs, forEachReferenceTargets(attr, *content.RangePtr)...)
117+
continue
118+
}
115119
}
116120
attrSchema, ok := bodySchema.Attributes[attr.Name]
117121
if !ok {

0 commit comments

Comments
 (0)