Skip to content

Commit 056ce5c

Browse files
authored
tflint: Remove duplicate variable references (#1072)
1 parent 5e028e7 commit 056ce5c

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

tflint/runner.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,17 +370,17 @@ func prepareVariableValues(config *configs.Config, variables ...terraform.InputV
370370
return variableValues
371371
}
372372

373-
func listVarRefs(expr hcl.Expression) []addrs.InputVariable {
373+
func listVarRefs(expr hcl.Expression) map[string]addrs.InputVariable {
374374
refs, diags := lang.ReferencesInExpr(expr)
375375
if diags.HasErrors() {
376376
// Maybe this is bug
377377
panic(diags.Err())
378378
}
379379

380-
ret := []addrs.InputVariable{}
380+
ret := map[string]addrs.InputVariable{}
381381
for _, ref := range refs {
382382
if varRef, ok := ref.Subject.(addrs.InputVariable); ok {
383-
ret = append(ret, varRef)
383+
ret[varRef.String()] = varRef
384384
}
385385
}
386386

tflint/runner_test.go

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/google/go-cmp/cmp/cmpopts"
1010
hcl "github.com/hashicorp/hcl/v2"
1111
"github.com/hashicorp/hcl/v2/hclsyntax"
12+
"github.com/hashicorp/terraform/addrs"
1213
"github.com/hashicorp/terraform/configs"
1314
"github.com/zclconf/go-cty/cty"
1415
)
@@ -206,7 +207,10 @@ func Test_NewModuleRunners_modVars(t *testing.T) {
206207
},
207208
},
208209
}
209-
opts = []cmp.Option{cmpopts.IgnoreFields(hcl.Pos{}, "Byte")}
210+
opts = []cmp.Option{
211+
cmpopts.IgnoreFields(hcl.Pos{}, "Byte"),
212+
cmpopts.SortSlices(func(x, y *moduleVariable) bool { return x.DeclRange.Start.Line > y.DeclRange.Start.Line }),
213+
}
210214
if !cmp.Equal(expected, grandchild.modVars, opts...) {
211215
t.Fatalf("`%s` module variables are unmatched: Diff=%s", grandchild.TFConfig.Path.String(), cmp.Diff(expected, grandchild.modVars, opts...))
212216
}
@@ -645,3 +649,61 @@ func Test_DecodeRuleConfig_emptyBody(t *testing.T) {
645649
t.Fatalf("Expected error message is %s, but got %s", expected, err.Error())
646650
}
647651
}
652+
653+
func Test_listVarRefs(t *testing.T) {
654+
cases := []struct {
655+
Name string
656+
Expr string
657+
Expected map[string]addrs.InputVariable
658+
}{
659+
{
660+
Name: "literal",
661+
Expr: "1",
662+
Expected: map[string]addrs.InputVariable{},
663+
},
664+
{
665+
Name: "input variable",
666+
Expr: "var.foo",
667+
Expected: map[string]addrs.InputVariable{
668+
"var.foo": {Name: "foo"},
669+
},
670+
},
671+
{
672+
Name: "local variable",
673+
Expr: "local.bar",
674+
Expected: map[string]addrs.InputVariable{},
675+
},
676+
{
677+
Name: "multiple input variables",
678+
Expr: `format("Hello, %s %s!", var.first_name, var.last_name)`,
679+
Expected: map[string]addrs.InputVariable{
680+
"var.first_name": {Name: "first_name"},
681+
"var.last_name": {Name: "last_name"},
682+
},
683+
},
684+
{
685+
Name: "map input variable",
686+
Expr: `{
687+
name = var.tags["name"]
688+
env = var.tags["env"]
689+
}`,
690+
Expected: map[string]addrs.InputVariable{
691+
"var.tags": {Name: "tags"},
692+
},
693+
},
694+
}
695+
696+
for _, tc := range cases {
697+
expr, diags := hclsyntax.ParseExpression([]byte(tc.Expr), "template.tf", hcl.InitialPos)
698+
if diags.HasErrors() {
699+
t.Fatal(diags)
700+
}
701+
702+
refs := listVarRefs(expr)
703+
704+
opt := cmpopts.IgnoreUnexported(addrs.InputVariable{})
705+
if !cmp.Equal(tc.Expected, refs, opt) {
706+
t.Fatalf("%s: Diff=%s", tc.Name, cmp.Diff(tc.Expected, refs, opt))
707+
}
708+
}
709+
}

0 commit comments

Comments
 (0)