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  }