7 // DiagnosticSeverity represents the severity of a diagnostic.
8 type DiagnosticSeverity int
11 // DiagInvalid is the invalid zero value of DiagnosticSeverity
12 DiagInvalid DiagnosticSeverity = iota
14 // DiagError indicates that the problem reported by a diagnostic prevents
15 // further progress in parsing and/or evaluating the subject.
18 // DiagWarning indicates that the problem reported by a diagnostic warrants
19 // user attention but does not prevent further progress. It is most
20 // commonly used for showing deprecation notices.
24 // Diagnostic represents information to be presented to a user about an
25 // error or anomoly in parsing or evaluating configuration.
26 type Diagnostic struct {
27 Severity DiagnosticSeverity
29 // Summary and Detail contain the English-language description of the
30 // problem. Summary is a terse description of the general problem and
31 // detail is a more elaborate, often-multi-sentence description of
32 // the probem and what might be done to solve it.
36 // Subject and Context are both source ranges relating to the diagnostic.
38 // Subject is a tight range referring to exactly the construct that
39 // is problematic, while Context is an optional broader range (which should
40 // fully contain Subject) that ought to be shown around Subject when
41 // generating isolated source-code snippets in diagnostic messages.
42 // If Context is nil, the Subject is also the Context.
44 // Some diagnostics have no source ranges at all. If Context is set then
45 // Subject should always also be set.
49 // For diagnostics that occur when evaluating an expression, Expression
50 // may refer to that expression and EvalContext may point to the
51 // EvalContext that was active when evaluating it. This may allow for the
52 // inclusion of additional useful information when rendering a diagnostic
53 // message to the user.
55 // It is not always possible to select a single EvalContext for a
56 // diagnostic, and so in some cases this field may be nil even when an
57 // expression causes a problem.
59 // EvalContexts form a tree, so the given EvalContext may refer to a parent
60 // which in turn refers to another parent, etc. For a full picture of all
61 // of the active variables and functions the caller must walk up this
62 // chain, preferring definitions that are "closer" to the expression in
63 // case of colliding names.
65 EvalContext *EvalContext
68 // Diagnostics is a list of Diagnostic instances.
69 type Diagnostics []*Diagnostic
71 // error implementation, so that diagnostics can be returned via APIs
72 // that normally deal in vanilla Go errors.
74 // This presents only minimal context about the error, for compatibility
75 // with usual expectations about how errors will present as strings.
76 func (d *Diagnostic) Error() string {
77 return fmt.Sprintf("%s: %s; %s", d.Subject, d.Summary, d.Detail)
80 // error implementation, so that sets of diagnostics can be returned via
81 // APIs that normally deal in vanilla Go errors.
82 func (d Diagnostics) Error() string {
86 return "no diagnostics"
90 return fmt.Sprintf("%s, and %d other diagnostic(s)", d[0].Error(), count-1)
94 // Append appends a new error to a Diagnostics and return the whole Diagnostics.
96 // This is provided as a convenience for returning from a function that
97 // collects and then returns a set of diagnostics:
99 // return nil, diags.Append(&hcl.Diagnostic{ ... })
101 // Note that this modifies the array underlying the diagnostics slice, so
102 // must be used carefully within a single codepath. It is incorrect (and rude)
103 // to extend a diagnostics created by a different subsystem.
104 func (d Diagnostics) Append(diag *Diagnostic) Diagnostics {
105 return append(d, diag)
108 // Extend concatenates the given Diagnostics with the receiver and returns
109 // the whole new Diagnostics.
111 // This is similar to Append but accepts multiple diagnostics to add. It has
112 // all the same caveats and constraints.
113 func (d Diagnostics) Extend(diags Diagnostics) Diagnostics {
114 return append(d, diags...)
117 // HasErrors returns true if the receiver contains any diagnostics of
118 // severity DiagError.
119 func (d Diagnostics) HasErrors() bool {
120 for _, diag := range d {
121 if diag.Severity == DiagError {
128 func (d Diagnostics) Errs() []error {
130 for _, diag := range d {
131 if diag.Severity == DiagError {
132 errs = append(errs, diag)
139 // A DiagnosticWriter emits diagnostics somehow.
140 type DiagnosticWriter interface {
141 WriteDiagnostic(*Diagnostic) error
142 WriteDiagnostics(Diagnostics) error