Skip to content

Commit d770b42

Browse files
authored
fix: filtering of self references for cross-file references (#105)
* add (failing) test * fix: filtering of self references for cross-file references
1 parent b2b314e commit d770b42

File tree

2 files changed

+180
-1
lines changed

2 files changed

+180
-1
lines changed

decoder/expression_candidates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ func (d *PathDecoder) candidatesForTraversalConstraint(tc schema.TraversalExpr,
331331

332332
d.pathCtx.ReferenceTargets.MatchWalk(tc, string(prefix), func(ref reference.Target) error {
333333
// avoid suggesting references to block's own fields from within (for now)
334-
if ref.RangePtr != nil &&
334+
if ref.RangePtr != nil && outerBodyRng.Filename == ref.RangePtr.Filename &&
335335
(outerBodyRng.ContainsPos(ref.RangePtr.Start) ||
336336
posEqual(outerBodyRng.End, ref.RangePtr.End)) {
337337
return nil

decoder/expression_candidates_test.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/hashicorp/hcl-lang/schema"
1111
"github.com/hashicorp/hcl/v2"
1212
"github.com/hashicorp/hcl/v2/hclsyntax"
13+
"github.com/zclconf/go-cty-debug/ctydebug"
1314
"github.com/zclconf/go-cty/cty"
1415
)
1516

@@ -2566,3 +2567,181 @@ another_block "meh" {
25662567
})
25672568
}
25682569
}
2570+
2571+
func TestDecoder_CandidateAtPos_expressions_crossFileTraversal(t *testing.T) {
2572+
f1, _ := hclsyntax.ParseConfig([]byte(`variable "aaa" {}
2573+
variable "bbb" {}
2574+
variable "ccc" {}
2575+
`), "test1.tf", hcl.InitialPos)
2576+
f2, _ := hclsyntax.ParseConfig([]byte(`value =
2577+
`), "test2.tf", hcl.InitialPos)
2578+
2579+
bodySchema := &schema.BodySchema{
2580+
Attributes: map[string]*schema.AttributeSchema{
2581+
"value": {
2582+
IsOptional: true,
2583+
Expr: schema.ExprConstraints{
2584+
schema.TraversalExpr{
2585+
OfScopeId: lang.ScopeId("variable"),
2586+
OfType: cty.DynamicPseudoType,
2587+
},
2588+
},
2589+
},
2590+
},
2591+
Blocks: map[string]*schema.BlockSchema{
2592+
"variable": {
2593+
Labels: []*schema.LabelSchema{
2594+
{Name: "name"},
2595+
},
2596+
Address: &schema.BlockAddrSchema{
2597+
Steps: []schema.AddrStep{
2598+
schema.StaticStep{Name: "var"},
2599+
schema.LabelStep{Index: 0},
2600+
},
2601+
FriendlyName: "variable",
2602+
ScopeId: lang.ScopeId("variable"),
2603+
AsTypeOf: &schema.BlockAsTypeOf{
2604+
AttributeExpr: "type",
2605+
AttributeValue: "default",
2606+
},
2607+
},
2608+
},
2609+
},
2610+
}
2611+
2612+
testDir := t.TempDir()
2613+
dirReader := &testPathReader{
2614+
paths: map[string]*PathContext{
2615+
testDir: {
2616+
Schema: bodySchema,
2617+
Files: map[string]*hcl.File{
2618+
"test1.tf": f1,
2619+
"test2.tf": f2,
2620+
},
2621+
ReferenceTargets: reference.Targets{},
2622+
},
2623+
},
2624+
}
2625+
decoder := NewDecoder(dirReader)
2626+
d, err := decoder.Path(lang.Path{Path: testDir})
2627+
if err != nil {
2628+
t.Fatal(err)
2629+
}
2630+
refTargets, err := d.CollectReferenceTargets()
2631+
if err != nil {
2632+
t.Fatal(err)
2633+
}
2634+
2635+
expectedTargets := reference.Targets{
2636+
{
2637+
Addr: lang.Address{lang.RootStep{Name: "var"}, lang.AttrStep{Name: "aaa"}},
2638+
ScopeId: lang.ScopeId("variable"),
2639+
RangePtr: &hcl.Range{
2640+
Filename: "test1.tf",
2641+
Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
2642+
End: hcl.Pos{Line: 1, Column: 18, Byte: 17},
2643+
},
2644+
DefRangePtr: &hcl.Range{
2645+
Filename: "test1.tf",
2646+
Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
2647+
End: hcl.Pos{Line: 1, Column: 15, Byte: 14},
2648+
},
2649+
Type: cty.DynamicPseudoType,
2650+
},
2651+
{
2652+
Addr: lang.Address{lang.RootStep{Name: "var"}, lang.AttrStep{Name: "bbb"}},
2653+
ScopeId: lang.ScopeId("variable"),
2654+
RangePtr: &hcl.Range{
2655+
Filename: "test1.tf",
2656+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 18},
2657+
End: hcl.Pos{Line: 2, Column: 18, Byte: 35},
2658+
},
2659+
DefRangePtr: &hcl.Range{
2660+
Filename: "test1.tf",
2661+
Start: hcl.Pos{Line: 2, Column: 1, Byte: 18},
2662+
End: hcl.Pos{Line: 2, Column: 15, Byte: 32},
2663+
},
2664+
Type: cty.DynamicPseudoType,
2665+
},
2666+
{
2667+
Addr: lang.Address{lang.RootStep{Name: "var"}, lang.AttrStep{Name: "ccc"}},
2668+
ScopeId: lang.ScopeId("variable"),
2669+
RangePtr: &hcl.Range{
2670+
Filename: "test1.tf",
2671+
Start: hcl.Pos{Line: 3, Column: 1, Byte: 36},
2672+
End: hcl.Pos{Line: 3, Column: 18, Byte: 53},
2673+
},
2674+
DefRangePtr: &hcl.Range{
2675+
Filename: "test1.tf",
2676+
Start: hcl.Pos{Line: 3, Column: 1, Byte: 36},
2677+
End: hcl.Pos{Line: 3, Column: 15, Byte: 50},
2678+
},
2679+
Type: cty.DynamicPseudoType,
2680+
},
2681+
}
2682+
if diff := cmp.Diff(expectedTargets, refTargets, ctydebug.CmpOptions); diff != "" {
2683+
t.Fatalf("unexpected targets: %s", diff)
2684+
}
2685+
2686+
dirReader.paths[testDir].ReferenceTargets = refTargets
2687+
2688+
candidates, err := d.CandidatesAtPos("test2.tf", hcl.Pos{
2689+
Line: 1,
2690+
Column: 9,
2691+
Byte: 8,
2692+
})
2693+
if err != nil {
2694+
t.Fatal(err)
2695+
}
2696+
2697+
expectedCandidates := lang.Candidates{
2698+
List: []lang.Candidate{
2699+
{
2700+
Label: "var.aaa",
2701+
Detail: "dynamic",
2702+
TextEdit: lang.TextEdit{
2703+
Range: hcl.Range{
2704+
Filename: "test2.tf",
2705+
Start: hcl.Pos{Line: 1, Column: 9, Byte: 8},
2706+
End: hcl.Pos{Line: 1, Column: 9, Byte: 8},
2707+
},
2708+
NewText: "var.aaa",
2709+
Snippet: "var.aaa",
2710+
},
2711+
Kind: lang.TraversalCandidateKind,
2712+
},
2713+
{
2714+
Label: "var.bbb",
2715+
Detail: "dynamic",
2716+
TextEdit: lang.TextEdit{
2717+
Range: hcl.Range{
2718+
Filename: "test2.tf",
2719+
Start: hcl.Pos{Line: 1, Column: 9, Byte: 8},
2720+
End: hcl.Pos{Line: 1, Column: 9, Byte: 8},
2721+
},
2722+
NewText: "var.bbb",
2723+
Snippet: "var.bbb",
2724+
},
2725+
Kind: lang.TraversalCandidateKind,
2726+
},
2727+
{
2728+
Label: "var.ccc",
2729+
Detail: "dynamic",
2730+
TextEdit: lang.TextEdit{
2731+
Range: hcl.Range{
2732+
Filename: "test2.tf",
2733+
Start: hcl.Pos{Line: 1, Column: 9, Byte: 8},
2734+
End: hcl.Pos{Line: 1, Column: 9, Byte: 8},
2735+
},
2736+
NewText: "var.ccc",
2737+
Snippet: "var.ccc",
2738+
},
2739+
Kind: lang.TraversalCandidateKind,
2740+
},
2741+
},
2742+
IsComplete: true,
2743+
}
2744+
if diff := cmp.Diff(expectedCandidates, candidates); diff != "" {
2745+
t.Fatalf("unexpected candidates: %s", diff)
2746+
}
2747+
}

0 commit comments

Comments
 (0)