github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/lang/references.go (about)

     1  package lang
     2  
     3  import (
     4  	"github.com/hashicorp/hcl/v2"
     5  	"github.com/hashicorp/terraform/internal/addrs"
     6  	"github.com/hashicorp/terraform/internal/configs/configschema"
     7  	"github.com/hashicorp/terraform/internal/lang/blocktoattr"
     8  	"github.com/hashicorp/terraform/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  }