github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/lang/globalref/analyzer.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package globalref 5 6 import ( 7 "fmt" 8 9 "github.com/terramate-io/tf/addrs" 10 "github.com/terramate-io/tf/configs" 11 "github.com/terramate-io/tf/providers" 12 ) 13 14 // Analyzer is the main component of this package, serving as a container for 15 // various state that the analysis algorithms depend on either for their core 16 // functionality or for producing results more quickly. 17 // 18 // Global reference analysis is currently intended only for "best effort" 19 // use-cases related to giving hints to the user or tailoring UI output. 20 // Avoid using it for anything that would cause changes to the analyzer being 21 // considered a breaking change under the v1 compatibility promises, because 22 // we expect to continue to refine and evolve these rules over time in ways 23 // that may cause us to detect either more or fewer references than today. 24 // Typically we will conservatively return more references than would be 25 // necessary dynamically, but that isn't guaranteed for all situations. 26 // 27 // In particular, we currently typically don't distinguish between multiple 28 // instances of the same module, and so we overgeneralize references from 29 // one instance of a module as references from the same location in all 30 // instances of that module. We may make this more precise in future, which 31 // would then remove various detected references from the analysis results. 32 // 33 // Each Analyzer works with a particular configs.Config object which it assumes 34 // represents the root module of a configuration. Config objects are typically 35 // immutable by convention anyway, but it's particularly important not to 36 // modify a configuration while it's attached to a live Analyzer, because 37 // the Analyzer contains caches derived from data in the configuration tree. 38 type Analyzer struct { 39 cfg *configs.Config 40 providerSchemas map[addrs.Provider]providers.ProviderSchema 41 } 42 43 // NewAnalyzer constructs a new analyzer bound to the given configuration and 44 // provider schemas. 45 // 46 // The given object must represent a root module, or this function will panic. 47 // 48 // The given provider schemas must cover at least all of the providers used 49 // in the given configuration. If not then analysis results will be silently 50 // incomplete for any decision that requires checking schema. 51 func NewAnalyzer(cfg *configs.Config, providerSchemas map[addrs.Provider]providers.ProviderSchema) *Analyzer { 52 if !cfg.Path.IsRoot() { 53 panic(fmt.Sprintf("constructing an Analyzer with non-root module %s", cfg.Path)) 54 } 55 56 ret := &Analyzer{ 57 cfg: cfg, 58 providerSchemas: providerSchemas, 59 } 60 return ret 61 } 62 63 // ModuleConfig retrieves a module configuration from the configuration the 64 // analyzer belongs to, or nil if there is no module with the given address. 65 func (a *Analyzer) ModuleConfig(addr addrs.ModuleInstance) *configs.Module { 66 modCfg := a.cfg.DescendentForInstance(addr) 67 if modCfg == nil { 68 return nil 69 } 70 return modCfg.Module 71 }