From 3040deac66e3bffd1fd69788897ee1bf84d481ce Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Wed, 24 Jan 2024 11:16:01 -0800 Subject: [PATCH] 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. --- internal/terraform/evaluate.go | 7 +++++ internal/terraform/evaluate_valid.go | 37 ++++++++++++----------- internal/terraform/evaluate_valid_test.go | 6 +--- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/internal/terraform/evaluate.go b/internal/terraform/evaluate.go index f7bd5e9c81..8157b1d1ab 100644 --- a/internal/terraform/evaluate.go +++ b/internal/terraform/evaluate.go @@ -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 { diff --git a/internal/terraform/evaluate_valid.go b/internal/terraform/evaluate_valid.go index 1b0dc22a4c..50b122f9eb 100644 --- a/internal/terraform/evaluate_valid.go +++ b/internal/terraform/evaluate_valid.go @@ -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 diff --git a/internal/terraform/evaluate_valid_test.go b/internal/terraform/evaluate_valid_test.go index c65e9aca03..778a5e674b 100644 --- a/internal/terraform/evaluate_valid_test.go +++ b/internal/terraform/evaluate_valid_test.go @@ -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())