diff --git a/codespan-reporting/CHANGELOG.md b/codespan-reporting/CHANGELOG.md index 14c47660..63ba2a91 100644 --- a/codespan-reporting/CHANGELOG.md +++ b/codespan-reporting/CHANGELOG.md @@ -64,6 +64,8 @@ This is because some testing dependencies now require this Rust version. ``` +- `Label`s can now be created without specifying a file id and instead later setting + the file id on a `Label` or all labels in a `Diagnostic`. ## [0.11.1] - 2021-01-18 diff --git a/codespan-reporting/examples/term.rs b/codespan-reporting/examples/term.rs index ee2c057d..9715f37c 100644 --- a/codespan-reporting/examples/term.rs +++ b/codespan-reporting/examples/term.rs @@ -128,12 +128,12 @@ fn main() -> anyhow::Result<()> { .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ - Label::primary(file_id3, 163..166).with_message("expected `String`, found `Nat`"), - Label::secondary(file_id3, 62..166) + Label::primary_anon(163..166).with_message("expected `String`, found `Nat`"), + Label::secondary_anon(62..166) .with_message("`case` clauses have incompatible types"), - Label::secondary(file_id3, 41..47) - .with_message("expected type `String` found here"), + Label::secondary_anon(41..47).with_message("expected type `String` found here"), ]) + .with_file(file_id3) .with_notes(vec![unindent::unindent( " expected type `String` @@ -145,18 +145,18 @@ fn main() -> anyhow::Result<()> { .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ - Label::primary(file_id3, 328..331).with_message("expected `String`, found `Nat`"), - Label::secondary(file_id3, 211..331) + Label::primary_anon(328..331).with_message("expected `String`, found `Nat`"), + Label::secondary_anon(211..331) .with_message("`case` clauses have incompatible types"), - Label::secondary(file_id3, 258..268) + Label::secondary_anon(258..268) .with_message("this is found to be of type `String`"), - Label::secondary(file_id3, 284..290) + Label::secondary_anon(284..290) .with_message("this is found to be of type `String`"), - Label::secondary(file_id3, 306..312) + Label::secondary_anon(306..312) .with_message("this is found to be of type `String`"), - Label::secondary(file_id3, 186..192) - .with_message("expected type `String` found here"), + Label::secondary_anon(186..192).with_message("expected type `String` found here"), ]) + .with_file(file_id3) .with_notes(vec![unindent::unindent( " expected type `String` diff --git a/codespan-reporting/src/diagnostic.rs b/codespan-reporting/src/diagnostic.rs index 8e3abf4f..871039cf 100644 --- a/codespan-reporting/src/diagnostic.rs +++ b/codespan-reporting/src/diagnostic.rs @@ -85,11 +85,58 @@ impl Label { Label::new(LabelStyle::Secondary, file_id, range) } - /// Add a message to the diagnostic. + /// Set the message for the diagnostic. The old message (if any) is discarded. pub fn with_message(mut self, message: impl ToString) -> Label { self.message = message.to_string(); self } + + /// Set the file id. The old file id (if any) is discarded. + pub fn with_file(self, file_id: NewFileId) -> Label { + Label { + style: self.style, + file_id, + range: self.range, + message: self.message, + } + } +} + +// use a separate impl so we do not have to specify the type like this in e.g. +// `primary_anon`: +// ``` +// Label::<()>::new_anon(..) +// ``` +impl Label<()> { + /// Create a new label without specifying a [`file_id`]. + /// + /// [`file_id`]: Label::file_id + pub fn new_anon(style: LabelStyle, range: impl Into>) -> Label<()> { + Label { + style, + file_id: (), + range: range.into(), + message: String::new(), + } + } + + /// Create a new label with a style of [`LabelStyle::Primary`] and without + /// specifying a [`file_id`]. + /// + /// [`LabelStyle::Primary`]: LabelStyle::Primary + /// [`file_id`]: Label::file_id + pub fn primary_anon(range: impl Into>) -> Label<()> { + Label::new_anon(LabelStyle::Primary, range) + } + + /// Create a new label with a style of [`LabelStyle::Secondary`] and without + /// specifying a [`file_id`]. + /// + /// [`LabelStyle::Secondary`]: LabelStyle::Secondary + /// [`file_id`]: Label::file_id + pub fn secondary_anon(range: impl Into>) -> Label<()> { + Label::new_anon(LabelStyle::Secondary, range) + } } /// Represents a diagnostic message that can provide information like errors and @@ -188,4 +235,20 @@ impl Diagnostic { self.notes.append(&mut notes); self } + + /// Set the file id for all labels in this Diagnostic by calling + /// [`Label::with_file`] on each label. + pub fn with_file(mut self, file_id: NewFileId) -> Diagnostic { + Diagnostic { + severity: self.severity, + code: self.code, + message: self.message, + labels: self + .labels + .drain(..) + .map(|label| label.with_file(file_id.clone())) + .collect(), + notes: self.notes, + } + } }