Skip to content

Commit

Permalink
config: duplicate external error (#704)
Browse files Browse the repository at this point in the history
* config: duplicate external error

* fix check
  • Loading branch information
BrettMayson authored Jun 11, 2024
1 parent b33d492 commit 3da46e3
Show file tree
Hide file tree
Showing 12 changed files with 415 additions and 254 deletions.
74 changes: 74 additions & 0 deletions libs/config/src/analyze/codes/ce8_duplicate_external.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use hemtt_workspace::reporting::{Code, Diagnostic, Label, Processed};

use crate::Class;

pub struct DuplicateExternal {
classes: Vec<Class>,
diagnostic: Option<Diagnostic>,
}

impl Code for DuplicateExternal {
fn ident(&self) -> &'static str {
"CE8"
}

fn message(&self) -> String {
"external class defined multiple times".to_string()
}

fn label_message(&self) -> String {
"defined multiple times".to_string()
}

fn help(&self) -> Option<String> {
self.classes
.first()
.expect("at least one class")
.name()
.map(|parent| {
format!(
"remove all but the first definition of `class {};`",
parent.as_str(),
)
})
}

fn diagnostic(&self) -> Option<Diagnostic> {
self.diagnostic.clone()
}
}

impl DuplicateExternal {
pub fn new(classes: Vec<Class>, processed: &Processed) -> Self {
Self {
classes,
diagnostic: None,
}
.generate_processed(processed)
}

fn generate_processed(mut self, processed: &Processed) -> Self {
let Some(name) = self.classes[0].name() else {
panic!("DuplicateExternal::generate_processed called on class without name");
};
self.diagnostic = Diagnostic::new_for_processed(&self, name.span.clone(), processed);
if let Some(diag) = &mut self.diagnostic {
for class in self.classes.iter().skip(1) {
let map = processed
.mapping(class.name().expect("class should have name").span.start)
.expect("mapping should exist");
let file = processed.source(map.source()).expect("source should exist");
diag.labels.push(
Label::secondary(
file.0.clone(),
map.original_start()
..map.original_start()
+ class.name().expect("class should have name").span.len(),
)
.with_message("also defined here"),
);
}
}
self
}
}
1 change: 1 addition & 0 deletions libs/config/src/analyze/codes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod ce4_missing_semicolon;
pub mod ce5_unexpected_array;
pub mod ce6_expected_array;
pub mod ce7_missing_parent;
pub mod ce8_duplicate_external;

pub mod cw1_parent_case;
pub mod cw2_magwell_missing_magazine;
Expand Down
254 changes: 0 additions & 254 deletions libs/config/src/analyze/config.rs

This file was deleted.

51 changes: 51 additions & 0 deletions libs/config/src/analyze/config/duplicate_properties.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::{collections::HashMap, sync::Arc};

use hemtt_workspace::reporting::{Code, Processed};

use crate::{analyze::codes::ce3_duplicate_property::DuplicateProperty, Class, Ident, Property};

pub fn duplicate_properties(properties: &[Property], processed: &Processed) -> Vec<Arc<dyn Code>> {
let mut seen: HashMap<String, Vec<(bool, Ident)>> = HashMap::new();
duplicate_properties_inner("", properties, &mut seen);
let mut errors: Vec<Arc<dyn Code>> = Vec::new();
for (_, idents) in seen {
if idents.len() > 1 && !idents.iter().all(|(class, _)| *class) {
errors.push(Arc::new(DuplicateProperty::new(
idents.into_iter().map(|(_, i)| i).collect(),
processed,
)));
}
}
errors
}

fn duplicate_properties_inner(
scope: &str,
properties: &[Property],
seen: &mut HashMap<String, Vec<(bool, Ident)>>,
) {
for property in properties {
match property {
Property::Class(Class::Local {
name, properties, ..
}) => {
duplicate_properties_inner(
&format!("{}.{}", scope, name.value.to_lowercase()),
properties,
seen,
);
let entry = seen
.entry(format!("{}.{}", scope, name.value.to_lowercase()))
.or_default();
entry.push((true, name.clone()));
}
Property::Entry { name, .. } | Property::MissingSemicolon(name, _) => {
let entry = seen
.entry(format!("{}.{}", scope, name.value.to_lowercase()))
.or_default();
entry.push((false, name.clone()));
}
_ => (),
}
}
}
Loading

0 comments on commit 3da46e3

Please sign in to comment.