diff --git a/internal/deprecation/deprecation.go b/internal/deprecation/deprecation.go index 956da60b4761..d7b89f3a9359 100644 --- a/internal/deprecation/deprecation.go +++ b/internal/deprecation/deprecation.go @@ -43,16 +43,32 @@ func (d *Deprecations) SuppressModuleCallDeprecation(addr addrs.Module) { // values. // If the value can not be referenced, use ValidateDeep or ValidateAsConfig instead. func (d *Deprecations) Validate(value cty.Value, module addrs.Module, rng *hcl.Range) (cty.Value, tfdiags.Diagnostics) { - deprecationMarks := marks.GetDeprecationMarks(value) - notDeprecatedValue := marks.RemoveDeprecationMarks(value) + notDeprecatedValue, deprecationMarks := marks.GetDeprecationMarks(value) return notDeprecatedValue, d.deprecationMarksToDiagnostics(deprecationMarks, module, rng) } -// ValidateDeep does the same as Validate but checks deeply nested deprecation marks as well. -func (d *Deprecations) ValidateDeep(value cty.Value, module addrs.Module, rng *hcl.Range) (cty.Value, tfdiags.Diagnostics) { - deprecationMarks := marks.GetDeprecationMarksDeep(value) - notDeprecatedValue := marks.RemoveDeprecationMarksDeep(value) - return notDeprecatedValue, d.deprecationMarksToDiagnostics(deprecationMarks, module, rng) +// ValidateExpressionDeep looks for deprecation marks deeply within the given value +// and returns diagnostics for each deprecation found, unless deprecation warnings +// are suppressed for the given module. It finds the most specific range possible for +// each diagnostic. +func (d *Deprecations) ValidateExpressionDeep(value cty.Value, module addrs.Module, expr hcl.Expression) (cty.Value, tfdiags.Diagnostics) { + var diags tfdiags.Diagnostics + unmarked, pvms := value.UnmarkDeepWithPaths() + + // Check if we need to suppress deprecation warnings for this module call. + if d.IsModuleCallDeprecationSuppressed(module) { + return unmarked.MarkWithPaths(marks.RemoveAll(pvms, marks.Deprecation)), diags + } + + for _, pvm := range pvms { + for m := range pvm.Marks { + if depMark, ok := m.(marks.DeprecationMark); ok { + rng := tfdiags.RangeForExpressionAtPath(expr, pvm.Path) + diags = diags.Append(deprecationMarkToDiagnostic(depMark, &rng)) + } + } + } + return unmarked.MarkWithPaths(marks.RemoveAll(pvms, marks.Deprecation)), diags } func (d *Deprecations) deprecationMarksToDiagnostics(deprecationMarks []marks.DeprecationMark, module addrs.Module, rng *hcl.Range) tfdiags.Diagnostics { @@ -67,31 +83,35 @@ func (d *Deprecations) deprecationMarksToDiagnostics(deprecationMarks []marks.De } for _, depMark := range deprecationMarks { - diag := &hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Deprecated value used", - Detail: depMark.Message, - Subject: rng, - } - if depMark.OriginDescription != "" { - diag.Extra = &tfdiags.DeprecationOriginDiagnosticExtra{ - OriginDescription: depMark.OriginDescription, - } - } - diags = diags.Append(diag) + diags = diags.Append(deprecationMarkToDiagnostic(depMark, rng)) } return diags } -// ValidateAsConfig checks the given value for deprecation marks and returns diagnostics +func deprecationMarkToDiagnostic(depMark marks.DeprecationMark, subject *hcl.Range) *hcl.Diagnostic { + diag := &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "Deprecated value used", + Detail: depMark.Message, + Subject: subject, + } + if depMark.OriginDescription != "" { + diag.Extra = &tfdiags.DeprecationOriginDiagnosticExtra{ + OriginDescription: depMark.OriginDescription, + } + } + return diag +} + +// ValidateConfig checks the given value deeply for deprecation marks and returns diagnostics // for each deprecation found, unless deprecation warnings are suppressed for the given module. -// It checks for deeply nested deprecation marks as well. -func (d *Deprecations) ValidateAsConfig(value cty.Value, schema *configschema.Block, module addrs.Module) tfdiags.Diagnostics { +func (d *Deprecations) ValidateConfig(value cty.Value, schema *configschema.Block, module addrs.Module) (cty.Value, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics - _, pvms := value.UnmarkDeepWithPaths() + unmarked, pvms := value.UnmarkDeepWithPaths() - if len(pvms) == 0 || d.IsModuleCallDeprecationSuppressed(module) { - return diags + if d.IsModuleCallDeprecationSuppressed(module) { + // Even if we don't want to get deprecation warnings we want to remove the marks + return unmarked.MarkWithPaths(marks.RemoveAll(pvms, marks.Deprecation)), diags } for _, pvm := range pvms { @@ -120,7 +140,8 @@ func (d *Deprecations) ValidateAsConfig(value cty.Value, schema *configschema.Bl } } } - return diags + + return unmarked.MarkWithPaths(marks.RemoveAll(pvms, marks.Deprecation)), diags } func (d *Deprecations) IsModuleCallDeprecationSuppressed(addr addrs.Module) bool { @@ -133,7 +154,3 @@ func (d *Deprecations) IsModuleCallDeprecationSuppressed(addr addrs.Module) bool } return false } - -func (d *Deprecations) DiagnosticsForValueMarks(valueMarks cty.ValueMarks, module addrs.Module, rng *hcl.Range) tfdiags.Diagnostics { - return d.deprecationMarksToDiagnostics(marks.FilterDeprecationMarks(valueMarks), module, rng) -} diff --git a/internal/lang/marks/marks.go b/internal/lang/marks/marks.go index 6421463f6069..3d59ea63c86b 100644 --- a/internal/lang/marks/marks.go +++ b/internal/lang/marks/marks.go @@ -51,28 +51,25 @@ func Contains(val cty.Value, mark interface{}) bool { // FilterDeprecationMarks returns all deprecation marks present in the given // cty.ValueMarks. -func FilterDeprecationMarks(marks cty.ValueMarks) []DeprecationMark { +func FilterDeprecationMarks(marks cty.ValueMarks) (cty.ValueMarks, []DeprecationMark) { + other := cty.ValueMarks{} depMarks := []DeprecationMark{} for mark := range marks { if d, ok := mark.(DeprecationMark); ok { depMarks = append(depMarks, d) + } else { + other[mark] = struct{}{} } } - return depMarks + return other, depMarks } // GetDeprecationMarks returns all deprecation marks present on the given // cty.Value. -func GetDeprecationMarks(val cty.Value) []DeprecationMark { - _, marks := val.Unmark() - return FilterDeprecationMarks(marks) -} - -// GetDeprecationMarksDeep returns all deprecation marks present on the given -// cty.Value or any nested values. -func GetDeprecationMarksDeep(val cty.Value) []DeprecationMark { - _, marks := val.UnmarkDeep() - return FilterDeprecationMarks(marks) +func GetDeprecationMarks(val cty.Value) (cty.Value, []DeprecationMark) { + unmarked, marks := val.Unmark() + other, depMarks := FilterDeprecationMarks(marks) + return unmarked.WithMarks(other), depMarks } // RemoveDeprecationMarks returns a copy of the given cty.Value with all diff --git a/internal/terraform/context_apply2_test.go b/internal/terraform/context_apply2_test.go index b07d7323665f..62eceec73bd2 100644 --- a/internal/terraform/context_apply2_test.go +++ b/internal/terraform/context_apply2_test.go @@ -4461,60 +4461,8 @@ resource "test_resource" "test" { ) }, expectedDiagnostics: func(m *configs.Config) tfdiags.Diagnostics { - return tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Deprecated value used", - Detail: "Please stop using this output", - Subject: &hcl.Range{ - Filename: filepath.Join(m.Module.SourceDir, "main.tf"), - Start: hcl.Pos{Line: 7, Column: 13, Byte: 86}, - End: hcl.Pos{Line: 7, Column: 27, Byte: 100}, - }, - }) - }, - }, - "update resource to stop using deprecated output": { - modules: map[string]string{ - "mod/main.tf": ` -output "old" { - deprecated = "Please stop using this output" - value = "deprecated-value" -} -output "new" { - value = "new-value" -} -`, - "main.tf": ` -module "mod" { - source = "./mod" -} - -resource "test_resource" "test" { - value = module.mod.old -} -`, - }, - buildState: func(s *states.SyncState) { - s.SetResourceInstanceCurrent( - mustResourceInstanceAddr("test_resource.test"), - &states.ResourceInstanceObjectSrc{ - AttrsJSON: []byte(`{"value":"deprecated-value"}`), - Status: states.ObjectReady, - }, - mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`), - ) - }, - expectedDiagnostics: func(m *configs.Config) tfdiags.Diagnostics { - return tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Deprecated value used", - Detail: "Please stop using this output", - Subject: &hcl.Range{ - Filename: filepath.Join(m.Module.SourceDir, "main.tf"), - Start: hcl.Pos{Line: 7, Column: 13, Byte: 86}, - End: hcl.Pos{Line: 7, Column: 27, Byte: 100}, - }, - }) + // if the resource instance is not executed, we can not warn (during plan a warning was already emitted) + return tfdiags.Diagnostics{} }, }, "create resource using deprecated variable": { diff --git a/internal/terraform/eval_conditions.go b/internal/terraform/eval_conditions.go index 3a5810734fa7..e1f3fd2d9970 100644 --- a/internal/terraform/eval_conditions.go +++ b/internal/terraform/eval_conditions.go @@ -107,7 +107,7 @@ func validateCheckRule(addr addrs.CheckRule, rule *configs.CheckRule, ctx EvalCo errorMessage, moreDiags := lang.EvalCheckErrorMessage(rule.ErrorMessage, hclCtx, &addr) diags = diags.Append(moreDiags) - _, deprecationDiags := ctx.Deprecations().ValidateDeep(errorMessage, ctx.Path().Module(), rule.ErrorMessage.Range().Ptr()) + _, deprecationDiags := ctx.Deprecations().Validate(errorMessage, ctx.Path().Module(), rule.ErrorMessage.Range().Ptr()) diags = diags.Append(deprecationDiags) // NOTE: We've discarded any other marks the string might have been carrying, @@ -169,8 +169,7 @@ func evalCheckRule(addr addrs.CheckRule, rule *configs.CheckRule, ctx EvalContex return checkResult{Status: checks.StatusError}, diags } - // We don't care about the returned value here, only the diagnostics - _, deprecationDiags := ctx.Deprecations().ValidateDeep(resultVal, addr.ModuleInstance().Module(), rule.Condition.Range().Ptr()) + resultVal, deprecationDiags := ctx.Deprecations().Validate(resultVal, addr.ModuleInstance().Module(), rule.Condition.Range().Ptr()) diags = diags.Append(deprecationDiags) var err error diff --git a/internal/terraform/node_action_instance.go b/internal/terraform/node_action_instance.go index a2eb8a884ad4..5f2074c63345 100644 --- a/internal/terraform/node_action_instance.go +++ b/internal/terraform/node_action_instance.go @@ -71,7 +71,8 @@ func (n *NodeActionDeclarationInstance) Execute(ctx EvalContext, _ walkOperation valDiags := validateResourceForbiddenEphemeralValues(ctx, configVal, n.Schema.ConfigSchema) diags = diags.Append(valDiags.InConfigBody(n.Config.Config, n.Addr.String())) - deprecationDiags := ctx.Deprecations().ValidateAsConfig(configVal, n.Schema.ConfigSchema, n.ModulePath()) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, n.Schema.ConfigSchema, n.ModulePath()) diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) if diags.HasErrors() { diff --git a/internal/terraform/node_action_partialexp.go b/internal/terraform/node_action_partialexp.go index 2fdbf1ce2383..d60f4380ac35 100644 --- a/internal/terraform/node_action_partialexp.go +++ b/internal/terraform/node_action_partialexp.go @@ -68,9 +68,9 @@ func (n *NodeActionDeclarationPartialExpanded) Execute(ctx EvalContext, op walkO if diags.HasErrors() { return diags } - - deprecationDiags := ctx.Deprecations().ValidateAsConfig(configVal, n.Schema.ConfigSchema, n.ActionAddr().Module) - diags = diags.Append(deprecationDiags) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, n.Schema.ConfigSchema, n.ActionAddr().Module) + diags = diags.Append(deprecationDiags.InConfigBody(n.config.Config, n.ActionAddr().String())) if diags.HasErrors() { return diags } diff --git a/internal/terraform/node_action_validate.go b/internal/terraform/node_action_validate.go index 59e85e20d97f..26cd98706d39 100644 --- a/internal/terraform/node_action_validate.go +++ b/internal/terraform/node_action_validate.go @@ -101,8 +101,9 @@ func (n *NodeValidatableAction) Execute(ctx EvalContext, _ walkOperation) tfdiag return diags } } - - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.ConfigSchema, n.ModulePath()).InConfigBody(n.Config.Config, n.Addr.String())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.ConfigSchema, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) valDiags = validateResourceForbiddenEphemeralValues(ctx, configVal, schema.ConfigSchema) diags = diags.Append(valDiags.InConfigBody(config, n.Addr.String())) diff --git a/internal/terraform/node_local.go b/internal/terraform/node_local.go index c0edab003326..8e3376aad868 100644 --- a/internal/terraform/node_local.go +++ b/internal/terraform/node_local.go @@ -140,6 +140,10 @@ func (n *NodeLocal) References() []*addrs.Reference { func (n *NodeLocal) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { namedVals := ctx.NamedValues() val, diags := evaluateLocalValue(n.Config, n.Addr.LocalValue, n.Addr.String(), ctx) + // We only use a shallow evaluation of deprecations here because we only want to warn + // if the entire value is deprecated. If e.g. a module is stored in the local and the module + // contains a deprecated output we don't want to warn about that here, but only when the + // output is actually referenced. valWithoutDeprecations, deprecationDiags := ctx.Deprecations().Validate(val, n.ModulePath(), n.Config.Expr.Range().Ptr()) diags = diags.Append(deprecationDiags) diff --git a/internal/terraform/node_output.go b/internal/terraform/node_output.go index ad08b187d8e3..bfd1fddbae88 100644 --- a/internal/terraform/node_output.go +++ b/internal/terraform/node_output.go @@ -530,7 +530,7 @@ If you do intend to export this data, annotate the output value as sensitive by } } else if n.Config.Expr != nil { var deprecationDiags tfdiags.Diagnostics - val, deprecationDiags = ctx.Deprecations().ValidateDeep(val, n.ModulePath(), n.Config.Expr.Range().Ptr()) + val, deprecationDiags = ctx.Deprecations().ValidateExpressionDeep(val, n.ModulePath(), n.Config.Expr) diags = diags.Append(deprecationDiags) } diff --git a/internal/terraform/node_provider.go b/internal/terraform/node_provider.go index 9ed0fe538d45..b4c2f0d7bd7b 100644 --- a/internal/terraform/node_provider.go +++ b/internal/terraform/node_provider.go @@ -83,7 +83,8 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi return diags } - deprecationDiags := ctx.Deprecations().ValidateAsConfig(configVal, configSchema, n.Addr.Module) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, configSchema, n.Addr.Module) diags = diags.Append(deprecationDiags.InConfigBody(configBody, n.Addr.String())) if diags.HasErrors() { return diags diff --git a/internal/terraform/node_resource_abstract_instance.go b/internal/terraform/node_resource_abstract_instance.go index 9e463bc89000..332e61f0eb4b 100644 --- a/internal/terraform/node_resource_abstract_instance.go +++ b/internal/terraform/node_resource_abstract_instance.go @@ -869,7 +869,9 @@ func (n *NodeAbstractResourceInstance) plan( diags = diags.Append( validateResourceForbiddenEphemeralValues(ctx, origConfigVal, schema.Body).InConfigBody(n.Config.Config, n.Addr.String()), ) - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(origConfigVal, schema.Body, n.ModulePath()).InConfigBody(n.Config.Config, n.Addr.String())) + var deprecationDiags tfdiags.Diagnostics + origConfigVal, deprecationDiags = ctx.Deprecations().ValidateConfig(origConfigVal, schema.Body, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) if diags.HasErrors() { return nil, nil, deferred, keyData, diags } @@ -1787,10 +1789,9 @@ func (n *NodeAbstractResourceInstance) providerMetas(ctx EvalContext) (cty.Value var configDiags tfdiags.Diagnostics metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, providerSchema.ProviderMeta.Body, nil, EvalDataForNoInstanceKey) diags = diags.Append(configDiags) - diags = diags.Append( - ctx.Deprecations().ValidateAsConfig(metaConfigVal, providerSchema.ProviderMeta.Body, ctx.Path().Module()).InConfigBody(m.Config, n.Addr.String()), - ) - metaConfigVal = marks.RemoveDeprecationMarks(metaConfigVal) + var deprecationDiags tfdiags.Diagnostics + metaConfigVal, deprecationDiags = ctx.Deprecations().ValidateConfig(metaConfigVal, providerSchema.ProviderMeta.Body, ctx.Path().Module()) + diags = diags.Append(deprecationDiags.InConfigBody(m.Config, n.Addr.String())) } } } @@ -1867,10 +1868,11 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRule diags = diags.Append( validateResourceForbiddenEphemeralValues(ctx, configVal, schema.Body).InConfigBody(n.Config.Config, n.Addr.String()), ) - diags = diags.Append( - ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, ctx.Path().Module()).InConfigBody(n.Config.Config, n.Addr.String()), - ) - configVal = marks.RemoveDeprecationMarks(configVal) + + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, ctx.Path().Module()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) + if diags.HasErrors() { return nil, nil, deferred, keyData, diags } @@ -2208,13 +2210,13 @@ func (n *NodeAbstractResourceInstance) applyDataSource(ctx EvalContext, planned return nil, keyData, diags } - diags = diags.Append( - ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ModulePath()).InConfigBody(n.Config.Config, n.Addr.String()), - ) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) + if diags.HasErrors() { return nil, keyData, diags } - configVal = marks.RemoveDeprecationMarks(configVal) newVal, readDeferred, readDiags := n.readDataSource(ctx, configVal) if check, nested := n.nestedInCheckBlock(); nested { @@ -2527,8 +2529,9 @@ func (n *NodeAbstractResourceInstance) evalProvisionerConfig(ctx EvalContext, bo config, _, configDiags := ctx.EvaluateBlock(body, schema, n.ResourceInstanceAddr().Resource, keyData) diags = diags.Append(configDiags) - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(config, schema, n.ModulePath()).InConfigBody(body, n.Addr.String())) - config = marks.RemoveDeprecationMarks(config) + var deprecationDiags tfdiags.Diagnostics + config, deprecationDiags = ctx.Deprecations().ValidateConfig(config, schema, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(body, n.Addr.String())) return config, diags } @@ -2546,8 +2549,9 @@ func (n *NodeAbstractResourceInstance) evalDestroyProvisionerConfig(ctx EvalCont evalScope := ctx.EvaluationScope(n.ResourceInstanceAddr().Resource, nil, keyData) config, evalDiags := evalScope.EvalSelfBlock(body, self, schema, keyData) diags = diags.Append(evalDiags) - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(config, schema, n.ModulePath()).InConfigBody(body, n.Addr.String())) - config = marks.RemoveDeprecationMarks(config) + var deprecationDiags tfdiags.Diagnostics + config, deprecationDiags = ctx.Deprecations().ValidateConfig(config, schema, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(body, n.Addr.String())) return config, diags } diff --git a/internal/terraform/node_resource_ephemeral.go b/internal/terraform/node_resource_ephemeral.go index 93530ccaf687..6f5eaa9c7f37 100644 --- a/internal/terraform/node_resource_ephemeral.go +++ b/internal/terraform/node_resource_ephemeral.go @@ -76,7 +76,9 @@ func ephemeralResourceOpen(ctx EvalContext, inp ephemeralResourceInput) (*provid if diags.HasErrors() { return nil, diags } - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, ctx.Path().Module()).InConfigBody(config.Config, inp.addr.String())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, ctx.Path().Module()) + diags = diags.Append(deprecationDiags.InConfigBody(config.Config, inp.addr.String())) if diags.HasErrors() { return nil, diags } diff --git a/internal/terraform/node_resource_plan_instance.go b/internal/terraform/node_resource_plan_instance.go index a18ac8e1adb8..bccc9027d897 100644 --- a/internal/terraform/node_resource_plan_instance.go +++ b/internal/terraform/node_resource_plan_instance.go @@ -662,7 +662,9 @@ func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs. diags = diags.Append(configDiags) return nil, deferred, diags } - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ModulePath()).InConfigBody(n.Config.Config, absAddr.String())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, absAddr.String())) if diags.HasErrors() { return nil, deferred, diags } diff --git a/internal/terraform/node_resource_plan_instance_query.go b/internal/terraform/node_resource_plan_instance_query.go index e99879f708bf..d2e479da2262 100644 --- a/internal/terraform/node_resource_plan_instance_query.go +++ b/internal/terraform/node_resource_plan_instance_query.go @@ -8,7 +8,6 @@ import ( "log" "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/lang/marks" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/tfdiags" @@ -50,8 +49,9 @@ func (n *NodePlannableResourceInstance) listResourceExecute(ctx EvalContext) (di if diags.HasErrors() { return diags } - - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(blockVal, schema.FullSchema, n.ModulePath()).InConfigBody(config.Config, n.Addr.String())) + var deprecationDiags tfdiags.Diagnostics + blockVal, deprecationDiags = ctx.Deprecations().ValidateConfig(blockVal, schema.FullSchema, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(config.Config, n.Addr.String())) if diags.HasErrors() { return diags } @@ -74,7 +74,6 @@ func (n *NodePlannableResourceInstance) listResourceExecute(ctx EvalContext) (di var limitDeprecationDiags tfdiags.Diagnostics limitCty, limitDeprecationDiags = ctx.Deprecations().Validate(limitCty, ctx.Path().Module(), config.List.Limit.Range().Ptr()) diags = diags.Append(limitDeprecationDiags) - limitCty = marks.RemoveDeprecationMarks(limitCty) } includeRscCty, includeRsc, includeDiags := newIncludeRscEvaluator(false).EvaluateExpr(ctx, config.List.IncludeResource) @@ -87,7 +86,6 @@ func (n *NodePlannableResourceInstance) listResourceExecute(ctx EvalContext) (di var includeDeprecationDiags tfdiags.Diagnostics includeRscCty, includeDeprecationDiags = ctx.Deprecations().Validate(includeRscCty, ctx.Path().Module(), config.List.IncludeResource.Range().Ptr()) diags = diags.Append(includeDeprecationDiags) - includeRscCty = marks.RemoveDeprecationMarks(includeRscCty) } rId := HookResourceIdentity{ diff --git a/internal/terraform/node_resource_plan_partialexp.go b/internal/terraform/node_resource_plan_partialexp.go index a8c2b34fca87..3a3a09b7a940 100644 --- a/internal/terraform/node_resource_plan_partialexp.go +++ b/internal/terraform/node_resource_plan_partialexp.go @@ -200,7 +200,9 @@ func (n *nodePlannablePartialExpandedResource) managedResourceExecute(ctx EvalCo return &change, diags } - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ResourceAddr().Module).InConfigBody(n.config.Config, n.addr.String())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ResourceAddr().Module) + diags = diags.Append(deprecationDiags.InConfigBody(n.config.Config, n.addr.String())) if diags.HasErrors() { return &change, diags } @@ -359,7 +361,9 @@ func (n *nodePlannablePartialExpandedResource) dataResourceExecute(ctx EvalConte return &change, diags } - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ResourceAddr().Module).InConfigBody(n.config.Config, n.addr.String())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ResourceAddr().Module) + diags = diags.Append(deprecationDiags.InConfigBody(n.config.Config, n.addr.String())) if diags.HasErrors() { return &change, diags } diff --git a/internal/terraform/node_resource_validate.go b/internal/terraform/node_resource_validate.go index c918cb32f491..eea1530d0b9c 100644 --- a/internal/terraform/node_resource_validate.go +++ b/internal/terraform/node_resource_validate.go @@ -19,7 +19,6 @@ import ( "github.com/hashicorp/terraform/internal/lang/ephemeral" "github.com/hashicorp/terraform/internal/lang/format" "github.com/hashicorp/terraform/internal/lang/langrefs" - "github.com/hashicorp/terraform/internal/lang/marks" "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/provisioners" "github.com/hashicorp/terraform/internal/tfdiags" @@ -144,9 +143,11 @@ func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil) val, hclBody, diags := ctx.EvaluateBlock(body, schema, selfAddr, keyData) - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(val, schema, n.Addr.Module).InConfigBody(body, n.Addr.String())) - return marks.RemoveDeprecationMarks(val), hclBody, diags + var deprecationDiags tfdiags.Diagnostics + val, deprecationDiags = ctx.Deprecations().ValidateConfig(val, schema, n.Addr.Module) + diags = diags.Append(deprecationDiags.InConfigBody(body, n.Addr.String())) + return val, hclBody, diags } // connectionBlockSupersetSchema is a schema representing the superset of all @@ -360,7 +361,9 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag diags = diags.Append( validateResourceForbiddenEphemeralValues(ctx, configVal, schema.Body).InConfigBody(n.Config.Config, n.Addr.String()), ) - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ModulePath()).InConfigBody(n.Config.Config, n.Addr.String())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) if n.Config.Managed != nil { // can be nil only in tests with poorly-configured mocks for _, traversal := range n.Config.Managed.IgnoreChanges { @@ -440,7 +443,9 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag diags = diags.Append( validateResourceForbiddenEphemeralValues(ctx, configVal, schema.Body).InConfigBody(n.Config.Config, n.Addr.String()), ) - diags = diags.Append(ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ModulePath())) + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ModulePath()) + diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) // Use unmarked value for validate request unmarkedConfigVal, _ := configVal.UnmarkDeep() @@ -468,8 +473,10 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag if valDiags.HasErrors() { return diags } + var deprecationDiags tfdiags.Diagnostics + configVal, deprecationDiags = ctx.Deprecations().ValidateConfig(configVal, schema.Body, n.ModulePath()) diags = diags.Append( - ctx.Deprecations().ValidateAsConfig(configVal, schema.Body, n.ModulePath()).InConfigBody(n.Config.Config, n.Addr.String()), + deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String()), ) // Use unmarked value for validate request unmarkedConfigVal, _ := configVal.UnmarkDeep() @@ -502,7 +509,8 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag if valDiags.HasErrors() { return diags } - deprecationDiags := ctx.Deprecations().ValidateAsConfig(blockVal, schema.FullSchema, n.ModulePath()) + var deprecationDiags tfdiags.Diagnostics + blockVal, deprecationDiags = ctx.Deprecations().ValidateConfig(blockVal, schema.FullSchema, n.ModulePath()) diags = diags.Append(deprecationDiags.InConfigBody(n.Config.Config, n.Addr.String())) } @@ -513,9 +521,9 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag if limitDiags.HasErrors() { return diags } - _, deprecationDiags := ctx.Deprecations().Validate(limit, n.ModulePath(), n.Config.List.Limit.Range().Ptr()) + var deprecationDiags tfdiags.Diagnostics + limit, deprecationDiags = ctx.Deprecations().Validate(limit, n.ModulePath(), n.Config.List.Limit.Range().Ptr()) diags = diags.Append(deprecationDiags) - limit = marks.RemoveDeprecationMarks(limit) } if n.Config.List.IncludeResource != nil { @@ -524,9 +532,9 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag if includeDiags.HasErrors() { return diags } - _, deprecationDiags := ctx.Deprecations().Validate(includeResource, n.ModulePath(), n.Config.List.IncludeResource.Range().Ptr()) + var deprecationDiags tfdiags.Diagnostics + includeResource, deprecationDiags = ctx.Deprecations().Validate(includeResource, n.ModulePath(), n.Config.List.IncludeResource.Range().Ptr()) diags = diags.Append(deprecationDiags) - includeResource = marks.RemoveDeprecationMarks(includeResource) } // Use unmarked value for validate request diff --git a/internal/tfdiags/contextual.go b/internal/tfdiags/contextual.go index 0b6f27b69ff7..4fdb2e76b232 100644 --- a/internal/tfdiags/contextual.go +++ b/internal/tfdiags/contextual.go @@ -338,12 +338,16 @@ func rangeOfDeepestAttributeValueFromPath(body hcl.Body, traverse cty.Path) hcl. return body.MissingItemRange() } + return RangeForExpressionAtPath(attr.Expr, rest) +} + +func RangeForExpressionAtPath(expression hcl.Expression, path cty.Path) hcl.Range { // Now we need to loop through the rest of the path and progressively introspect // the HCL expression. - currentExpr := attr.Expr + currentExpr := expression STEP_ITERATION: - for _, step := range rest { + for _, step := range path { // We treat cty.IndexStep[type=String] and cty.GetAttrStep the same, so we just // need to deal with list indexes first if idxStep, ok := step.(cty.IndexStep); ok && idxStep.Key.Type() == cty.Number { @@ -354,7 +358,7 @@ STEP_ITERATION: return currentExpr.Range() } if err != nil || idx >= len(items) { - return attr.NameRange + return currentExpr.Range() } currentExpr = items[idx] continue STEP_ITERATION @@ -386,7 +390,7 @@ STEP_ITERATION: } } // If we could not find the item return early - return attr.NameRange + return currentExpr.Range() } return currentExpr.Range() diff --git a/internal/tfdiags/contextual_test.go b/internal/tfdiags/contextual_test.go index 82313c27aaf6..e02dde28810c 100644 --- a/internal/tfdiags/contextual_test.go +++ b/internal/tfdiags/contextual_test.go @@ -239,8 +239,8 @@ simple_attr = "val" ), &SourceRange{ Filename: "test.tf", - Start: SourcePos{Line: 19, Column: 3, Byte: 155}, - End: SourcePos{Line: 19, Column: 19, Byte: 171}, + Start: SourcePos{Line: 19, Column: 22, Byte: 174}, + End: SourcePos{Line: 19, Column: 43, Byte: 195}, }, }, { @@ -378,8 +378,8 @@ simple_attr = "val" ), &SourceRange{ Filename: "test.tf", - Start: SourcePos{Line: 21, Column: 3, Byte: 233}, - End: SourcePos{Line: 21, Column: 13, Byte: 243}, + Start: SourcePos{Line: 21, Column: 16, Byte: 246}, + End: SourcePos{Line: 25, Column: 4, Byte: 393}, }, }, @@ -444,8 +444,8 @@ simple_attr = "val" ), &SourceRange{ Filename: "test.tf", - Start: SourcePos{Line: 27, Column: 1, Byte: 396}, - End: SourcePos{Line: 27, Column: 13, Byte: 408}, + Start: SourcePos{Line: 27, Column: 16, Byte: 411}, + End: SourcePos{Line: 27, Column: 23, Byte: 418}, }, }, { @@ -461,8 +461,8 @@ simple_attr = "val" ), &SourceRange{ Filename: "test.tf", - Start: SourcePos{Line: 28, Column: 1, Byte: 419}, - End: SourcePos{Line: 28, Column: 13, Byte: 431}, + Start: SourcePos{Line: 28, Column: 16, Byte: 434}, + End: SourcePos{Line: 28, Column: 34, Byte: 452}, }, }, { @@ -509,8 +509,8 @@ simple_attr = "val" ), &SourceRange{ Filename: "test.tf", - Start: SourcePos{Line: 29, Column: 1, Byte: 453}, - End: SourcePos{Line: 29, Column: 9, Byte: 461}, + Start: SourcePos{Line: 29, Column: 12, Byte: 464}, + End: SourcePos{Line: 32, Column: 2, Byte: 501}, }, }, {