Skip to content

Commit

Permalink
decoder/reference: Recognize self refs in completion + hover + go-to-*
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Nov 24, 2022
1 parent a9ad708 commit 3b1b516
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 1 deletion.
3 changes: 3 additions & 0 deletions decoder/candidates.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func (d *PathDecoder) candidatesAtPos(ctx context.Context, body *hclsyntax.Body,

for _, attr := range body.Attributes {
if d.isPosInsideAttrExpr(attr, pos) {
if bodySchema.Extensions != nil && bodySchema.Extensions.SelfRefs {
ctx = schema.WithActiveSelfRefs(ctx)
}
if bodySchema.Extensions != nil && bodySchema.Extensions.Count && attr.Name == "count" {
return d.attrValueCandidatesAtPos(ctx, attr, countAttributeSchema(), outerBodyRng, pos)
}
Expand Down
4 changes: 4 additions & 0 deletions decoder/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, body
for name, attr := range body.Attributes {
if attr.Range().ContainsPos(pos) {
var aSchema *schema.AttributeSchema
if bodySchema.Extensions != nil && bodySchema.Extensions.SelfRefs {
ctx = schema.WithActiveSelfRefs(ctx)
}

if bodySchema.Extensions != nil && bodySchema.Extensions.Count && name == "count" {
aSchema = countAttributeSchema()
} else if bodySchema.Extensions != nil && bodySchema.Extensions.ForEach && name == "for_each" {
Expand Down
3 changes: 2 additions & 1 deletion reference/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ func copyHclRangePtr(rng *hcl.Range) *hcl.Range {
// depending on the provided context
func (r Target) Address(ctx context.Context) lang.Address {
addr := r.Addr
if len(r.LocalAddr) > 0 {
if len(r.LocalAddr) > 0 &&
(len(r.Addr) == 0 || schema.ActiveSelfRefsFromContext(ctx)) {
addr = r.LocalAddr
}

Expand Down
5 changes: 5 additions & 0 deletions reference/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func (refs Targets) MatchWalk(ctx context.Context, te schema.TraversalExpr, pref

func localTargetMatches(ctx context.Context, target Target, te schema.TraversalExpr, prefix string, outermostBodyRng, originRng hcl.Range) bool {
if len(target.LocalAddr) > 0 && strings.HasPrefix(target.LocalAddr.String(), prefix) {
// reject self references if not enabled
if !schema.ActiveSelfRefsFromContext(ctx) && target.LocalAddr[0].String() == "self" {
return false
}

hasNestedMatches := target.NestedTargets.containsMatch(ctx, te, prefix, outermostBodyRng, originRng)

// Avoid suggesting cyclical reference to the same attribute
Expand Down
175 changes: 175 additions & 0 deletions reference/targets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
prefix string
outermostBodyRng hcl.Range
originRng hcl.Range
activeSelfRefs bool
expectedTargets Targets
}{
{
Expand All @@ -898,6 +899,7 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
false,
Targets{},
},
{
Expand Down Expand Up @@ -928,6 +930,7 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
false,
Targets{
{
LocalAddr: lang.Address{
Expand Down Expand Up @@ -978,6 +981,7 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
Start: hcl.InitialPos,
End: hcl.InitialPos,
},
false,
Targets{
{
LocalAddr: lang.Address{
Expand Down Expand Up @@ -1044,6 +1048,7 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
Start: hcl.Pos{Line: 5, Column: 1, Byte: 25},
End: hcl.Pos{Line: 5, Column: 10, Byte: 35},
},
false,
Targets{
{
LocalAddr: lang.Address{
Expand Down Expand Up @@ -1099,6 +1104,7 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
Start: hcl.Pos{Line: 2, Column: 11, Byte: 38},
End: hcl.Pos{Line: 2, Column: 11, Byte: 38},
},
false,
Targets{},
},
{
Expand Down Expand Up @@ -1158,6 +1164,172 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
Start: hcl.Pos{Line: 2, Column: 9, Byte: 36},
End: hcl.Pos{Line: 2, Column: 9, Byte: 36},
},
true,
Targets{},
},
{
"self only matches when enabled",
Targets{
{
Addr: lang.Address{
lang.RootStep{Name: "aws_alb"},
lang.AttrStep{Name: "test"},
},
LocalAddr: lang.Address{
lang.RootStep{Name: "self"},
},
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
TargetableFromRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
NestedTargets: Targets{
{
Addr: lang.Address{
lang.RootStep{Name: "aws_alb"},
lang.AttrStep{Name: "test"},
lang.AttrStep{Name: "bar"},
},
LocalAddr: lang.Address{
lang.RootStep{Name: "self"},
lang.AttrStep{Name: "bar"},
},
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 30},
End: hcl.Pos{Line: 2, Column: 20, Byte: 35},
},
TargetableFromRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
},
},
},
},
schema.TraversalExpr{},
"",
hcl.Range{ // outermost body range
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 3, Column: 1, Byte: 37},
},
hcl.Range{ // origin range
Filename: "test.tf",
Start: hcl.Pos{Line: 3, Column: 2, Byte: 36},
End: hcl.Pos{Line: 3, Column: 2, Byte: 36},
},
true,
Targets{
{
Addr: lang.Address{
lang.RootStep{Name: "aws_alb"},
lang.AttrStep{Name: "test"},
},
LocalAddr: lang.Address{
lang.RootStep{Name: "self"},
},
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
TargetableFromRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
NestedTargets: Targets{
{
Addr: lang.Address{
lang.RootStep{Name: "aws_alb"},
lang.AttrStep{Name: "test"},
lang.AttrStep{Name: "bar"},
},
LocalAddr: lang.Address{
lang.RootStep{Name: "self"},
lang.AttrStep{Name: "bar"},
},
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 30},
End: hcl.Pos{Line: 2, Column: 20, Byte: 35},
},
TargetableFromRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
},
},
},
},
},
{
"self doesn't match when disabled",
Targets{
{
Addr: lang.Address{
lang.RootStep{Name: "aws_alb"},
lang.AttrStep{Name: "test"},
},
LocalAddr: lang.Address{
lang.RootStep{Name: "self"},
},
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
TargetableFromRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
NestedTargets: Targets{
{
Addr: lang.Address{
lang.RootStep{Name: "aws_alb"},
lang.AttrStep{Name: "test"},
lang.AttrStep{Name: "bar"},
},
LocalAddr: lang.Address{
lang.RootStep{Name: "self"},
lang.AttrStep{Name: "bar"},
},
RangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 2, Column: 1, Byte: 30},
End: hcl.Pos{Line: 2, Column: 20, Byte: 35},
},
TargetableFromRangePtr: &hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 4, Column: 1, Byte: 37},
},
},
},
},
},
schema.TraversalExpr{},
"",
hcl.Range{ // outermost body range
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 28, Byte: 27},
End: hcl.Pos{Line: 3, Column: 1, Byte: 37},
},
hcl.Range{ // origin range
Filename: "test.tf",
Start: hcl.Pos{Line: 3, Column: 2, Byte: 36},
End: hcl.Pos{Line: 3, Column: 2, Byte: 36},
},
false,
Targets{},
},
}
Expand All @@ -1166,6 +1338,9 @@ func TestTargets_MatchWalk_localRefs(t *testing.T) {
t.Run(fmt.Sprintf("%d-%s", i, tc.name), func(t *testing.T) {
targets := make(Targets, 0)
ctx := context.Background()
if tc.activeSelfRefs {
ctx = schema.WithActiveSelfRefs(ctx)
}
tc.targets.MatchWalk(ctx, tc.traversalConst, tc.prefix, tc.outermostBodyRng, tc.originRng, func(t Target) error {
targets = append(targets, t)
return nil
Expand Down
10 changes: 10 additions & 0 deletions schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ func ActiveForEachFromContext(ctx context.Context) bool {
return ctx.Value(bodyActiveForEachCtxKey{}) != nil
}

type bodyActiveSelfRefsCtxKey struct{}

func WithActiveSelfRefs(ctx context.Context) context.Context {
return context.WithValue(ctx, bodyActiveSelfRefsCtxKey{}, true)
}

func ActiveSelfRefsFromContext(ctx context.Context) bool {
return ctx.Value(bodyActiveSelfRefsCtxKey{}) != nil
}

type bodyActiveDynamicBlockCtxKey struct{}

func WithActiveDynamicBlock(ctx context.Context) context.Context {
Expand Down

0 comments on commit 3b1b516

Please sign in to comment.