|
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 |
|
@@ -51,7 +52,7 @@ impl PartialOrd for Severity { |
51 | 52 | } |
52 | 53 | } |
53 | 54 |
|
54 | | -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)] |
| 55 | +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] |
55 | 56 | #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] |
56 | 57 | pub enum LabelStyle { |
57 | 58 | /// Labels that describe the primary cause of a diagnostic. |
@@ -114,7 +115,9 @@ impl<FileId> Label<FileId> { |
114 | 115 | /// Represents a diagnostic message that can provide information like errors and |
115 | 116 | /// warnings to the user. |
116 | 117 | /// |
117 | | -/// 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. |
| 118 | +/// The position of a Diagnostic is considered to be the position of the |
| 119 | +/// [`Label`] that has the earliest starting position and has the highest style |
| 120 | +/// which appears in all the labels of the diagnostic. |
118 | 121 | #[derive(Clone, Debug, PartialEq, Eq)] |
119 | 122 | #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] |
120 | 123 | pub struct Diagnostic<FileId> { |
@@ -207,4 +210,36 @@ impl<FileId> Diagnostic<FileId> { |
207 | 210 | self.notes.append(&mut notes); |
208 | 211 | self |
209 | 212 | } |
| 213 | + |
| 214 | + /// Calculate the locus of this diagnostic. |
| 215 | + /// |
| 216 | + /// If this Diagnostic covers multple files, a Vec with multiple values |
| 217 | + /// will be returned. Or contrary, if there are no labels in the |
| 218 | + /// Diagnostic, an empty Vec will be returned. |
| 219 | + pub fn locuses(&self) -> BTreeMap<FileId, usize> |
| 220 | + where |
| 221 | + FileId: Copy + Ord, |
| 222 | + { |
| 223 | + let mut labels = self |
| 224 | + .labels |
| 225 | + .iter() |
| 226 | + .map(|label| (label.file_id, label.style, label.range.start)) |
| 227 | + .collect::<Vec<_>>(); |
| 228 | + |
| 229 | + labels.sort_unstable_by(|a, b| { |
| 230 | + a.0.partial_cmp(&b.0) |
| 231 | + .unwrap_or(std::cmp::Ordering::Equal) |
| 232 | + .then_with(|| a.1.cmp(&b.1)) |
| 233 | + .then_with(|| a.2.cmp(&b.2)) |
| 234 | + // reverse the sorting so we can use `Extend` to deduplicate |
| 235 | + .reverse() |
| 236 | + }); |
| 237 | + |
| 238 | + labels |
| 239 | + .drain(..) |
| 240 | + // the label style was only needed for sorting |
| 241 | + .map(|(file, _, start)| (file, start)) |
| 242 | + // this also deduplicates |
| 243 | + .collect() |
| 244 | + } |
210 | 245 | } |
0 commit comments