mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
This package has two different mechanisms that can cause an existing diagnostic to be replaced with a modified version: - "Override" effectively wraps an arbitrary other diagnostic with a new severity and optional new "extra info". - Contextual diagnostics allow a diagnostic to be created in one place with some incomplete information, and then "elaborated" in another place where more information is available. Those two mechanisms did not previously interact well together: passing a contextual diagnostic to Override would prevent its elaboration process from taking effect. Now the overriddenDiagnostic type -- implementation detail of "Override" -- implements the same unexported interface that the contextual diagnostics do, and delegates the elaboration request to the diagnostic that it's wrapping so that the elaboration can take effect while still preserving the effect of the overrides. This combination is okay because in practice "override" only affects Severity and ExtraInfo, while contextual diagnostics today only affect the source location information and the "address" components of the diagnostic, so the two can work independently of one another. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
104 lines
2.9 KiB
Go
104 lines
2.9 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package tfdiags
|
|
|
|
import (
|
|
"github.com/hashicorp/hcl/v2"
|
|
)
|
|
|
|
// overriddenDiagnostic implements the Diagnostic interface by wrapping another
|
|
// Diagnostic while overriding the severity of the original Diagnostic.
|
|
type overriddenDiagnostic struct {
|
|
original Diagnostic
|
|
severity Severity
|
|
extra interface{}
|
|
}
|
|
|
|
var _ Diagnostic = overriddenDiagnostic{}
|
|
var _ contextualFromConfigBody = overriddenDiagnostic{}
|
|
|
|
// OverrideAll accepts a set of Diagnostics and wraps them with a new severity
|
|
// and, optionally, a new ExtraInfo.
|
|
func OverrideAll(originals Diagnostics, severity Severity, createExtra func() DiagnosticExtraWrapper) Diagnostics {
|
|
var diags Diagnostics
|
|
for _, diag := range originals {
|
|
diags = diags.Append(Override(diag, severity, createExtra))
|
|
}
|
|
return diags
|
|
}
|
|
|
|
// Override matches OverrideAll except it operates over a single Diagnostic
|
|
// rather than multiple Diagnostics.
|
|
func Override(original Diagnostic, severity Severity, createExtra func() DiagnosticExtraWrapper) Diagnostic {
|
|
extra := original.ExtraInfo()
|
|
if createExtra != nil {
|
|
nw := createExtra()
|
|
nw.WrapDiagnosticExtra(extra)
|
|
extra = nw
|
|
}
|
|
|
|
return overriddenDiagnostic{
|
|
original: original,
|
|
severity: severity,
|
|
extra: extra,
|
|
}
|
|
}
|
|
|
|
// UndoOverride will return the original diagnostic that was overridden within
|
|
// the OverrideAll function.
|
|
//
|
|
// If the provided Diagnostic was never overridden then it is simply returned
|
|
// unchanged.
|
|
func UndoOverride(diag Diagnostic) Diagnostic {
|
|
if override, ok := diag.(overriddenDiagnostic); ok {
|
|
return override.original
|
|
}
|
|
|
|
// Then it wasn't overridden, so we'll just return the diag unchanged.
|
|
return diag
|
|
}
|
|
|
|
func (o overriddenDiagnostic) Severity() Severity {
|
|
return o.severity
|
|
}
|
|
|
|
func (o overriddenDiagnostic) Description() Description {
|
|
return o.original.Description()
|
|
}
|
|
|
|
func (o overriddenDiagnostic) Source() Source {
|
|
return o.original.Source()
|
|
}
|
|
|
|
func (o overriddenDiagnostic) FromExpr() *FromExpr {
|
|
return o.original.FromExpr()
|
|
}
|
|
|
|
func (o overriddenDiagnostic) ExtraInfo() interface{} {
|
|
return o.extra
|
|
}
|
|
|
|
// ElaborateFromConfigBody implements contextualFromConfigBody.
|
|
//
|
|
// If the original diagnostic also implements contextualFromConfigBody then this
|
|
// delegates to its own ElaborateFromConfigBody implementation and then re-wraps
|
|
// the result with the same overrides.
|
|
//
|
|
// Otherwise, the reciever is returned unchanged.
|
|
func (o overriddenDiagnostic) ElaborateFromConfigBody(body hcl.Body, addr string) Diagnostic {
|
|
innerContextual, ok := o.original.(contextualFromConfigBody)
|
|
if !ok {
|
|
return o // inner diagnostic is not contextual, so nothing to do
|
|
}
|
|
|
|
newOriginal := innerContextual.ElaborateFromConfigBody(body, addr)
|
|
return overriddenDiagnostic{
|
|
original: newOriginal,
|
|
severity: o.severity,
|
|
extra: o.extra,
|
|
}
|
|
}
|