github.com/opentofu/opentofu@v1.7.1/internal/lang/globalref/analyzer_meta_references_shortcuts.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package globalref 7 8 import ( 9 "fmt" 10 11 "github.com/opentofu/opentofu/internal/addrs" 12 "github.com/opentofu/opentofu/internal/lang" 13 ) 14 15 // ReferencesFromOutputValue returns all of the direct references from the 16 // value expression of the given output value. It doesn't include any indirect 17 // references. 18 func (a *Analyzer) ReferencesFromOutputValue(addr addrs.AbsOutputValue) []Reference { 19 mc := a.ModuleConfig(addr.Module) 20 if mc == nil { 21 return nil 22 } 23 oc := mc.Outputs[addr.OutputValue.Name] 24 if oc == nil { 25 return nil 26 } 27 refs, _ := lang.ReferencesInExpr(addrs.ParseRef, oc.Expr) 28 return absoluteRefs(addr.Module, refs) 29 } 30 31 // ReferencesFromResourceInstance returns all of the direct references from the 32 // definition of the resource instance at the given address. It doesn't include 33 // any indirect references. 34 // 35 // The result doesn't directly include references from a "count" or "for_each" 36 // expression belonging to the associated resource, but it will include any 37 // references to count.index, each.key, or each.value that appear in the 38 // expressions which you can then, if you wish, resolve indirectly using 39 // Analyzer.MetaReferences. Alternatively, you can use 40 // Analyzer.ReferencesFromResourceRepetition to get that same result directly. 41 func (a *Analyzer) ReferencesFromResourceInstance(addr addrs.AbsResourceInstance) []Reference { 42 // Using MetaReferences for this is kinda overkill, since 43 // lang.ReferencesInBlock would be sufficient really, but 44 // this ensures we keep consistent in how we build the 45 // resulting absolute references and otherwise aside from 46 // some extra overhead this call boils down to a call to 47 // lang.ReferencesInBlock anyway. 48 fakeRef := Reference{ 49 ContainerAddr: addr.Module, 50 LocalRef: &addrs.Reference{ 51 Subject: addr.Resource, 52 }, 53 } 54 return a.MetaReferences(fakeRef) 55 } 56 57 // ReferencesFromResourceRepetition returns the references from the given 58 // resource's for_each or count expression, or an empty set if the resource 59 // doesn't use repetition. 60 // 61 // This is a special-case sort of helper for use in situations where an 62 // expression might refer to count.index, each.key, or each.value, and thus 63 // we say that it depends indirectly on the repetition expression. 64 func (a *Analyzer) ReferencesFromResourceRepetition(addr addrs.AbsResource) []Reference { 65 modCfg := a.ModuleConfig(addr.Module) 66 if modCfg == nil { 67 return nil 68 } 69 rc := modCfg.ResourceByAddr(addr.Resource) 70 if rc == nil { 71 return nil 72 } 73 74 // We're assuming here that resources can either have count or for_each, 75 // but never both, because that's a requirement enforced by the language 76 // decoder. But we'll assert it just to make sure we catch it if that 77 // changes for some reason. 78 if rc.ForEach != nil && rc.Count != nil { 79 panic(fmt.Sprintf("%s has both for_each and count", addr)) 80 } 81 82 switch { 83 case rc.ForEach != nil: 84 refs, _ := lang.ReferencesInExpr(addrs.ParseRef, rc.ForEach) 85 return absoluteRefs(addr.Module, refs) 86 case rc.Count != nil: 87 refs, _ := lang.ReferencesInExpr(addrs.ParseRef, rc.Count) 88 return absoluteRefs(addr.Module, refs) 89 default: 90 return nil 91 } 92 }