terraform: Evaluator.StaticValidateReferences

We previously had the StaticValidateReferences method implemented on the
evaluationStateData type directly, but really the only information it
needs directly from that object is the static module path, with everything
else just coming from the wrapped Evaluator.

That means that we can instead implement this as a method of Evaluator
that is thinly wrapped by the prior evaluationStateData method. The
guts of that method are functions that don't really depend on either of
the two objects as a whole, so thus further turns them into just plain
unexported functions that take the data they need as arguments.

This commit doesn't achieve anything other than some light refactoring,
but it will become more important in a subsequent commit that will add
an additional implementation of lang.Data for evaluating references in
expressions beneath an incompletely-expanded module. Both of those
implementations can safely share the same implementation of
StaticValidateReference though, since that method doesn't consider any
dynamic expansion by definition anyway.
pull/34578/head
Martin Atkins 2 years ago
parent 49663bfc33
commit 3040deac66

@ -146,6 +146,13 @@ var EvalDataForNoInstanceKey = InstanceKeyEvalData{}
// evaluationStateData must implement lang.Data
var _ lang.Data = (*evaluationStateData)(nil)
// StaticValidateReferences calls [Evaluator.StaticValidateReferences] on
// the evaluator embedded in this data object, using this data object's
// static module path.
func (d *evaluationStateData) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
return d.Evaluator.StaticValidateReferences(refs, d.ModulePath.Module(), self, source)
}
func (d *evaluationStateData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
switch addr.Name {

@ -31,24 +31,27 @@ import (
//
// The result may include warning diagnostics if, for example, deprecated
// features are referenced.
func (d *evaluationStateData) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
func (e *Evaluator) StaticValidateReferences(refs []*addrs.Reference, modAddr addrs.Module, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
for _, ref := range refs {
moreDiags := d.staticValidateReference(ref, self, source)
moreDiags := e.StaticValidateReference(ref, modAddr, self, source)
diags = diags.Append(moreDiags)
}
return diags
}
func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
modCfg := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
func (e *Evaluator) StaticValidateReference(ref *addrs.Reference, modAddr addrs.Module, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
modCfg := e.Config.Descendent(modAddr)
if modCfg == nil {
// This is a bug in the caller rather than a problem with the
// reference, but rather than crashing out here in an unhelpful way
// we'll just ignore it and trust a different layer to catch it.
return nil
}
return e.staticValidateReference(ref, modCfg, self, source)
}
func (e *Evaluator) staticValidateReference(ref *addrs.Reference, modCfg *configs.Config, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
if ref.Subject == addrs.Self {
// The "self" address is a special alias for the address given as
// our self parameter here, if present.
@ -80,20 +83,20 @@ func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self
// staticValidateMultiResourceReference respectively.
case addrs.Resource:
var diags tfdiags.Diagnostics
diags = diags.Append(d.staticValidateSingleResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange))
diags = diags.Append(d.staticValidateResourceReference(modCfg, addr, source, ref.Remaining, ref.SourceRange))
diags = diags.Append(staticValidateSingleResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange))
diags = diags.Append(staticValidateResourceReference(modCfg, addr, source, e.Plugins, ref.Remaining, ref.SourceRange))
return diags
case addrs.ResourceInstance:
var diags tfdiags.Diagnostics
diags = diags.Append(d.staticValidateMultiResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange))
diags = diags.Append(d.staticValidateResourceReference(modCfg, addr.ContainingResource(), source, ref.Remaining, ref.SourceRange))
diags = diags.Append(staticValidateMultiResourceReference(modCfg, addr, ref.Remaining, ref.SourceRange))
diags = diags.Append(staticValidateResourceReference(modCfg, addr.ContainingResource(), source, e.Plugins, ref.Remaining, ref.SourceRange))
return diags
// We also handle all module call references the same way, disregarding index.
case addrs.ModuleCall:
return d.staticValidateModuleCallReference(modCfg, addr, ref.Remaining, ref.SourceRange)
return staticValidateModuleCallReference(modCfg, addr, ref.Remaining, ref.SourceRange)
case addrs.ModuleCallInstance:
return d.staticValidateModuleCallReference(modCfg, addr.Call, ref.Remaining, ref.SourceRange)
return staticValidateModuleCallReference(modCfg, addr.Call, ref.Remaining, ref.SourceRange)
case addrs.ModuleCallInstanceOutput:
// This one is a funny one because we will take the output name referenced
// and use it to fake up a "remaining" that would make sense for the
@ -109,7 +112,7 @@ func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self
// but is close enough for our purposes.
SrcRange: ref.SourceRange.ToHCL(),
}
return d.staticValidateModuleCallReference(modCfg, addr.Call.Call, remain, ref.SourceRange)
return staticValidateModuleCallReference(modCfg, addr.Call.Call, remain, ref.SourceRange)
default:
// Anything else we'll just permit through without any static validation
@ -118,7 +121,7 @@ func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self
}
}
func (d *evaluationStateData) staticValidateSingleResourceReference(modCfg *configs.Config, addr addrs.Resource, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
func staticValidateSingleResourceReference(modCfg *configs.Config, addr addrs.Resource, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
// If we have at least one step in "remain" and this resource has
// "count" set then we know for sure this in invalid because we have
// something like:
@ -163,7 +166,7 @@ func (d *evaluationStateData) staticValidateSingleResourceReference(modCfg *conf
return diags
}
func (d *evaluationStateData) staticValidateMultiResourceReference(modCfg *configs.Config, addr addrs.ResourceInstance, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
func staticValidateMultiResourceReference(modCfg *configs.Config, addr addrs.ResourceInstance, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
cfg := modCfg.Module.ResourceByAddr(addr.ContainingResource())
@ -175,7 +178,7 @@ func (d *evaluationStateData) staticValidateMultiResourceReference(modCfg *confi
if addr.Key == addrs.NoKey {
// This is a different path into staticValidateSingleResourceReference
return d.staticValidateSingleResourceReference(modCfg, addr.ContainingResource(), remain, rng)
return staticValidateSingleResourceReference(modCfg, addr.ContainingResource(), remain, rng)
} else {
if cfg.Count == nil && cfg.ForEach == nil {
diags = diags.Append(&hcl.Diagnostic{
@ -190,7 +193,7 @@ func (d *evaluationStateData) staticValidateMultiResourceReference(modCfg *confi
return diags
}
func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Config, addr addrs.Resource, source addrs.Referenceable, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
func staticValidateResourceReference(modCfg *configs.Config, addr addrs.Resource, source addrs.Referenceable, plugins *contextPlugins, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
var modeAdjective string
@ -236,7 +239,7 @@ func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Co
}
providerFqn := modCfg.Module.ProviderForLocalConfig(cfg.ProviderConfigAddr())
schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(providerFqn, addr.Mode, addr.Type)
schema, _, err := plugins.ResourceTypeSchema(providerFqn, addr.Mode, addr.Type)
if err != nil {
// Prior validation should've taken care of a schema lookup error,
// so we should never get here but we'll handle it here anyway for
@ -286,7 +289,7 @@ func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Co
return diags
}
func (d *evaluationStateData) staticValidateModuleCallReference(modCfg *configs.Config, addr addrs.ModuleCall, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
func staticValidateModuleCallReference(modCfg *configs.Config, addr addrs.ModuleCall, remain hcl.Traversal, rng tfdiags.SourceRange) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
// For now, our focus here is just in testing that the referenced module

@ -135,11 +135,7 @@ For example, to correlate with indices of a referring resource, use:
t.Fatal(diags.Err())
}
data := &evaluationStateData{
Evaluator: evaluator,
}
diags = data.StaticValidateReferences(refs, nil, test.Src)
diags = evaluator.StaticValidateReferences(refs, addrs.RootModule, nil, test.Src)
if diags.HasErrors() {
if test.WantErr == "" {
t.Fatalf("Unexpected diagnostics: %s", diags.Err())

Loading…
Cancel
Save