diff options
| author | Mica White <botahamec@outlook.com> | 2026-07-12 19:49:14 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2026-07-12 19:49:14 -0400 |
| commit | 8399983fd45bc0f11eac9def280c0833ffb93c04 (patch) | |
| tree | f84173ca30a3c62db7abb92a0d869ff5d5199c51 /src/diagnostics/duplicate_attribute_names.rs | |
Diffstat (limited to 'src/diagnostics/duplicate_attribute_names.rs')
| -rw-r--r-- | src/diagnostics/duplicate_attribute_names.rs | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/src/diagnostics/duplicate_attribute_names.rs b/src/diagnostics/duplicate_attribute_names.rs new file mode 100644 index 0000000..542d8ec --- /dev/null +++ b/src/diagnostics/duplicate_attribute_names.rs @@ -0,0 +1,41 @@ +use std::collections::HashMap; + +use miette::Diagnostic; +use thiserror::Error; + +use crate::{ + diagnostics::AstDiagnostic, + parse::{Attribute, Element}, + tokenize::Span, +}; + +#[derive(Error, Debug, Diagnostic)] +#[error("Multiple attributes have the same name")] +#[diagnostic(code(DuplicateAttributeNames), severity(Error))] +pub struct DuplicateAttributeNames { + #[label(collection)] + duplicates: Vec<Span>, +} + +impl AstDiagnostic for DuplicateAttributeNames { + fn handle_element(element: &Element<'_>) -> Option<Self> { + let mut seen_attributes = HashMap::<&str, Attribute<'_>>::new(); + for attribute in element.attributes { + let Some(name) = attribute.name_lowercase() else { + continue; + }; + if let Some(duplicate) = seen_attributes.get(name) { + return Some(Self { + duplicates: vec![ + duplicate.name_token().expect("a named attribute").span, + attribute.name_token().expect("a named attribute").span, + ], + }); + } + + seen_attributes.insert(name, *attribute); + } + + None + } +} |
