Repository: opentofu/opentofu
File: internal/lang/marks/marks.go (Go)

Code before:
		if !ok {
			continue
		}

		// Already marked as deprecated for this cause.
		if addrs.Equivalent(dm.Cause.By, cause.By) {
			return v
		}
	}

	return v.Mark(deprecationMark{
		Cause: cause,
	})
}

// DeprecatedOutput marks a given values as deprecated constructing a DeprecationCause
// from module output specific data.
func DeprecatedOutput(v cty.Value, addr addrs.AbsOutputValue, msg string, isFromRemoteModule bool) cty.Value {
	_, callOutAddr := addr.ModuleCallOutput()
	return Deprecated(v, DeprecationCause{
		IsFromRemoteModule: isFromRemoteModule,
		By:                 callOutAddr,
		// Used to identify the output on the consolidation diagnostics and
		// make sure they are consolidated correctly. We use:
		// output value + deprecated message as the key
		Key:     addr.OutputValue.Name + msg,
		Message: msg,
	})
}

// ExtractDeprecationDiagnosticsWithBody composes deprecation diagnostics based on deprecation marks inside
// the cty.Value. It uses hcl.Body to properly reference deprecated attributes in final diagnostics.
// The returned cty.Value has no deprecation marks inside, since all the relevant diagnostics has been collected.
func ExtractDeprecationDiagnosticsWithBody(val cty.Value, body hcl.Body) (cty.Value, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics

	val, deprecatedPathMarks := unmarkDeepWithPathsDeprecated(val)

	for _, pm := range deprecatedPathMarks {
		for m := range pm.Marks {
			cause := m.(deprecationMark).Cause
			diag := tfdiags.AttributeValue(
				tfdiags.Warning,
				"Value derived from a deprecated source",
				fmt.Sprintf("This value is derived from %v, which is deprecated with the following message:\n\n%s", cause.By, cause.Message),
				pm.Path,
			)
			diags = diags.Append(tfdiags.Override(diag, tfdiags.Warning, func() tfdiags.DiagnosticExtraWrapper {
				return &deprecatedOutputDiagnosticExtra{
					Cause: cause,
				}

Review comment (bug):
I'd suggest including a newline character, or really just any other character that isn't allowed in an HCL identifier, to separate these two parts.

Although I acknowledge that it's very unlikely, without some sort of delimiter it's possible that two combinations of different output value name and message would result in the same concatenated string and so be incorrectly consolidated. That would not cause a huge problem but might nonetheless be confusing and hard to debug.


Code after:
		if !ok {
			continue
		}

		// Already marked as deprecated for this cause.
		if addrs.Equivalent(dm.Cause.By, cause.By) {
			return v
		}
	}

	return v.Mark(deprecationMark{
		Cause: cause,
	})
}

// DeprecatedOutput marks a given values as deprecated constructing a DeprecationCause
// from module output specific data.
func DeprecatedOutput(v cty.Value, addr addrs.AbsOutputValue, msg string, isFromRemoteModule bool) cty.Value {
	_, callOutAddr := addr.ModuleCallOutput()
	return Deprecated(v, DeprecationCause{
		IsFromRemoteModule: isFromRemoteModule,
		By:                 callOutAddr,
		// Used to identify the output on the consolidation diagnostics and
		// make sure they are consolidated correctly. We use:
		// output value + deprecated message as the key
		Key:     fmt.Sprintf("%s\n%s", addr.OutputValue.Name, msg),
		Message: msg,
	})
}

// ExtractDeprecationDiagnosticsWithBody composes deprecation diagnostics based on deprecation marks inside
// the cty.Value. It uses hcl.Body to properly reference deprecated attributes in final diagnostics.
// The returned cty.Value has no deprecation marks inside, since all the relevant diagnostics has been collected.
func ExtractDeprecationDiagnosticsWithBody(val cty.Value, body hcl.Body) (cty.Value, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics

	val, deprecatedPathMarks := unmarkDeepWithPathsDeprecated(val)

	for _, pm := range deprecatedPathMarks {
		for m := range pm.Marks {
			cause := m.(deprecationMark).Cause
			diag := tfdiags.AttributeValue(
				tfdiags.Warning,
				"Value derived from a deprecated source",
				fmt.Sprintf("This value is derived from %v, which is deprecated with the following message:\n\n%s", cause.By, cause.Message),
				pm.Path,
			)
			diags = diags.Append(tfdiags.Override(diag, tfdiags.Warning, func() tfdiags.DiagnosticExtraWrapper {
				return &deprecatedOutputDiagnosticExtra{
					Cause: cause,
				}