aldrin_parser/error/
duplicate_service_item.rs

1use super::Error;
2use crate::ast::{Ident, ServiceDef};
3use crate::diag::{Diagnostic, DiagnosticKind, Formatted, Formatter};
4use crate::validate::Validate;
5use crate::{util, Parsed, Span};
6
7#[derive(Debug)]
8pub struct DuplicateServiceItem {
9    schema_name: String,
10    duplicate: Ident,
11    first: Span,
12    service_ident: Ident,
13}
14
15impl DuplicateServiceItem {
16    pub(crate) fn validate(service: &ServiceDef, validate: &mut Validate) {
17        let mut fallback_dup = false;
18
19        util::find_duplicates(
20            service.items(),
21            |item| item.name().value(),
22            |duplicate, first| {
23                validate.add_error(Self {
24                    schema_name: validate.schema_name().to_owned(),
25                    duplicate: duplicate.name().clone(),
26                    first: first.name().span(),
27                    service_ident: service.name().clone(),
28                })
29            },
30        );
31
32        if let Some(fallback) = service.function_fallback() {
33            for item in service.items() {
34                if fallback.name().value() == item.name().value() {
35                    validate.add_error(Self {
36                        schema_name: validate.schema_name().to_owned(),
37                        duplicate: fallback.name().clone(),
38                        first: item.name().span(),
39                        service_ident: service.name().clone(),
40                    });
41
42                    fallback_dup = true;
43                    break;
44                }
45            }
46        }
47
48        if let Some(fallback) = service.event_fallback() {
49            for item in service.items() {
50                if fallback.name().value() == item.name().value() {
51                    validate.add_error(Self {
52                        schema_name: validate.schema_name().to_owned(),
53                        duplicate: fallback.name().clone(),
54                        first: item.name().span(),
55                        service_ident: service.name().clone(),
56                    });
57
58                    fallback_dup = true;
59                    break;
60                }
61            }
62        }
63
64        if !fallback_dup {
65            if let (Some(func), Some(ev)) = (service.function_fallback(), service.event_fallback())
66            {
67                if func.name().value() == ev.name().value() {
68                    let (duplicate, first) = if func.span().from < ev.span().from {
69                        (ev.name().clone(), func.name().span())
70                    } else {
71                        (func.name().clone(), ev.name().span())
72                    };
73
74                    validate.add_error(Self {
75                        schema_name: validate.schema_name().to_owned(),
76                        duplicate,
77                        first,
78                        service_ident: service.name().clone(),
79                    });
80                }
81            }
82        }
83    }
84
85    pub fn duplicate(&self) -> &Ident {
86        &self.duplicate
87    }
88
89    pub fn first(&self) -> Span {
90        self.first
91    }
92
93    pub fn service_ident(&self) -> &Ident {
94        &self.service_ident
95    }
96}
97
98impl Diagnostic for DuplicateServiceItem {
99    fn kind(&self) -> DiagnosticKind {
100        DiagnosticKind::Error
101    }
102
103    fn schema_name(&self) -> &str {
104        &self.schema_name
105    }
106
107    fn format<'a>(&'a self, parsed: &'a Parsed) -> Formatted<'a> {
108        let mut fmt = Formatter::new(
109            self,
110            format!(
111                "duplicate item `{}` in service `{}`",
112                self.duplicate.value(),
113                self.service_ident.value()
114            ),
115        );
116
117        if let Some(schema) = parsed.get_schema(&self.schema_name) {
118            fmt.main_block(
119                schema,
120                self.duplicate.span().from,
121                self.duplicate.span(),
122                "duplicate defined here",
123            )
124            .info_block(schema, self.first.from, self.first, "first defined here");
125        }
126
127        fmt.format()
128    }
129}
130
131impl From<DuplicateServiceItem> for Error {
132    fn from(e: DuplicateServiceItem) -> Self {
133        Self::DuplicateServiceItem(e)
134    }
135}