4 "github.com/hashicorp/hcl2/hcl"
5 "github.com/hashicorp/terraform/addrs"
6 "github.com/hashicorp/terraform/configs/configschema"
7 "github.com/hashicorp/terraform/lang/blocktoattr"
8 "github.com/hashicorp/terraform/tfdiags"
11 // References finds all of the references in the given set of traversals,
12 // returning diagnostics if any of the traversals cannot be interpreted as a
15 // This function does not do any de-duplication of references, since references
16 // have source location information embedded in them and so any invalid
17 // references that are duplicated should have errors reported for each
20 // If the returned diagnostics contains errors then the result may be
21 // incomplete or invalid. Otherwise, the returned slice has one reference per
22 // given traversal, though it is not guaranteed that the references will
23 // appear in the same order as the given traversals.
24 func References(traversals []hcl.Traversal) ([]*addrs.Reference, tfdiags.Diagnostics) {
25 if len(traversals) == 0 {
29 var diags tfdiags.Diagnostics
30 refs := make([]*addrs.Reference, 0, len(traversals))
32 for _, traversal := range traversals {
33 ref, refDiags := addrs.ParseRef(traversal)
34 diags = diags.Append(refDiags)
38 refs = append(refs, ref)
44 // ReferencesInBlock is a helper wrapper around References that first searches
45 // the given body for traversals, before converting those traversals to
48 // A block schema must be provided so that this function can determine where in
49 // the body variables are expected.
50 func ReferencesInBlock(body hcl.Body, schema *configschema.Block) ([]*addrs.Reference, tfdiags.Diagnostics) {
55 // We use blocktoattr.ExpandedVariables instead of hcldec.Variables or
56 // dynblock.VariablesHCLDec here because when we evaluate a block we'll
57 // first apply the dynamic block extension and _then_ the blocktoattr
58 // transform, and so blocktoattr.ExpandedVariables takes into account
59 // both of those transforms when it analyzes the body to ensure we find
60 // all of the references as if they'd already moved into their final
61 // locations, even though we can't expand dynamic blocks yet until we
62 // already know which variables are required.
64 // The set of cases we want to detect here is covered by the tests for
65 // the plan graph builder in the main 'terraform' package, since it's
66 // in a better position to test this due to having mock providers etc
68 traversals := blocktoattr.ExpandedVariables(body, schema)
69 return References(traversals)
72 // ReferencesInExpr is a helper wrapper around References that first searches
73 // the given expression for traversals, before converting those traversals
75 func ReferencesInExpr(expr hcl.Expression) ([]*addrs.Reference, tfdiags.Diagnostics) {
79 traversals := expr.Variables()
80 return References(traversals)