Skip to content

Commit

Permalink
Use local ref. targets for count.index (#160)
Browse files Browse the repository at this point in the history
* Add RangePtr to body content

* Use local ref. targets for count.index
  • Loading branch information
radeksimko authored Nov 22, 2022
1 parent 0f2e32b commit f48e63d
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 50 deletions.
52 changes: 48 additions & 4 deletions decoder/body_extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestCompletionAtPos_BodySchema_Extensions(t *testing.T) {
{
Label: "count",
Description: lang.MarkupContent{
Value: "The distinct index number (starting with 0) corresponding to the instance",
Value: "Total number of instances of this block.\n\n**Note**: A given block cannot use both `count` and `for_each`.",
Kind: lang.MarkdownKind,
},
Detail: "optional, number",
Expand Down Expand Up @@ -136,7 +136,7 @@ func TestCompletionAtPos_BodySchema_Extensions(t *testing.T) {
{
Label: "count",
Description: lang.MarkupContent{
Value: "The distinct index number (starting with 0) corresponding to the instance",
Value: "Total number of instances of this block.\n\n**Note**: A given block cannot use both `count` and `for_each`.",
Kind: lang.MarkdownKind,
},
Detail: "optional, number",
Expand Down Expand Up @@ -289,7 +289,16 @@ func TestCompletionAtPos_BodySchema_Extensions(t *testing.T) {
},
},
},
reference.Targets{},
reference.Targets{
{
LocalAddr: lang.Address{
lang.RootStep{Name: "count"},
lang.AttrStep{Name: "index"},
},
Type: cty.Number,
Description: lang.PlainText("The distinct index number (starting with 0) corresponding to the instance"),
},
},
`resource "aws_instance" "foo" {
count = 4
cpu_count =
Expand Down Expand Up @@ -440,7 +449,42 @@ func TestCompletionAtPos_BodySchema_Extensions(t *testing.T) {
},
},
},
reference.Targets{},
reference.Targets{
{
LocalAddr: lang.Address{
lang.RootStep{Name: "count"},
lang.AttrStep{Name: "index"},
},
Type: cty.Number,
Description: lang.PlainText("The distinct index number (starting with 0) corresponding to the instance"),
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Line: 2,
Column: 3,
Byte: 34,
},
End: hcl.Pos{
Line: 2,
Column: 12,
Byte: 43,
},
},
DefRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{
Line: 2,
Column: 3,
Byte: 34,
},
End: hcl.Pos{
Line: 2,
Column: 8,
Byte: 39,
},
},
},
},
`resource "aws_instance" "foo" {
count = 4
foo {
Expand Down
34 changes: 16 additions & 18 deletions decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"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 @@ -104,6 +105,7 @@ type blockContent struct {
type bodyContent struct {
Attributes hcl.Attributes
Blocks []*blockContent
RangePtr *hcl.Range
}

// decodeBody produces content of either HCL or JSON body
Expand Down Expand Up @@ -131,6 +133,8 @@ func decodeBody(body hcl.Body, bodySchema *schema.BodySchema) bodyContent {
})
}

content.RangePtr = hclBody.Range().Ptr()

return content
}

Expand Down Expand Up @@ -177,7 +181,8 @@ func countAttributeSchema() *schema.AttributeSchema {
schema.TraversalExpr{OfType: cty.Number},
schema.LiteralTypeExpr{Type: cty.Number},
},
Description: lang.Markdown("The distinct index number (starting with 0) corresponding to the instance"),
Description: lang.Markdown("Total number of instances of this block.\n\n" +
"**Note**: A given block cannot use both `count` and `for_each`."),
}
}

Expand Down Expand Up @@ -245,24 +250,17 @@ func dynamicBlockSchema() *schema.BlockSchema {
}
}

func countIndexHoverData(rng hcl.Range) *lang.HoverData {
return &lang.HoverData{
Content: lang.Markdown("`count.index` _number_\n\nThe distinct index number (starting with 0) corresponding to the instance"),
Range: rng,
}
}

func countIndexCandidate(editRng hcl.Range) lang.Candidate {
return lang.Candidate{
Label: "count.index",
Detail: "number",
Description: lang.PlainText("The distinct index number (starting with 0) corresponding to the instance"),
Kind: lang.TraversalCandidateKind,
TextEdit: lang.TextEdit{
NewText: "count.index",
Snippet: "count.index",
Range: editRng,
func countIndexReferenceTarget(attr *hcl.Attribute, bodyRange hcl.Range) reference.Target {
return reference.Target{
LocalAddr: lang.Address{
lang.RootStep{Name: "count"},
lang.AttrStep{Name: "index"},
},
TargetableFromRangePtr: bodyRange.Ptr(),
Type: cty.Number,
Description: lang.Markdown("The distinct index number (starting with 0) corresponding to the instance"),
RangePtr: attr.Range.Ptr(),
DefRangePtr: attr.NameRange.Ptr(),
}
}

Expand Down
3 changes: 0 additions & 3 deletions decoder/expression_candidates.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,6 @@ func (d *PathDecoder) constraintToCandidates(ctx context.Context, constraint sch
},
})
case schema.TraversalExpr:
if schema.ActiveCountFromContext(ctx) && attr.Name != "count" {
candidates = append(candidates, countIndexCandidate(editRng))
}
if schema.ActiveForEachFromContext(ctx) && attr.Name != "for_each" {
candidates = append(candidates, foreachEachCandidate(editRng)...)
}
Expand Down
5 changes: 1 addition & 4 deletions decoder/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,10 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression,
return nil, err
}

