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