|
2 | 2 |
|
3 | 3 | #[cfg(feature = "serialization")] |
4 | 4 | use serde::{Deserialize, Serialize}; |
| 5 | +use std::collections::BTreeMap; |
5 | 6 | use std::ops::Range; |
6 | 7 | use std::string::ToString; |
7 | 8 |
|
@@ -32,7 +33,7 @@ pub enum Severity { |
32 | 33 | Bug, |
33 | 34 | } |
34 | 35 |
|
35 | | -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)] |
| 36 | +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] |
36 | 37 | #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] |
37 | 38 | pub enum LabelStyle { |
38 | 39 | /// Labels that describe the primary cause of a diagnostic. |
@@ -95,7 +96,9 @@ impl<FileId> Label<FileId> { |
95 | 96 | /// Represents a diagnostic message that can provide information like errors and |
96 | 97 | /// warnings to the user. |
97 | 98 | /// |
98 | | -/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic. |
| 99 | +/// The position of a Diagnostic is considered to be the position of the |
| 100 | +/// [`Label`] that has the earliest starting position and has the highest style |
| 101 | +/// which appears in all the labels of the diagnostic. |
99 | 102 | #[derive(Clone, Debug, PartialEq, Eq)] |
100 | 103 | #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] |
101 | 104 | pub struct Diagnostic<FileId> { |
@@ -188,4 +191,36 @@ impl<FileId> Diagnostic<FileId> { |
188 | 191 | self.notes.append(&mut notes); |
189 | 192 | self |
190 | 193 | } |
| 194 | + |
| 195 | + /// Calculate the locus of this diagnostic. |
| 196 | + /// |
| 197 | + /// If this Diagnostic covers multple files, a Vec with multiple values |
| 198 | + /// will be returned. Or contrary, if there are no labels in the |
| 199 | + /// Diagnostic, an empty Vec will be returned. |
| 200 | + pub fn locuses(&self) -> BTreeMap<FileId, usize> |
| 201 | + where |
| 202 | + FileId: Copy + Ord, |
| 203 | + { |
| 204 | + let mut labels = self |
| 205 | + .labels |
| 206 | + .iter() |
| 207 | + .map(|label| (label.file_id, label.style, label.range.start)) |
| 208 | + .collect::<Vec<_>>(); |
| 209 | + |
| 210 | + labels.sort_unstable_by(|a, b| { |
| 211 | + a.0.partial_cmp(&b.0) |
| 212 | + .unwrap_or(std::cmp::Ordering::Equal) |
| 213 | + .then_with(|| a.1.cmp(&b.1)) |
| 214 | + .then_with(|| a.2.cmp(&b.2)) |
| 215 | + // reverse the sorting so we can use `Extend` to deduplicate |
| 216 | + .reverse() |
| 217 | + }); |
| 218 | + |
| 219 | + labels |
| 220 | + .drain(..) |
| 221 | + // the label style was only needed for sorting |
| 222 | + .map(|(file, _, start)| (file, start)) |
| 223 | + // this also deduplicates |
| 224 | + .collect() |
| 225 | + } |
191 | 226 | } |
0 commit comments