countIndexAddr := lang.Address{lang.RootStep{Name: "count"}, lang.AttrStep{Name: "index"}}
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(countIndexAddr) && schema.ActiveCountFromContext(ctx) {
return countIndexHoverData(expr.Range()), nil
} else if address.Equals(eachKeyAddr) && schema.ActiveForEachFromContext(ctx) {
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
Expand Down
4 changes: 2 additions & 2 deletions decoder/hover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) {
`,
hcl.Pos{Line: 2, Column: 5, Byte: 24},
&lang.HoverData{
Content: lang.Markdown("**count** _optional, number_\n\nThe distinct index number (starting with 0) corresponding to the instance"),
Content: lang.Markdown("**count** _optional, number_\n\nTotal number of instances of this block.\n\n**Note**: A given block cannot use both `count` and `for_each`."),
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 3, Byte: 24},
Expand Down Expand Up @@ -1034,7 +1034,7 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) {
`,
hcl.Pos{Line: 3, Column: 15, Byte: 48},
&lang.HoverData{
Content: lang.Markdown("`count.index` _number_\n\nThe distinct index number (starting with 0) corresponding to the instance"),
Content: lang.Markdown("`count.index`\n_number_\n\nThe distinct index number (starting with 0) corresponding to the instance"),
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 3, Column: 11, Byte: 44},
Expand Down
6 changes: 6 additions & 0 deletions decoder/reference_targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ func (d *PathDecoder) decodeReferenceTargetsForBody(body hcl.Body, parentBlock *
content := decodeBody(body, bodySchema)

for _, attr := range content.Attributes {
if bodySchema.Extensions != nil {
if bodySchema.Extensions.Count && attr.Name == "count" && content.RangePtr != nil {
refs = append(refs, countIndexReferenceTarget(attr, *content.RangePtr))
continue
}
}
attrSchema, ok := bodySchema.Attributes[attr.Name]
if !ok {
if bodySchema.AnyAttribute == nil {
Expand Down
11 changes: 0 additions & 11 deletions decoder/semantic_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,6 @@ func (d *PathDecoder) tokensForExpression(ctx context.Context, expr hclsyntax.Ex
return tokens
}

countAvailable := schema.ActiveCountFromContext(ctx)
countIndexAttr := lang.Address{
lang.RootStep{Name: "count"}, lang.AttrStep{Name: "index"},
}

if address.Equals(countIndexAttr) && countAvailable {
tokens = append(tokens, semanticTokensForTraversalExpression(eType.AsTraversal())...)

return tokens
}

foreachAvailable := schema.ActiveForEachFromContext(ctx)
eachKeyAddress := lang.Address{
lang.RootStep{Name: "each"}, lang.AttrStep{Name: "key"},
Expand Down
18 changes: 10 additions & 8 deletions decoder/semantic_tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ resource "vault_auth_backend" "blah" {
}
}

func TestDecoder_SemanticTokensInFile_extensions(t *testing.T) {
func TestDecoder_SemanticTokensInFile_extensions_basic(t *testing.T) {
bodySchema := &schema.BodySchema{
Blocks: map[string]*schema.BlockSchema{
"resource": {
Expand Down Expand Up @@ -1079,8 +1079,8 @@ resource "aws_instance" "app_server" {
},
End: hcl.Pos{
Line: 4,
Column: 32,
Byte: 92,
Column: 31,
Byte: 91,
},
},
},
Expand Down Expand Up @@ -1329,8 +1329,8 @@ resource "aws_instance" "app_server" {
},
End: hcl.Pos{
Line: 4,
Column: 32,
Byte: 92,
Column: 31,
Byte: 91,
},
},
},
Expand Down Expand Up @@ -1492,7 +1492,9 @@ func TestDecoder_SemanticTokensInFile_extensions_countIndexInSubBlock(t *testing
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"attr": {
Expr: schema.LiteralTypeOnly(cty.Number),
Expr: schema.ExprConstraints{
schema.TraversalExpr{OfType: cty.Number},
},
},
},
},
Expand Down Expand Up @@ -1726,8 +1728,8 @@ resource "foobar" "name" {
},
End: hcl.Pos{
Line: 5,
Column: 22,
Byte: 69,
Column: 21,
Byte: 68,
},
},
},
Expand Down

0 comments on commit f48e63d

Please sign in to comment.