github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/lang/references.go (about) 1 package lang 2 3 import ( 4 "github.com/hashicorp/hcl/v2" 5 "github.com/muratcelep/terraform/not-internal/addrs" 6 "github.com/muratcelep/terraform/not-internal/configs/configschema" 7 "github.com/muratcelep/terraform/not-internal/lang/blocktoattr" 8 "github.com/muratcelep/terraform/not-internal/tfdiags" 9 ) 10 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 13 // reference. 14 // 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 18 // occurence. 19 // 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 { 26 return nil, nil 27 } 28 29 var diags tfdiags.Diagnostics 30 refs := make([]*addrs.Reference, 0, len(traversals)) 31 32 for _, traversal := range traversals { 33 ref, refDiags := addrs.ParseRef(traversal) 34 diags = diags.Append(refDiags) 35 if ref == nil { 36 continue 37 } 38 refs = append(refs, ref) 39 } 40 41 return refs, diags 42 } 43 44 // ReferencesInBlock is a helper wrapper around References that first searches 45 // the given body for traversals, before converting those traversals to 46 // references. 47 // 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) { 51 if body == nil { 52 return nil, nil 53 } 54 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. 63 // 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 67 // available. 68 traversals := blocktoattr.ExpandedVariables(body, schema) 69 return References(traversals) 70 } 71 72 // ReferencesInExpr is a helper wrapper around References that first searches 73 // the given expression for traversals, before converting those traversals 74 // to references. 75 func ReferencesInExpr(expr hcl.Expression) ([]*addrs.Reference, tfdiags.Diagnostics) { 76 if expr == nil { 77 return nil, nil 78 } 79 traversals := expr.Variables() 80 return References(traversals) 81 }