package globalref import ( "fmt" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/providers" ) // Analyzer is the main component of this package, serving as a container for // various state that the analysis algorithms depend on either for their core // functionality or for producing results more quickly. // // Global reference analysis is currently intended only for "best effort" // use-cases related to giving hints to the user or tailoring UI output. // Avoid using it for anything that would cause changes to the analyzer being // considered a breaking change under the v1 compatibility promises, because // we expect to continue to refine and evolve these rules over time in ways // that may cause us to detect either more or fewer references than today. // Typically we will conservatively return more references than would be // necessary dynamically, but that isn't guaranteed for all situations. // // In particular, we currently typically don't distinguish between multiple // instances of the same module, and so we overgeneralize references from // one instance of a module as references from the same location in all // instances of that module. We may make this more precise in future, which // would then remove various detected references from the analysis results. // // Each Analyzer works with a particular configs.Config object which it assumes // represents the root module of a configuration. Config objects are typically // immutable by convention anyway, but it's particularly important not to // modify a configuration while it's attached to a live Analyzer, because // the Analyzer contains caches derived from data in the configuration tree. type Analyzer struct { cfg *configs.Config providerSchemas map[addrs.Provider]*providers.Schemas } // NewAnalyzer constructs a new analyzer bound to the given configuration and // provider schemas. // // The given object must represent a root module, or this function will panic. // // The given provider schemas must cover at least all of the providers used // in the given configuration. If not then analysis results will be silently // incomplete for any decision that requires checking schema. func NewAnalyzer(cfg *configs.Config, providerSchemas map[addrs.Provider]*providers.Schemas) *Analyzer { if !cfg.Path.IsRoot() { panic(fmt.Sprintf("constructing an Analyzer with non-root module %s", cfg.Path)) } ret := &Analyzer{ cfg: cfg, providerSchemas: providerSchemas, } return ret } // ModuleConfig retrieves a module configuration from the configuration the // analyzer belongs to, or nil if there is no module with the given address. func (a *Analyzer) ModuleConfig(addr addrs.ModuleInstance) *configs.Module { modCfg := a.cfg.DescendentForInstance(addr) if modCfg == nil { return nil } return modCfg.Module }