aldrin_parser/error/
duplicate_struct_field_id.rs

1use super::Error;
2use crate::ast::{Ident, LitPosInt, StructField};
3use crate::diag::{Diagnostic, DiagnosticKind, Formatted, Formatter};
4use crate::validate::Validate;
5use crate::{util, Parsed, Span};
6
7#[derive(Debug)]
8pub struct DuplicateStructFieldId {
9    schema_name: String,
10    duplicate: LitPosInt,
11    first: Span,
12    struct_span: Span,
13    struct_ident: Option<Ident>,
14    free_id: u32,
15}
16
17impl DuplicateStructFieldId {
18    pub(crate) fn validate(
19        fields: &[StructField],
20        struct_span: Span,
21        ident: Option<&Ident>,
22        validate: &mut Validate,
23    ) {
24        let mut max_id = fields
25            .iter()
26            .fold(0, |cur, field| match field.id().value().parse() {
27                Ok(id) if id > cur => id,
28                _ => cur,
29            });
30
31        util::find_duplicates(
32            fields,
33            |field| field.id().value(),
34            |duplicate, first| {
35                max_id += 1;
36                let free_id = max_id;
37                validate.add_error(Self {
38                    schema_name: validate.schema_name().to_owned(),
39                    duplicate: duplicate.id().clone(),
40                    first: first.id().span(),
41                    struct_span,
42                    struct_ident: ident.cloned(),
43                    free_id,
44                })
45            },
46        );
47    }
48
49    pub fn duplicate(&self) -> &LitPosInt {
50        &self.duplicate
51    }
52
53    pub fn first(&self) -> Span {
54        self.first
55    }
56
57    pub fn struct_span(&self) -> Span {
58        self.struct_span
59    }
60
61    pub fn struct_ident(&self) -> Option<&Ident> {
62        self.struct_ident.as_ref()
63    }
64
65    pub fn free_id(&self) -> u32 {
66        self.free_id
67    }
68}
69
70impl Diagnostic for DuplicateStructFieldId {
71    fn kind(&self) -> DiagnosticKind {
72        DiagnosticKind::Error
73    }
74
75    fn schema_name(&self) -> &str {
76        &self.schema_name
77    }
78
79    fn format<'a>(&'a self, parsed: &'a Parsed) -> Formatted<'a> {
80        let mut fmt = if let Some(ref ident) = self.struct_ident {
81            Formatter::new(
82                self,
83                format!(
84                    "duplicate id `{}` in struct `{}`",
85                    self.duplicate.value(),
86                    ident.value()
87                ),
88            )
89        } else {
90            Formatter::new(
91                self,
92                format!("duplicate id `{}` in inline struct", self.duplicate.value()),
93            )
94        };
95
96        if let Some(schema) = parsed.get_schema(&self.schema_name) {
97            fmt.main_block(
98                schema,
99                self.duplicate.span().from,
100                self.duplicate.span(),
101                "duplicate defined here",
102            )
103            .info_block(schema, self.first.from, self.first, "first defined here");
104        }
105
106        fmt.help(format!("use a free id, e.g. {}", self.free_id));
107        fmt.format()
108    }
109}
110
111impl From<DuplicateStructFieldId> for Error {
112    fn from(e: DuplicateStructFieldId) -> Self {
113        Self::DuplicateStructFieldId(e)
114    }
115}