Skip to main content

device_driver_diagnostics/
errors.rs

1#![allow(
2    unused_assignments,
3    reason = "Something going on with the diagnostics derive"
4)]
5
6use std::borrow::Cow;
7
8use annotate_snippets::{AnnotationKind, Group, Level, Patch, Snippet};
9use device_driver_common::{
10    identifier::{self, Identifier, RuntimeNamespace},
11    interner::Istr,
12    span::{Span, Spanned},
13    specifiers::{BaseType, Integer, NodeType},
14};
15use itertools::Itertools;
16
17use crate::{Diagnostic, Severity, encode_ansi_url};
18
19#[derive(Debug)]
20pub struct IntegerFieldSizeTooBig {
21    pub field_address: Span,
22    pub base_type: Span,
23    pub field_set: Span,
24    pub size_bits: u64,
25}
26
27impl Diagnostic for IntegerFieldSizeTooBig {
28    fn severity(&self) -> Severity {
29        Severity::Error
30    }
31
32    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
33        let field_message = format!("field has a size of {} bits", self.size_bits);
34
35        [
36            self.title_snippet().element(
37                Snippet::source(source)
38                    .path(path)
39                    .annotation(
40                        AnnotationKind::Primary
41                            .span(self.field_address.into())
42                            .label(field_message),
43                    )
44                    .annotation(
45                        AnnotationKind::Context
46                            .span(self.base_type.into())
47                            .label("field uses an integer as base type"),
48                    )
49                    .annotation(AnnotationKind::Visible.span(self.field_set.into())),
50            ),
51            Group::with_title(
52                Level::NOTE.secondary_title("integer base types are available up to 64-bit"),
53            ),
54            Group::with_title(Level::INFO.secondary_title(format!(
55                "if you need an array or string base type, please comment here: {}",
56                encode_ansi_url(
57                    "https://github.com/diondokter/device-driver/issues/131",
58                    "issue 131"
59                )
60            ))),
61        ]
62        .to_vec()
63    }
64
65    fn primary_span(&self) -> Span {
66        self.field_address
67    }
68
69    fn title(&self) -> Cow<'static, str> {
70        "field size exceeds 64-bit size limit".into()
71    }
72}
73
74#[derive(Debug)]
75pub struct DeviceNameNotPascal {
76    pub device_name: Span,
77    pub suggestion: String,
78}
79
80impl Diagnostic for DeviceNameNotPascal {
81    fn severity(&self) -> Severity {
82        Severity::Error
83    }
84
85    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
86        const INFO_TEXT: &str = "device names tend to be a bit weird, so the casing is not automatically changed from the input. Because of that, they need to be roughly PascalCase shaped.";
87
88        [
89            self.title_snippet().element(
90                Snippet::source(source).path(path).annotation(
91                    AnnotationKind::Primary
92                        .span(self.device_name.into())
93                        .label("device name is not Pascal cased"),
94                ),
95            ),
96            Level::HELP
97                .secondary_title("device names need to be pascal-shaped")
98                .element(
99                    Snippet::source(source)
100                        .path(path)
101                        .patch(Patch::new(self.device_name.into(), &self.suggestion)),
102                ),
103            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
104        ]
105        .to_vec()
106    }
107
108    fn primary_span(&self) -> Span {
109        self.device_name
110    }
111
112    fn title(&self) -> Cow<'static, str> {
113        "invalid device name".into()
114    }
115}
116
117#[derive(Debug)]
118pub struct DuplicateName {
119    pub original: Span,
120    pub original_value: Identifier<RuntimeNamespace>,
121    pub duplicate: Span,
122    pub duplicate_value: Identifier<RuntimeNamespace>,
123}
124
125impl Diagnostic for DuplicateName {
126    fn severity(&self) -> Severity {
127        Severity::Error
128    }
129
130    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
131        const INFO_TEXT: &str =
132            "names may not collide within their namespace. There are 4 namespaces:
133- Types: a type definition
134- Operations: something you *do* with a driver
135- Fields: unique within a fieldset
136- Enum variants: unique within an enum";
137
138        [
139            self.title_snippet().element(
140                Snippet::source(source)
141                    .path(path)
142                    .annotation(
143                        AnnotationKind::Context
144                            .span(self.original.into())
145                            .label(format!(
146                                "the original: {:?}, after word split: {:?}",
147                                self.original_value.original(),
148                                self.original_value.words_display()
149                            )),
150                    )
151                    .annotation(AnnotationKind::Primary.span(self.duplicate.into()).label(
152                        format!(
153                            "the duplicate: {:?}, after word split: {:?}",
154                            self.duplicate_value.original(),
155                            self.duplicate_value.words_display()
156                        ),
157                    )),
158            ),
159            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
160        ]
161        .to_vec()
162    }
163
164    fn primary_span(&self) -> Span {
165        self.duplicate
166    }
167
168    fn title(&self) -> Cow<'static, str> {
169        "duplicate name found".into()
170    }
171}
172
173#[derive(Debug)]
174pub struct EmptyEnum {
175    pub enum_node: Span,
176}
177
178impl Diagnostic for EmptyEnum {
179    fn severity(&self) -> Severity {
180        Severity::Error
181    }
182
183    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
184        [
185            self.title_snippet().element(
186                Snippet::source(source).path(path).annotation(
187                    AnnotationKind::Primary
188                        .span(self.enum_node.into())
189                        .label("empty enum"),
190                ),
191            ),
192            Group::with_title(
193                Level::INFO.secondary_title("all enums must have at least one variant"),
194            ),
195        ]
196        .to_vec()
197    }
198
199    fn primary_span(&self) -> Span {
200        self.enum_node
201    }
202
203    fn title(&self) -> Cow<'static, str> {
204        "enum has no variants".into()
205    }
206}
207
208#[derive(Debug)]
209pub struct DuplicateVariantValue {
210    pub duplicates: Vec<Span>,
211    pub value: i128,
212}
213
214impl Diagnostic for DuplicateVariantValue {
215    fn severity(&self) -> Severity {
216        Severity::Error
217    }
218
219    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
220        const INFO_TEXT: &str = "all enum variants must have a unique value";
221
222        [
223            self.title_snippet()
224                .element(Snippet::source(source).path(path).annotations(
225                    self.duplicates.iter().map(|dup| {
226                        AnnotationKind::Primary.span(dup.into()).label(format!(
227                            "variant value is: {} ({:#X})",
228                            self.value, self.value
229                        ))
230                    }),
231                )),
232            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
233        ]
234        .to_vec()
235    }
236
237    fn primary_span(&self) -> Span {
238        self.duplicates[0]
239    }
240
241    fn title(&self) -> Cow<'static, str> {
242        "two or more enum variants share the same value".into()
243    }
244}
245
246#[derive(Debug)]
247pub struct EnumBadBasetype {
248    pub enum_name: Span,
249    pub base_type: Span,
250    pub info: &'static str,
251    pub context: Vec<Spanned<String>>,
252}
253
254impl Diagnostic for EnumBadBasetype {
255    fn severity(&self) -> Severity {
256        Severity::Error
257    }
258
259    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
260        [
261            self.title_snippet().element(
262                Snippet::source(source)
263                    .path(path)
264                    .annotation(
265                        AnnotationKind::Primary
266                            .span(self.base_type.into())
267                            .label("invalid base type"),
268                    )
269                    .annotation(
270                        AnnotationKind::Context
271                            .span(self.enum_name.into())
272                            .label("enum using invalid base type"),
273                    )
274                    .annotations(
275                        self.context
276                            .iter()
277                            .map(|c| AnnotationKind::Context.span(c.span.into()).label(&c.value)),
278                    ),
279            ),
280            Group::with_title(Level::INFO.secondary_title(self.info)),
281        ]
282        .to_vec()
283    }
284
285    fn primary_span(&self) -> Span {
286        self.base_type
287    }
288
289    fn title(&self) -> Cow<'static, str> {
290        "invalid base type for enum".into()
291    }
292}
293
294#[derive(Debug)]
295pub struct EnumSizeBitsBiggerThanBaseType {
296    pub enum_name: Span,
297    pub base_type: Span,
298    pub enum_size_bits: u32,
299    pub base_type_size_bits: u32,
300}
301
302impl Diagnostic for EnumSizeBitsBiggerThanBaseType {
303    fn severity(&self) -> Severity {
304        Severity::Error
305    }
306
307    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
308        [
309            self.title_snippet().element(
310                Snippet::source(source)
311                    .path(path)
312                    .annotation(
313                        AnnotationKind::Primary
314                            .span(self.enum_name.into())
315                            .label(format!("enum is {} bits", self.enum_size_bits)),
316                    )
317                    .annotation(
318                        AnnotationKind::Primary
319                            .span(self.base_type.into())
320                            .label(format!("base type is {} bits", self.base_type_size_bits)),
321                    ),
322            ),
323            Group::with_title(
324                // TODO: Add patch for base type
325                Level::HELP.secondary_title("make the enum smaller or pick a bigger base type"),
326            ),
327        ]
328        .to_vec()
329    }
330
331    fn primary_span(&self) -> Span {
332        self.enum_name
333    }
334
335    fn title(&self) -> Cow<'static, str> {
336        "enum doesn't fit its base type".into()
337    }
338}
339
340#[derive(Debug)]
341pub struct EnumNoAutoBaseTypeSelected {
342    pub enum_name: Span,
343}
344
345impl Diagnostic for EnumNoAutoBaseTypeSelected {
346    fn severity(&self) -> Severity {
347        Severity::Error
348    }
349
350    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
351        const NOTE_TEXT: &str =
352            "a variant or the size-bits is too big to fit in any of the base types";
353
354        [
355            self.title_snippet().element(
356                Snippet::source(source).path(path).annotation(
357                    AnnotationKind::Primary
358                        .span(self.enum_name.into())
359                        .label("could not select a valid base type for this enum"),
360                ),
361            ),
362            Group::with_title(Level::NOTE.secondary_title(NOTE_TEXT)),
363        ]
364        .to_vec()
365    }
366
367    fn primary_span(&self) -> Span {
368        self.enum_name
369    }
370
371    fn title(&self) -> Cow<'static, str> {
372        "no valid base type found".into()
373    }
374}
375
376#[derive(Debug)]
377pub struct VariantValuesTooHigh {
378    pub variant_names: Vec<Span>,
379    pub enum_name: Span,
380    pub max_value: i128,
381    pub size_bits: u32,
382}
383
384impl Diagnostic for VariantValuesTooHigh {
385    fn severity(&self) -> Severity {
386        Severity::Error
387    }
388
389    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
390        [
391            self.title_snippet().element(
392                Snippet::source(source)
393                    .path(path)
394                    .annotation(
395                        AnnotationKind::Context
396                            .span(self.enum_name.into())
397                            .label(format!("enum is {} bits", self.size_bits)),
398                    )
399                    .annotations(self.variant_names.iter().map(|name| {
400                        AnnotationKind::Primary.span(name.into()).label(format!(
401                            "variant value exceeds the max of {} ({:#X})",
402                            self.max_value, self.max_value
403                        ))
404                    })),
405            ),
406            Group::with_title(Level::INFO.secondary_title("all variants must fit in their enum")),
407        ]
408        .to_vec()
409    }
410
411    fn primary_span(&self) -> Span {
412        self.variant_names[0]
413    }
414
415    fn title(&self) -> Cow<'static, str> {
416        "enum variant value is too high".into()
417    }
418}
419
420#[derive(Debug)]
421pub struct VariantValuesTooLow {
422    pub variant_names: Vec<Span>,
423    pub enum_name: Span,
424    pub min_value: i128,
425    pub size_bits: u32,
426}
427
428impl Diagnostic for VariantValuesTooLow {
429    fn severity(&self) -> Severity {
430        Severity::Error
431    }
432
433    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
434        [
435            Level::ERROR
436                .primary_title("enum variant value is too low")
437                .element(
438                    Snippet::source(source)
439                        .path(path)
440                        .annotation(
441                            AnnotationKind::Context
442                                .span(self.enum_name.into())
443                                .label(format!("enum is {} bits", self.size_bits)),
444                        )
445                        .annotations(self.variant_names.iter().map(|name| {
446                            AnnotationKind::Primary.span(name.into()).label(format!(
447                                "variant value exceeds the min of {}",
448                                self.min_value
449                            ))
450                        })),
451                ),
452            Group::with_title(Level::INFO.secondary_title("all variants must fit in their enum")),
453        ]
454        .to_vec()
455    }
456
457    fn primary_span(&self) -> Span {
458        self.variant_names[0]
459    }
460
461    fn title(&self) -> Cow<'static, str> {
462        "enum variant value is too low".into()
463    }
464}
465
466#[derive(Debug)]
467pub struct EnumMultipleDefaults {
468    pub enum_name: Span,
469    pub variant_names: Vec<Span>,
470}
471
472impl Diagnostic for EnumMultipleDefaults {
473    fn severity(&self) -> Severity {
474        Severity::Error
475    }
476
477    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
478        [
479            self.title_snippet().element(
480                Snippet::source(source)
481                    .path(path)
482                    .annotation(
483                        AnnotationKind::Context
484                            .span(self.enum_name.into())
485                            .label("offending enum"),
486                    )
487                    .annotations(self.variant_names.iter().enumerate().map(
488                        |(index, variant_name)| {
489                            if index == 0 {
490                                AnnotationKind::Context
491                                    .span(variant_name.into())
492                                    .label("first default variant")
493                            } else {
494                                AnnotationKind::Primary
495                                    .span(variant_name.into())
496                                    .label("extra default variant")
497                            }
498                        },
499                    )),
500            ),
501            Group::with_title(
502                Level::INFO.secondary_title("enums can have at most one default variant"),
503            ),
504        ]
505        .to_vec()
506    }
507
508    fn primary_span(&self) -> Span {
509        self.variant_names[1]
510    }
511
512    fn title(&self) -> Cow<'static, str> {
513        "enum defines more than one default variant".into()
514    }
515}
516
517#[derive(Debug)]
518pub struct EnumMultipleCatchalls {
519    pub enum_name: Span,
520    pub variant_names: Vec<Span>,
521}
522
523impl Diagnostic for EnumMultipleCatchalls {
524    fn severity(&self) -> Severity {
525        Severity::Error
526    }
527
528    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
529        [
530            self.title_snippet().element(
531                Snippet::source(source)
532                    .path(path)
533                    .annotation(
534                        AnnotationKind::Context
535                            .span(self.enum_name.into())
536                            .label("offending enum"),
537                    )
538                    .annotations(self.variant_names.iter().enumerate().map(
539                        |(index, variant_name)| {
540                            if index == 0 {
541                                AnnotationKind::Context
542                                    .span(variant_name.into())
543                                    .label("first catch-all variant")
544                            } else {
545                                AnnotationKind::Primary
546                                    .span(variant_name.into())
547                                    .label("extra catch-all variant")
548                            }
549                        },
550                    )),
551            ),
552            Group::with_title(
553                Level::INFO.secondary_title("enums can have at most one catch-all variant"),
554            ),
555        ]
556        .to_vec()
557    }
558
559    fn primary_span(&self) -> Span {
560        self.variant_names[1]
561    }
562
563    fn title(&self) -> Cow<'static, str> {
564        "enum defines more than one catch-all variant".into()
565    }
566}
567
568#[derive(Debug)]
569pub struct ReferencedObjectDoesNotExist {
570    pub object_reference: Span,
571}
572
573impl Diagnostic for ReferencedObjectDoesNotExist {
574    fn severity(&self) -> Severity {
575        Severity::Error
576    }
577
578    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
579        const INFO_TEXT: &str = "all objects must be specified in the manifest. It's possible a previous analysis step removed it due to some error. See the previous diagnostics";
580
581        [
582            self.title_snippet().element(
583                Snippet::source(source).path(path).annotation(
584                    AnnotationKind::Primary
585                        .span(self.object_reference.into())
586                        .label("object cannot be found"),
587                ),
588            ),
589            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
590        ]
591        .to_vec()
592    }
593
594    fn primary_span(&self) -> Span {
595        self.object_reference
596    }
597
598    fn title(&self) -> Cow<'static, str> {
599        "referenced object does not exist".into()
600    }
601}
602
603#[derive(Debug)]
604pub struct InvalidConversionType {
605    pub object_reference: Span,
606    pub referenced_object: Span,
607}
608
609impl Diagnostic for InvalidConversionType {
610    fn severity(&self) -> Severity {
611        Severity::Error
612    }
613
614    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
615        const NOTE_TEXT: &str = "the referenced object has an invalid type. Only enums and externs can be used for conversions";
616
617        [
618            self.title_snippet().element(
619                Snippet::source(source)
620                    .path(path)
621                    .annotation(
622                        AnnotationKind::Primary
623                            .span(self.object_reference.into())
624                            .label("object referenced as conversion type"),
625                    )
626                    .annotation(
627                        AnnotationKind::Context
628                            .span(self.referenced_object.into())
629                            .label("referenced object"),
630                    ),
631            ),
632            Group::with_title(Level::NOTE.secondary_title(NOTE_TEXT)),
633        ]
634        .to_vec()
635    }
636
637    fn primary_span(&self) -> Span {
638        self.object_reference
639    }
640
641    fn title(&self) -> Cow<'static, str> {
642        "object has invalid conversion type".into()
643    }
644}
645
646#[derive(Debug)]
647pub struct RepeatEnumWithCatchAll {
648    pub repeat_enum: Span,
649    pub enum_name: Span,
650    pub catch_all: Span,
651}
652
653impl Diagnostic for RepeatEnumWithCatchAll {
654    fn severity(&self) -> Severity {
655        Severity::Error
656    }
657
658    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
659        const INFO_TEXT: &str = "to be able to do all analysis passes correctly, the amount of repeats need to be statically known.
660This is not possible with an enum containing a catch-all since it can take on any value";
661
662        [
663            self.title_snippet().element(
664                Snippet::source(source)
665                    .path(path)
666                    .annotation(
667                        AnnotationKind::Primary
668                            .span(self.repeat_enum.into())
669                            .label("repeat uses enum with catch-all"),
670                    )
671                    .annotation(AnnotationKind::Visible.span(self.enum_name.into()))
672                    .annotation(
673                        AnnotationKind::Context
674                            .span(self.catch_all.into())
675                            .label("catch-all specified here"),
676                    ),
677            ),
678            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
679            Group::with_title(Level::HELP.secondary_title(
680                "remove the catch-all from the enum or don't use it as repeat source",
681            )),
682        ]
683        .to_vec()
684    }
685
686    fn primary_span(&self) -> Span {
687        self.repeat_enum
688    }
689
690    fn title(&self) -> Cow<'static, str> {
691        "enum with catch-all used as repeat source".into()
692    }
693}
694
695#[derive(Debug)]
696pub struct RepeatMathOverflow {
697    pub repeat_span: Span,
698    pub max_value_span: Span,
699    pub max_value: i128,
700    pub stride: i128,
701}
702
703impl Diagnostic for RepeatMathOverflow {
704    fn severity(&self) -> Severity {
705        Severity::Error
706    }
707
708    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
709        const INFO_TEXT: &str = "repeat math is done with `i32` integers to keep the runtime lean, so all calculations need to fit in a limited range";
710
711        [
712            self.title_snippet().element(
713                Snippet::source(source)
714                    .path(path)
715                    .annotation(AnnotationKind::Primary.span(self.repeat_span.into()).label(
716                        format!(
717                            "repeat calculation overflows the allowed `i32` range at {}",
718                            self.max_value * self.stride
719                        ),
720                    ))
721                    .annotation(
722                        AnnotationKind::Context
723                            .span(self.max_value_span.into())
724                            .label(format!("biggest index of {} specified here, which gets multiplied with the stride", self.max_value)),
725                    ),
726            ),
727            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
728        ]
729        .to_vec()
730    }
731
732    fn primary_span(&self) -> Span {
733        self.repeat_span
734    }
735
736    fn title(&self) -> Cow<'static, str> {
737        "repeat math overflow".into()
738    }
739}
740
741#[derive(Debug)]
742pub struct ExternInvalidBaseType {
743    pub extern_name: Span,
744    pub base_type: Option<Span>,
745}
746
747impl Diagnostic for ExternInvalidBaseType {
748    fn severity(&self) -> Severity {
749        Severity::Error
750    }
751
752    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
753        const INFO_TEXT: &str = "externs must specify a fixed size integer type as their base type";
754
755        [
756            self.title_snippet().element(
757                Snippet::source(source)
758                    .path(path)
759                    .annotation(
760                        if self.base_type.is_some() {
761                            AnnotationKind::Context
762                        } else {
763                            AnnotationKind::Primary
764                        }
765                        .span(self.extern_name.into())
766                        .label(if self.base_type.is_some() {
767                            "extern has an invalid base type"
768                        } else {
769                            "extern has no base type"
770                        }),
771                    )
772                    .annotations(self.base_type.map(|base_type| {
773                        AnnotationKind::Primary
774                            .span(base_type.into())
775                            .label("invalid base type")
776                    })),
777            ),
778            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
779        ]
780        .to_vec()
781    }
782
783    fn primary_span(&self) -> Span {
784        self.base_type.unwrap_or(self.extern_name)
785    }
786
787    fn title(&self) -> Cow<'static, str> {
788        "invalid base type for extern object".into()
789    }
790}
791
792#[derive(Debug)]
793pub struct ExternInvalidSizeBits {
794    pub extern_name: Span,
795    pub size_bits: Span,
796    pub reason: Cow<'static, str>,
797}
798
799impl Diagnostic for ExternInvalidSizeBits {
800    fn severity(&self) -> Severity {
801        Severity::Error
802    }
803
804    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
805        [self.title_snippet().element(
806            Snippet::source(source)
807                .path(path)
808                .annotation(
809                    AnnotationKind::Primary
810                        .span(self.size_bits.into())
811                        .label(&self.reason),
812                )
813                .annotation(AnnotationKind::Visible.span(self.extern_name.into())),
814        )]
815        .to_vec()
816    }
817
818    fn primary_span(&self) -> Span {
819        self.size_bits
820    }
821
822    fn title(&self) -> Cow<'static, str> {
823        "invalid size-bits value for extern object".into()
824    }
825}
826
827#[derive(Debug)]
828pub struct DifferentBaseTypes {
829    pub field: Span,
830    pub field_base_type: BaseType,
831    pub conversion: Span,
832    pub conversion_object: Span,
833    pub conversion_base_type: BaseType,
834}
835
836impl Diagnostic for DifferentBaseTypes {
837    fn severity(&self) -> Severity {
838        Severity::Error
839    }
840
841    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
842        const INFO_TEXT: &str = "conversions can only happen when the same base type is shared";
843
844        [
845            self.title_snippet().element(
846                Snippet::source(source)
847                    .path(path)
848                    .annotation(
849                        AnnotationKind::Context
850                            .span(self.conversion.into())
851                            .label("conversion specified here"),
852                    )
853                    .annotation(
854                        AnnotationKind::Primary
855                            .span(self.field.into())
856                            .label(format!("field uses base type: {}", self.field_base_type)),
857                    )
858                    .annotation(
859                        AnnotationKind::Primary
860                            .span(self.conversion_object.into())
861                            .label(format!(
862                                "conversion object uses base type: {}",
863                                self.conversion_base_type
864                            )),
865                    ),
866            ),
867            // TODO: Add help with patch
868            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
869        ]
870        .to_vec()
871    }
872
873    fn primary_span(&self) -> Span {
874        self.field
875    }
876
877    fn title(&self) -> Cow<'static, str> {
878        "field and conversion use different base types".into()
879    }
880}
881
882// TODO: Split in multiple error types
883#[derive(Debug)]
884pub struct InvalidInfallibleConversion {
885    pub field: Span,
886    pub conversion: Span,
887    pub context: Vec<Spanned<Cow<'static, str>>>,
888    pub existing_type_specifier_content: String,
889}
890
891impl Diagnostic for InvalidInfallibleConversion {
892    fn severity(&self) -> Severity {
893        Severity::Error
894    }
895
896    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
897        [
898            self.title_snippet().element(
899                Snippet::source(source)
900                    .path(path)
901                    .annotation(
902                        AnnotationKind::Primary
903                            .span(self.conversion.into())
904                            .label("conversion specified here"),
905                    )
906                    .annotations(
907                        self.context
908                            .iter()
909                            .map(|c| AnnotationKind::Context.span(c.span.into()).label(&c.value)),
910                    )
911                    .annotation(AnnotationKind::Visible.span(self.field.into())),
912            ),
913            // TODO: Add patch
914            Group::with_title(Level::HELP.secondary_title("mark the conversion fallible")),
915            Group::with_title(
916                Level::HELP
917                    .secondary_title("make the conversion type support infallible conversion"),
918            ),
919        ]
920        .to_vec()
921    }
922
923    fn primary_span(&self) -> Span {
924        self.conversion
925    }
926
927    fn title(&self) -> Cow<'static, str> {
928        "invalid infallible conversion".into()
929    }
930}
931
932#[derive(Debug)]
933pub struct ConversionTypeTooBig {
934    pub field: Span,
935    pub field_address: Span,
936    pub conversion_type: Span,
937    pub conversion: Span,
938    pub field_len: u64,
939    pub conversion_len: u64,
940}
941
942impl Diagnostic for ConversionTypeTooBig {
943    fn severity(&self) -> Severity {
944        Severity::Error
945    }
946
947    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
948        const INFO_TEXT: &str = "a field can only convert to types of equal length or smaller";
949
950        [
951            self.title_snippet().element(
952                Snippet::source(source)
953                    .path(path)
954                    .annotation(AnnotationKind::Visible.span(self.field.into()))
955                    .annotation(
956                        AnnotationKind::Primary
957                            .span(self.field_address.into())
958                            .label(format!("field is {} bits", self.field_len)),
959                    )
960                    .annotation(
961                        AnnotationKind::Primary
962                            .span(self.conversion_type.into())
963                            .label(format!("target type is {} bits", self.conversion_len)),
964                    )
965                    .annotation(
966                        AnnotationKind::Context
967                            .span(self.conversion.into())
968                            .label("field specifies a conversion type here"),
969                    ),
970            ),
971            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
972        ]
973        .to_vec()
974    }
975
976    fn primary_span(&self) -> Span {
977        self.field_address
978    }
979
980    fn title(&self) -> Cow<'static, str> {
981        "conversion type too big for field".into()
982    }
983}
984
985#[derive(Debug)]
986pub struct UnspecifiedByteOrder {
987    pub fieldset_name: Span,
988    pub properties_span: Option<Span>,
989}
990
991impl Diagnostic for UnspecifiedByteOrder {
992    fn severity(&self) -> Severity {
993        Severity::Error
994    }
995
996    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
997        [
998            self.title_snippet()
999                .element(
1000                    Snippet::source(source).path(path).annotation(
1001                        AnnotationKind::Primary
1002                            .span(self.fieldset_name.into())
1003                            .label("fieldset requires a byte order, but none is specified"),
1004                    ),
1005                ),
1006            Level::HELP.secondary_title(
1007                "specify the byte order on the fieldset or add a default byte order on the device",
1008            )
1009            .elements( self.properties_span.map(|properties_span| {
1010                Snippet::source(source).path(path).patch(
1011                    Patch::new(properties_span.collapse_to_start().into(), "byte-order: LE,\n")
1012                )}
1013            )),
1014            Group::with_title(Level::NOTE.secondary_title(
1015                "the fieldset spans multiple bytes, so it needs to have byte ordering specified",
1016            )),
1017            Group::with_title(Level::INFO.secondary_title(
1018                "byte order is important for any multi-byte value. It has no default, so it needs to be manually specified",
1019            )),
1020        ]
1021        .to_vec()
1022    }
1023
1024    fn primary_span(&self) -> Span {
1025        self.fieldset_name
1026    }
1027
1028    fn title(&self) -> Cow<'static, str> {
1029        "fieldset needs byte order specified".into()
1030    }
1031}
1032
1033#[derive(Debug)]
1034pub struct UnspecifiedAccess {
1035    pub object_name: Span,
1036    pub short_property: bool,
1037    pub properties_span: Option<Span>,
1038}
1039
1040impl Diagnostic for UnspecifiedAccess {
1041    fn severity(&self) -> Severity {
1042        Severity::Error
1043    }
1044
1045    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1046        [
1047            self.title_snippet().element(
1048                Snippet::source(source).path(path).annotation(
1049                    AnnotationKind::Primary
1050                        .span(self.object_name.into())
1051                        .label("object requires an access to be specified, but none is"),
1052                ),
1053            ),
1054            Level::HELP
1055                .secondary_title(
1056                    "specify the access on the object or add a `default-access` to a parent object",
1057                )
1058                .elements(self.properties_span.map(|properties_span| {
1059                    Snippet::source(source).path(path).patch(Patch::new(
1060                        if self.short_property {
1061                            properties_span.collapse_to_end().into()
1062                        } else {
1063                            properties_span.collapse_to_start().into()
1064                        },
1065                        if self.short_property {
1066                            " RW"
1067                        } else {
1068                            "access: RW,\n"
1069                        },
1070                    ))
1071                })),
1072        ]
1073        .to_vec()
1074    }
1075
1076    fn primary_span(&self) -> Span {
1077        self.object_name
1078    }
1079
1080    fn title(&self) -> Cow<'static, str> {
1081        "object needs access specified".into()
1082    }
1083}
1084
1085#[derive(Debug)]
1086pub struct ResetValueIntTooBig {
1087    pub register_context: Span,
1088    pub reset_value: Span,
1089    pub reset_value_size_bytes: u32,
1090    pub register_size_bytes: u32,
1091}
1092
1093impl Diagnostic for ResetValueIntTooBig {
1094    fn severity(&self) -> Severity {
1095        Severity::Error
1096    }
1097
1098    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1099        const INFO_TEXT: &str = "reset values cannot be bigger than their fieldset";
1100
1101        [
1102            self.title_snippet().element(
1103                Snippet::source(source)
1104                    .path(path)
1105                    .annotation(AnnotationKind::Primary.span(self.reset_value.into()).label(
1106                        format!(
1107                            "the reset value is specified with {} bytes, but the register only has {}",
1108                            self.reset_value_size_bytes, self.register_size_bytes
1109                        ),
1110                    ))
1111                    .annotation(AnnotationKind::Visible.span(self.register_context.into())),
1112            ),
1113            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
1114        ]
1115        .to_vec()
1116    }
1117
1118    fn primary_span(&self) -> Span {
1119        self.reset_value
1120    }
1121
1122    fn title(&self) -> Cow<'static, str> {
1123        "reset value too big for register".into()
1124    }
1125}
1126
1127#[derive(Debug)]
1128pub struct ResetValueArrayWrongSize {
1129    pub register_context: Span,
1130    pub reset_value: Span,
1131    pub reset_value_size_bytes: u32,
1132    pub register_size_bytes: u32,
1133}
1134
1135impl Diagnostic for ResetValueArrayWrongSize {
1136    fn severity(&self) -> Severity {
1137        Severity::Error
1138    }
1139
1140    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1141        const INFO_TEXT: &str = "reset values must have the same size as their associated register";
1142
1143        [
1144            self.title_snippet().element(
1145                Snippet::source(source)
1146                    .path(path)
1147                    .annotation(AnnotationKind::Primary.span(self.reset_value.into()).label(
1148                        format!(
1149                            "the reset value is specified with {} bytes while the register has {}",
1150                            self.reset_value_size_bytes, self.register_size_bytes
1151                        ),
1152                    ))
1153                    .annotation(AnnotationKind::Visible.span(self.register_context.into())),
1154            ),
1155            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
1156        ]
1157        .to_vec()
1158    }
1159
1160    fn primary_span(&self) -> Span {
1161        self.reset_value
1162    }
1163
1164    fn title(&self) -> Cow<'static, str> {
1165        "reset value wrong size".into()
1166    }
1167}
1168
1169#[derive(Debug)]
1170pub struct BoolFieldTooLarge {
1171    pub base_type: Option<Span>,
1172    pub address: Span,
1173    pub address_bits: u32,
1174    pub address_start: u32,
1175    pub field_set_context: Span,
1176}
1177
1178impl Diagnostic for BoolFieldTooLarge {
1179    fn severity(&self) -> Severity {
1180        Severity::Error
1181    }
1182
1183    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1184        [
1185            self.title_snippet().element(
1186                Snippet::source(source).path(path).annotations(
1187                    [
1188                        Some(
1189                            AnnotationKind::Primary
1190                                .span(self.address.into())
1191                                .label(format!("address is {} bits", self.address_bits)),
1192                        ),
1193                        self.base_type.map(|base_type| {
1194                            AnnotationKind::Context
1195                                .span(base_type.into())
1196                                .label("bool base type set here")
1197                        }),
1198                        Some(AnnotationKind::Visible.span(self.field_set_context.into())),
1199                    ]
1200                    .into_iter()
1201                    .flatten(),
1202                ),
1203            ),
1204            Level::HELP
1205                .secondary_title("a field with a `bool` base type can only be 1 bit large")
1206                .element(Snippet::source(source).path(path).patch(Patch::new(
1207                    self.address.into(),
1208                    format!("{}:{}", self.address_start, self.address_start),
1209                )))
1210                .element(Snippet::source(source).path(path).patch(Patch::new(
1211                    self.address.into(),
1212                    format!("{}", self.address_start),
1213                ))),
1214        ]
1215        .to_vec()
1216    }
1217
1218    fn primary_span(&self) -> Span {
1219        self.address
1220    }
1221
1222    fn title(&self) -> Cow<'static, str> {
1223        "bool field too large".into()
1224    }
1225}
1226
1227#[derive(Debug)]
1228pub struct FieldAddressExceedsFieldsetSize {
1229    pub address: Span,
1230    pub max_field_end: i128,
1231    pub repeat_offset: Option<i128>,
1232    pub fieldset_size_span: Span,
1233    pub fieldset_size_bits: u32,
1234}
1235
1236impl FieldAddressExceedsFieldsetSize {
1237    fn get_repeat_message(&self) -> String {
1238        match self.repeat_offset {
1239            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}"),
1240            None => String::new(),
1241        }
1242    }
1243}
1244
1245impl Diagnostic for FieldAddressExceedsFieldsetSize {
1246    fn severity(&self) -> Severity {
1247        Severity::Error
1248    }
1249
1250    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1251        [
1252            self.title_snippet().element(
1253                Snippet::source(source)
1254                    .path(path)
1255                    .annotation(
1256                        AnnotationKind::Primary
1257                            .span(self.address.into())
1258                            .label(format!(
1259                                "address goes up to {}{}",
1260                                self.max_field_end,
1261                                self.get_repeat_message()
1262                            )),
1263                    )
1264                    .annotation(
1265                        AnnotationKind::Context
1266                            .span(self.fieldset_size_span.into())
1267                            .label(format!(
1268                                "The fieldset is only {} bits",
1269                                self.fieldset_size_bits
1270                            )),
1271                    ),
1272            ),
1273            Group::with_title(Level::INFO.secondary_title(
1274                "fields, including all repeats, must be fully contained in a fieldset",
1275            )),
1276        ]
1277        .to_vec()
1278    }
1279
1280    fn primary_span(&self) -> Span {
1281        self.address
1282    }
1283
1284    fn title(&self) -> Cow<'static, str> {
1285        "field address exceeds fieldset size".into()
1286    }
1287}
1288
1289#[derive(Debug)]
1290pub struct FieldAddressNegative {
1291    pub address: Span,
1292    pub min_field_start: i128,
1293    pub repeat_offset: Option<i128>,
1294    pub field_set_context: Span,
1295}
1296
1297impl FieldAddressNegative {
1298    fn get_repeat_message(&self) -> Cow<'static, str> {
1299        match self.repeat_offset {
1300            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}").into(),
1301            None => "".into(),
1302        }
1303    }
1304}
1305
1306impl Diagnostic for FieldAddressNegative {
1307    fn severity(&self) -> Severity {
1308        Severity::Error
1309    }
1310
1311    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1312        [
1313            self.title_snippet().element(
1314                Snippet::source(source)
1315                    .path(path)
1316                    .annotation(
1317                        AnnotationKind::Primary
1318                            .span(self.address.into())
1319                            .label(format!(
1320                                "address goes down to {}{}",
1321                                self.min_field_start,
1322                                self.get_repeat_message()
1323                            )),
1324                    )
1325                    .annotation(AnnotationKind::Visible.span(self.field_set_context.into())),
1326            ),
1327            Group::with_title(Level::INFO.secondary_title(
1328                "fields, including all repeats, must be fully contained in a fieldset",
1329            )),
1330        ]
1331        .to_vec()
1332    }
1333
1334    fn primary_span(&self) -> Span {
1335        self.address
1336    }
1337
1338    fn title(&self) -> Cow<'static, str> {
1339        "field address is negative".into()
1340    }
1341}
1342
1343#[derive(Debug)]
1344pub struct OverlappingFields {
1345    pub field_address_1: Span,
1346    pub repeat_offset_1: Option<i128>,
1347    pub field_address_start_1: i128,
1348    pub field_address_end_1: i128,
1349    pub field_address_2: Span,
1350    pub repeat_offset_2: Option<i128>,
1351    pub field_address_start_2: i128,
1352    pub field_address_end_2: i128,
1353
1354    pub field_set_context: Span,
1355}
1356
1357impl OverlappingFields {
1358    fn get_repeat_message_1(&self) -> Cow<'static, str> {
1359        match self.repeat_offset_1 {
1360            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}").into(),
1361            None => "".into(),
1362        }
1363    }
1364    fn get_repeat_message_2(&self) -> Cow<'static, str> {
1365        match self.repeat_offset_2 {
1366            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}").into(),
1367            None => "".into(),
1368        }
1369    }
1370}
1371
1372impl Diagnostic for OverlappingFields {
1373    fn severity(&self) -> Severity {
1374        Severity::Warning
1375    }
1376
1377    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1378        const HELP_TEXT: &str = "if overlap is intended, the warning can be suppressed by adding the bit-overlap property to the fieldset";
1379        const INFO_TEXT: &str = "overlapping fields are usually the result of a copy paste mistake. This warning exists to alert to that possibility";
1380
1381        [
1382            self.title_snippet().element(
1383                Snippet::source(source)
1384                    .path(path)
1385                    .annotation(
1386                        AnnotationKind::Primary
1387                            .span(self.field_address_1.into())
1388                            .label(format!(
1389                                "field sits at address range @{}:{}{}",
1390                                self.field_address_end_1 - 1,
1391                                self.field_address_start_1,
1392                                self.get_repeat_message_1()
1393                            )),
1394                    )
1395                    .annotation(
1396                        AnnotationKind::Primary
1397                            .span(self.field_address_2.into())
1398                            .label(format!(
1399                                "field sits at address range @{}:{}{}",
1400                                self.field_address_end_2 - 1,
1401                                self.field_address_start_2,
1402                                self.get_repeat_message_2()
1403                            )),
1404                    )
1405                    .annotation(AnnotationKind::Visible.span(self.field_set_context.into())),
1406                // TODO: Add context annotation for where the repeats are defined
1407            ),
1408            // TODO: Add patch
1409            Group::with_title(Level::HELP.secondary_title(HELP_TEXT)),
1410            Group::with_title(Level::NOTE.secondary_title(INFO_TEXT)),
1411        ]
1412        .to_vec()
1413    }
1414
1415    fn primary_span(&self) -> Span {
1416        self.field_address_2
1417    }
1418
1419    fn title(&self) -> Cow<'static, str> {
1420        "overlapping fields".into()
1421    }
1422}
1423
1424#[derive(Debug)]
1425pub struct AddressTypeUndefined {
1426    pub object_name: Span,
1427    pub device: Span,
1428    pub properties_span: Option<Span>,
1429    pub object_type: &'static str,
1430}
1431
1432impl Diagnostic for AddressTypeUndefined {
1433    fn severity(&self) -> Severity {
1434        Severity::Error
1435    }
1436
1437    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1438        vec![
1439            self.title_snippet().element(
1440                Snippet::source(source)
1441                    .path(path)
1442                    .annotation(
1443                        AnnotationKind::Primary
1444                            .span(self.device.into())
1445                            .label(format!(
1446                                "this device doesn't define a {}-address-type",
1447                                self.object_type
1448                            )),
1449                    )
1450                    .annotation(
1451                        AnnotationKind::Context
1452                            .span(self.object_name.into())
1453                            .label(format!("{} object defined here", self.object_type)),
1454                    ),
1455            ),
1456            Level::HELP.secondary_title(
1457                "add the address type as a global default or as config on the device the object is defined in"
1458            ).elements(
1459                self.properties_span.map(|properties_span| {
1460                    Snippet::source(source).path(path).patch(
1461                        Patch::new(properties_span.collapse_to_start().into(), format!("{}-address-type: u16\n", self.object_type))
1462                    )
1463                })
1464            ),
1465            Group::with_title(
1466                Level::INFO.secondary_title("device-driver is agnostic to the address types being used. As such, it must be manually specified")
1467            ),
1468        ]
1469    }
1470
1471    fn primary_span(&self) -> Span {
1472        self.device
1473    }
1474
1475    fn title(&self) -> Cow<'static, str> {
1476        format!("{} address type not defined", self.object_type).into()
1477    }
1478}
1479
1480#[derive(Debug)]
1481pub struct AddressOutOfRange {
1482    pub object: Span,
1483    pub address: Span,
1484    pub address_value_min: i128,
1485    pub address_value_max: i128,
1486    pub address_type_config: Span,
1487    pub address_type: Integer,
1488}
1489
1490impl Diagnostic for AddressOutOfRange {
1491    fn severity(&self) -> Severity {
1492        Severity::Error
1493    }
1494
1495    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1496        vec![
1497            self.title_snippet()
1498                .element(
1499                    Snippet::source(source)
1500                        .path(path)
1501                        .annotation(AnnotationKind::Primary.span(self.address.into()).label(
1502                            if self.address_value_min == self.address_value_max {
1503                                format!("address has value: {}", self.address_value_max)
1504                            } else {
1505                                format!(
1506                                    "address ranges from {} to {}",
1507                                    self.address_value_min, self.address_value_max
1508                                )
1509                            },
1510                        ))
1511                        .annotation(AnnotationKind::Visible.span(self.object.into())),
1512                )
1513                .element(
1514                    Snippet::source(source).path(path).annotation(
1515                        AnnotationKind::Context
1516                            .span(self.address_type_config.into())
1517                            .label(format!(
1518                                "address type supports a range of {} to {}",
1519                                self.address_type.min_value(),
1520                                self.address_type.max_value()
1521                            )),
1522                    ),
1523                ),
1524            if let Some(fitting_integer) =
1525                Integer::find_smallest(self.address_value_min, self.address_value_max, 0)
1526            {
1527                Level::HELP
1528                    .secondary_title("use an address type that fits the whole range being used")
1529                    .element(Snippet::source(source).path(path).patch(Patch::new(
1530                        self.address_type_config.into(),
1531                        fitting_integer.to_string(),
1532                    )))
1533            } else {
1534                Group::with_title(
1535                    Level::HELP
1536                        .secondary_title("address is too big to fit any possible address type"),
1537                )
1538            },
1539        ]
1540    }
1541
1542    fn primary_span(&self) -> Span {
1543        self.address
1544    }
1545
1546    fn title(&self) -> Cow<'static, str> {
1547        format!(
1548            "address out of range for address type {}",
1549            self.address_type
1550        )
1551        .into()
1552    }
1553}
1554
1555#[derive(Debug)]
1556pub struct AddressOverlap {
1557    pub address: i128,
1558    pub object_1: Span,
1559    pub object_1_address: Span,
1560    pub object_1_size: Span,
1561    pub repeat_offset_1: Option<i128>,
1562    pub object_2: Span,
1563    pub object_2_address: Span,
1564    pub object_2_size: Span,
1565    pub repeat_offset_2: Option<i128>,
1566}
1567
1568impl Diagnostic for AddressOverlap {
1569    fn severity(&self) -> Severity {
1570        Severity::Warning
1571    }
1572
1573    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1574        let object_1_message = format!(
1575            "object 1 overlaps with other object 2{}",
1576            if let Some(repeat_offset) = self.repeat_offset_1 {
1577                format!(" at repeat offset {repeat_offset}")
1578            } else {
1579                String::new()
1580            }
1581        );
1582        let object_2_message = format!(
1583            "object 2 overlaps with other object 1{}",
1584            if let Some(repeat_offset) = self.repeat_offset_2 {
1585                format!(" at repeat offset {repeat_offset}")
1586            } else {
1587                String::new()
1588            }
1589        );
1590
1591        const HELP_TEXT: &str = "if overlap is intended, the warning can be suppressed by allowing overlap on both objects";
1592        const INFO_TEXT: &str = "overlapping objects are usually the result of a copy paste mistake. This warning exists to alert to that possibility";
1593
1594        [
1595            self.title_snippet()
1596                .element(
1597                    Snippet::source(source)
1598                        .path(path)
1599                        .annotation(
1600                            AnnotationKind::Primary
1601                                .span(self.object_1.into())
1602                                .label(object_1_message),
1603                        )
1604                        .annotation(
1605                            AnnotationKind::Context
1606                                .span(self.object_1_address.into())
1607                                .label("address 1 set here"),
1608                        )
1609                        .annotations(
1610                            (!self.object_1_size.is_empty()).then_some(
1611                                AnnotationKind::Context
1612                                    .span(self.object_1_size.into())
1613                                    .label("size 1 set here"),
1614                            ),
1615                        ), // TODO: Add context annotation for where the repeat is defined
1616                )
1617                .element(
1618                    Snippet::source(source)
1619                        .path(path)
1620                        .annotation(
1621                            AnnotationKind::Primary
1622                                .span(self.object_2.into())
1623                                .label(object_2_message),
1624                        )
1625                        .annotation(
1626                            AnnotationKind::Context
1627                                .span(self.object_2_address.into())
1628                                .label("address 2 set here"),
1629                        )
1630                        .annotations(
1631                            (!self.object_2_size.is_empty()).then_some(
1632                                AnnotationKind::Context
1633                                    .span(self.object_2_size.into())
1634                                    .label("size 2 set here"),
1635                            ),
1636                        ), // TODO: Add context annotation for where the repeat is defined
1637                ),
1638            // TODO: Add patch
1639            Group::with_title(Level::HELP.secondary_title(HELP_TEXT)),
1640            Group::with_title(Level::NOTE.secondary_title(INFO_TEXT)),
1641        ]
1642        .to_vec()
1643    }
1644
1645    fn primary_span(&self) -> Span {
1646        self.object_2
1647    }
1648
1649    fn title(&self) -> Cow<'static, str> {
1650        format!("address overlap at {} ({:#X})", self.address, self.address).into()
1651    }
1652}
1653
1654#[derive(Debug)]
1655pub struct InvalidIdentifier {
1656    pub error: identifier::Error,
1657    pub identifier: Span,
1658}
1659
1660impl InvalidIdentifier {
1661    pub fn new(error: identifier::Error, identifier: Span) -> Self {
1662        Self { error, identifier }
1663    }
1664}
1665
1666impl Diagnostic for InvalidIdentifier {
1667    fn severity(&self) -> Severity {
1668        Severity::Error
1669    }
1670
1671    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1672        const INFO_TEXT: &str = "identifiers are split into words using the 'word-boundaries'.\n\
1673After the split the first character of the first word must be a unicode XID start character.\n\
1674All other characters must be a unicode XID continue character.\n\
1675\n\
1676Identifiers must also be able to be converted to different casings. That means the split words must not contain `-` or `_`,\n\
1677which in practice means the word-boundaries should always include those characters.";
1678
1679        let annotation = match &self.error {
1680            identifier::Error::Empty => AnnotationKind::Primary
1681                .span(self.identifier.into())
1682                .label("identifier is empty"),
1683            identifier::Error::EmptyAfterSplits => AnnotationKind::Primary
1684                .span(self.identifier.into())
1685                .label("identifier is empty after word split"),
1686            identifier::Error::InvalidCharacter {
1687                byte_offset: offset,
1688                invalid_char: character,
1689            } if !self.identifier.is_empty() => AnnotationKind::Primary
1690                .span(
1691                    self.identifier.start as usize + offset
1692                        ..self.identifier.start as usize + offset + character.len_utf8(),
1693                )
1694                .label(format!(
1695                    "`{character}` (or `{}`) is not a valid character",
1696                    character.escape_unicode()
1697                )),
1698            identifier::Error::InvalidCharacter {
1699                byte_offset: _,
1700                invalid_char: character,
1701            } => AnnotationKind::Primary
1702                .span(self.identifier.into())
1703                .label(format!(
1704                    "`{character}` (or `{}`) is not a valid character",
1705                    character.escape_unicode()
1706                )),
1707            e @ identifier::Error::CannotConvert { .. } => AnnotationKind::Primary
1708                .span(self.identifier.into())
1709                .label(e.to_string()),
1710        };
1711
1712        [
1713            self.title_snippet()
1714                .element(Snippet::source(source).path(path).annotation(annotation)),
1715            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
1716        ]
1717        .to_vec()
1718    }
1719
1720    fn primary_span(&self) -> Span {
1721        self.identifier
1722    }
1723
1724    fn title(&self) -> Cow<'static, str> {
1725        "invalid identifier".into()
1726    }
1727}
1728
1729#[derive(Debug)]
1730pub struct InvalidAutoIdentifier {
1731    pub auto_identifier: Span,
1732}
1733
1734impl Diagnostic for InvalidAutoIdentifier {
1735    fn severity(&self) -> Severity {
1736        Severity::Error
1737    }
1738
1739    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1740        const INFO_TEXT: &str = "auto identifiers can only be used in places where there's a parent node of which the name can be taken";
1741
1742        [
1743            self.title_snippet().element(
1744                Snippet::source(source).path(path).annotation(
1745                    AnnotationKind::Primary
1746                        .span(self.auto_identifier.into())
1747                        .label("auto identifier can't be used here"),
1748                ),
1749            ),
1750            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
1751        ]
1752        .to_vec()
1753    }
1754
1755    fn primary_span(&self) -> Span {
1756        self.auto_identifier
1757    }
1758
1759    fn title(&self) -> Cow<'static, str> {
1760        "invalid identifier".into()
1761    }
1762}
1763
1764#[derive(Debug)]
1765pub struct ParsingError {
1766    pub reason: String,
1767    pub span: Span,
1768}
1769
1770impl Diagnostic for ParsingError {
1771    fn severity(&self) -> Severity {
1772        Severity::Error
1773    }
1774
1775    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1776        [Level::ERROR.primary_title("parsing error").element(
1777            Snippet::source(source).path(path).annotation(
1778                AnnotationKind::Primary
1779                    .span(self.span.into())
1780                    .label(&self.reason),
1781            ),
1782        )]
1783        .to_vec()
1784    }
1785
1786    fn primary_span(&self) -> Span {
1787        self.span
1788    }
1789
1790    fn title(&self) -> Cow<'static, str> {
1791        format!("parsing error: {}", self.reason).into()
1792    }
1793}
1794
1795#[derive(Debug)]
1796pub struct UnknownNodeType {
1797    pub node_type: Span,
1798    pub allowed_node_types: Vec<NodeType>,
1799}
1800
1801impl Diagnostic for UnknownNodeType {
1802    fn severity(&self) -> Severity {
1803        Severity::Error
1804    }
1805
1806    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1807        [self.title_snippet().element(
1808            Snippet::source(source).path(path).annotation(
1809                AnnotationKind::Primary
1810                    .span(self.node_type.into())
1811                    .label(format!(
1812                        "expected one of: {}",
1813                        self.allowed_node_types.iter().join(", ")
1814                    )),
1815            ),
1816        )]
1817        .to_vec()
1818    }
1819
1820    fn primary_span(&self) -> Span {
1821        self.node_type
1822    }
1823
1824    fn title(&self) -> Cow<'static, str> {
1825        "unknown node type".into()
1826    }
1827}
1828
1829#[derive(Debug)]
1830pub struct InvalidPropertyName {
1831    pub property: Span,
1832    pub node_type: Spanned<NodeType>,
1833    pub expected_names: Vec<Istr>,
1834}
1835
1836impl Diagnostic for InvalidPropertyName {
1837    fn severity(&self) -> Severity {
1838        Severity::Error
1839    }
1840
1841    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1842        [self
1843            .title_snippet()
1844            .element(Snippet::source(source).path(path).annotation(
1845                AnnotationKind::Primary.span(self.property.into()).label(
1846                    if self.expected_names.is_empty() {
1847                        "no named properties are expected".into()
1848                    } else {
1849                        format!("expected one of: {}", self.expected_names.join(", "))
1850                    },
1851                ),
1852            ))]
1853        .to_vec()
1854    }
1855
1856    fn primary_span(&self) -> Span {
1857        self.property
1858    }
1859
1860    fn title(&self) -> Cow<'static, str> {
1861        format!("invalid property name for `{}` nodes", self.node_type).into()
1862    }
1863}
1864
1865#[derive(Debug)]
1866pub struct InvalidExpressionType {
1867    pub expression: Spanned<String>,
1868    pub node_type: Spanned<NodeType>,
1869    pub valid_expression_types: Vec<String>,
1870    pub valid_expression_values: Vec<Cow<'static, str>>,
1871}
1872
1873impl Diagnostic for InvalidExpressionType {
1874    fn severity(&self) -> Severity {
1875        Severity::Error
1876    }
1877
1878    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1879        let mut report = [self.title_snippet().element(
1880            Snippet::source(source).path(path).annotation(
1881                AnnotationKind::Primary
1882                    .span(self.expression.span.into())
1883                    .label(format!(
1884                        "got {}, expected one of: {}",
1885                        self.expression,
1886                        self.valid_expression_types.join(", ")
1887                    )),
1888            ),
1889        )]
1890        .to_vec();
1891
1892        for (name, value) in self
1893            .valid_expression_types
1894            .iter()
1895            .zip(&self.valid_expression_values)
1896        {
1897            report.push(
1898                Level::HELP
1899                    .secondary_title(format!("change to a {name} expression"))
1900                    .element(
1901                        Snippet::source(source)
1902                            .path(path)
1903                            .patch(Patch::new(self.expression.span.into(), &**value)),
1904                    ),
1905            );
1906        }
1907
1908        report
1909    }
1910
1911    fn primary_span(&self) -> Span {
1912        self.expression.span
1913    }
1914
1915    fn title(&self) -> Cow<'static, str> {
1916        format!(
1917            "invalid expression type for this property in {} nodes",
1918            self.node_type
1919        )
1920        .into()
1921    }
1922}
1923
1924#[derive(Debug)]
1925pub struct DuplicateProperty {
1926    pub original: Span,
1927    pub duplicate: Span,
1928}
1929
1930impl Diagnostic for DuplicateProperty {
1931    fn severity(&self) -> Severity {
1932        Severity::Error
1933    }
1934
1935    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1936        [self.title_snippet().element(
1937            Snippet::source(source)
1938                .path(path)
1939                .annotation(
1940                    AnnotationKind::Context
1941                        .span(self.original.into())
1942                        .label("first occurrence"),
1943                )
1944                .annotation(
1945                    AnnotationKind::Primary
1946                        .span(self.duplicate.into())
1947                        .label("duplicate"),
1948                ),
1949        )]
1950        .to_vec()
1951    }
1952
1953    fn primary_span(&self) -> Span {
1954        self.duplicate
1955    }
1956
1957    fn title(&self) -> Cow<'static, str> {
1958        "duplicate property".into()
1959    }
1960}
1961
1962#[derive(Debug)]
1963pub struct InvalidNodeType {
1964    pub node_type: Span,
1965    pub parent_node_type: Option<Spanned<NodeType>>,
1966    pub allowed_node_types: Vec<NodeType>,
1967}
1968
1969impl Diagnostic for InvalidNodeType {
1970    fn severity(&self) -> Severity {
1971        Severity::Error
1972    }
1973
1974    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1975        [
1976            self.title_snippet().element(
1977                Snippet::source(source)
1978                    .path(path)
1979                    .annotation(
1980                        AnnotationKind::Primary.span(self.node_type.into()).label(
1981                            if let Some(parent_node_type) = self.parent_node_type {
1982                                format!(
1983                                    "node type can't be used as a sub-node of a {parent_node_type}",
1984                                )
1985                            } else {
1986                                "node type can't be used as the root".into()
1987                            },
1988                        ),
1989                    )
1990                    .annotations(self.parent_node_type.map(|pnt| {
1991                        AnnotationKind::Context
1992                            .span(pnt.span.into())
1993                            .label("in this node")
1994                    })),
1995            ),
1996            Group::with_title(Level::NOTE.secondary_title(format!(
1997                "valid node types are: {}",
1998                self.allowed_node_types.iter().join(", ")
1999            ))),
2000        ]
2001        .to_vec()
2002    }
2003
2004    fn primary_span(&self) -> Span {
2005        self.node_type
2006    }
2007
2008    fn title(&self) -> Cow<'static, str> {
2009        "invalid node type".into()
2010    }
2011}
2012
2013#[derive(Debug)]
2014pub struct MissingRequiredProperty {
2015    pub node_type: Spanned<NodeType>,
2016    pub property_name: String,
2017    pub short: bool,
2018    pub allowed_property_types: Vec<String>,
2019    pub example_values: Vec<Cow<'static, str>>,
2020    pub properties_span: Option<Span>,
2021}
2022
2023impl Diagnostic for MissingRequiredProperty {
2024    fn severity(&self) -> Severity {
2025        Severity::Error
2026    }
2027
2028    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2029        let label = if self.short {
2030            format!(
2031                "missing short property for `{}`, with one of these expression types: {}",
2032                self.property_name,
2033                self.allowed_property_types.join(", ")
2034            )
2035        } else {
2036            format!(
2037                "missing property `{}`, with one of these expression types: {}",
2038                self.property_name,
2039                self.allowed_property_types.join(", ")
2040            )
2041        };
2042
2043        [self
2044            .title_snippet()
2045            .element(
2046                Snippet::source(source).path(path).annotation(
2047                    AnnotationKind::Primary
2048                        .span(self.node_type.span.into())
2049                        .label(label),
2050                ),
2051            )
2052            .elements(self.example_values.iter().flat_map(|example_value| {
2053                self.properties_span.map(|properties_span| {
2054                    Snippet::source(source).path(path).patch(Patch::new(
2055                        if self.short {
2056                            properties_span.collapse_to_end().into()
2057                        } else {
2058                            properties_span.collapse_to_start().into()
2059                        },
2060                        if self.short {
2061                            format!(" {example_value}")
2062                        } else {
2063                            format!("{}: {example_value},\n", self.property_name)
2064                        },
2065                    ))
2066                })
2067            }))]
2068        .to_vec()
2069    }
2070
2071    fn primary_span(&self) -> Span {
2072        self.node_type.span
2073    }
2074
2075    fn title(&self) -> Cow<'static, str> {
2076        format!(
2077            "{} node is missing a required property: {}",
2078            self.node_type, self.property_name
2079        )
2080        .into()
2081    }
2082}
2083
2084#[derive(Debug)]
2085pub struct InvalidSubnode {
2086    pub node_type: Spanned<NodeType>,
2087    pub subnode: Span,
2088}
2089
2090impl Diagnostic for InvalidSubnode {
2091    fn severity(&self) -> Severity {
2092        Severity::Error
2093    }
2094
2095    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2096        [self.title_snippet().element(
2097            Snippet::source(source)
2098                .path(path)
2099                .annotation(
2100                    AnnotationKind::Primary
2101                        .span(self.subnode.into())
2102                        .label("subnode not supported in this location"),
2103                )
2104                .annotation(
2105                    AnnotationKind::Context
2106                        .span(self.node_type.span.into())
2107                        .label(format!("{} nodes don't support subnodes", self.node_type)),
2108                ),
2109        )]
2110        .to_vec()
2111    }
2112
2113    fn primary_span(&self) -> Span {
2114        self.subnode
2115    }
2116
2117    fn title(&self) -> Cow<'static, str> {
2118        "invalid subnode".into()
2119    }
2120}
2121
2122#[derive(Debug)]
2123pub struct SizeBytesTooLarge {
2124    pub value: Span,
2125    pub field_set: Span,
2126}
2127
2128impl Diagnostic for SizeBytesTooLarge {
2129    fn severity(&self) -> Severity {
2130        Severity::Error
2131    }
2132
2133    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2134        [
2135            self.title_snippet().element(
2136                Snippet::source(source)
2137                    .path(path)
2138                    .annotation(AnnotationKind::Context.span(self.field_set.into()))
2139                    .annotation(
2140                        AnnotationKind::Primary
2141                            .span(self.value.into())
2142                            .label("value too large"),
2143                    ),
2144            ),
2145            Level::HELP
2146                .secondary_title(
2147                    "the maximum value of size-bytes is 0x10_0000 (or 1MB). Keep the value below the limit",
2148                )
2149                .element(
2150                    Snippet::source(source)
2151                        .path(path)
2152                        .patch(Patch::new(self.value.into(), "0xFFFF_FFFF")),
2153                ),
2154        ]
2155        .to_vec()
2156    }
2157
2158    fn primary_span(&self) -> Span {
2159        self.value
2160    }
2161
2162    fn title(&self) -> Cow<'static, str> {
2163        "size-bytes too large".into()
2164    }
2165}
2166
2167#[derive(Debug)]
2168pub struct FieldAddressOutOfRange {
2169    pub field_address: Span,
2170}
2171
2172impl Diagnostic for FieldAddressOutOfRange {
2173    fn severity(&self) -> Severity {
2174        Severity::Error
2175    }
2176
2177    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2178        [self.title_snippet().element(
2179            Snippet::source(source).path(path).annotation(
2180                AnnotationKind::Primary
2181                    .span(self.field_address.into())
2182                    .label("address must be non-negative and lower than 2^32"),
2183            ),
2184        )]
2185        .to_vec()
2186    }
2187
2188    fn primary_span(&self) -> Span {
2189        self.field_address
2190    }
2191
2192    fn title(&self) -> Cow<'static, str> {
2193        "field address exceeds the allowed limits".into()
2194    }
2195}
2196
2197#[derive(Debug)]
2198pub struct ResetValueNegative {
2199    pub reset_value: Span,
2200}
2201
2202impl Diagnostic for ResetValueNegative {
2203    fn severity(&self) -> Severity {
2204        Severity::Error
2205    }
2206
2207    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2208        [self.title_snippet().element(
2209            Snippet::source(source).path(path).annotation(
2210                AnnotationKind::Primary
2211                    .span(self.reset_value.into())
2212                    .label("value may not be negative"),
2213            ),
2214        )]
2215        .to_vec()
2216    }
2217
2218    fn primary_span(&self) -> Span {
2219        self.reset_value
2220    }
2221
2222    fn title(&self) -> Cow<'static, str> {
2223        "reset value is negative".into()
2224    }
2225}
2226
2227#[derive(Debug)]
2228pub struct InvalidShortProperty {
2229    pub property: Span,
2230    pub node_type: Spanned<NodeType>,
2231    pub got: String,
2232    pub expected: Vec<(String, Istr)>,
2233}
2234
2235impl Diagnostic for InvalidShortProperty {
2236    fn severity(&self) -> Severity {
2237        Severity::Error
2238    }
2239
2240    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2241        [self.title_snippet().element(
2242            Snippet::source(source)
2243                .path(path)
2244                .annotation(AnnotationKind::Primary.span(self.property.into()).label(
2245                    if self.expected.is_empty() {
2246                        "no short properties are expected".into()
2247                    } else {
2248                        format!(
2249                            "expected one of: {}",
2250                            self.expected
2251                                .iter()
2252                                .map(|(expression, purpose)| format!("`{expression}` as {purpose}"))
2253                                .join(", ")
2254                        )
2255                    },
2256                ))
2257                .annotation(
2258                    AnnotationKind::Context
2259                        .span(self.property.into())
2260                        .label(format!("got: `{}`", self.got,)),
2261                ),
2262        )]
2263        .to_vec()
2264    }
2265
2266    fn primary_span(&self) -> Span {
2267        self.property
2268    }
2269
2270    fn title(&self) -> Cow<'static, str> {
2271        format!("invalid short property for `{}` nodes", self.node_type).into()
2272    }
2273}
2274
2275#[derive(Debug)]
2276pub struct FieldAddressWrongOrder {
2277    pub address: Span,
2278    pub end: i128,
2279    pub start: i128,
2280}
2281
2282impl Diagnostic for FieldAddressWrongOrder {
2283    fn severity(&self) -> Severity {
2284        Severity::Error
2285    }
2286
2287    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2288        const NOTE_TEXT: &str = "the ordering is `high:low` because that mirrors the format commonly used in datasheets and HDLs";
2289        [
2290            self.title_snippet().element(
2291                Snippet::source(source).path(path).annotation(
2292                    AnnotationKind::Primary
2293                        .span(self.address.into())
2294                        .label("address must be specified as `high:low`"),
2295                ),
2296            ),
2297            Level::HELP
2298                .secondary_title("try switching around the numbers")
2299                .element(Snippet::source(source).path(path).patch(Patch::new(
2300                    self.address.into(),
2301                    format!("{}:{}", self.start, self.end),
2302                ))),
2303            Group::with_title(Level::NOTE.secondary_title(NOTE_TEXT)),
2304        ]
2305        .into()
2306    }
2307
2308    fn primary_span(&self) -> Span {
2309        self.address
2310    }
2311
2312    fn title(&self) -> Cow<'static, str> {
2313        "field address specified in wrong order".into()
2314    }
2315}
2316
2317#[derive(Debug)]
2318pub struct IgnoredDocCommentOnProperty {
2319    pub doc_comments: Span,
2320    pub property: Span,
2321}
2322
2323impl Diagnostic for IgnoredDocCommentOnProperty {
2324    fn severity(&self) -> Severity {
2325        Severity::Warning
2326    }
2327
2328    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2329        [self.title_snippet().element(
2330            Snippet::source(source)
2331                .path(path)
2332                .annotation(
2333                    AnnotationKind::Primary
2334                        .span(self.doc_comments.into())
2335                        .label("these doc comments are ignored"),
2336                )
2337                .annotation(AnnotationKind::Visible.span(self.property.into())),
2338        )]
2339        .into()
2340    }
2341
2342    fn primary_span(&self) -> Span {
2343        self.doc_comments
2344    }
2345
2346    fn title(&self) -> Cow<'static, str> {
2347        "doc comments placed on property that doesn't use them".into()
2348    }
2349}
2350
2351#[derive(Debug)]
2352pub struct InvalidTypeSpecifier {
2353    pub node_type: Spanned<NodeType>,
2354    pub type_specifier: Span,
2355}
2356
2357impl Diagnostic for InvalidTypeSpecifier {
2358    fn severity(&self) -> Severity {
2359        Severity::Error
2360    }
2361
2362    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2363        [
2364            self.title_snippet().element(
2365                Snippet::source(source)
2366                    .path(path)
2367                    .annotation(AnnotationKind::Visible.span(self.node_type.span.into()))
2368                    .annotation(
2369                        AnnotationKind::Primary
2370                            .span(self.type_specifier.into())
2371                            .label("no type specifier is allowed on this node"),
2372                    ),
2373            ),
2374            Level::HELP
2375                .secondary_title("remove the type specifier")
2376                .element(
2377                    Snippet::source(source)
2378                        .path(path)
2379                        .patch(Patch::new(self.type_specifier.into(), "")),
2380                ),
2381        ]
2382        .to_vec()
2383    }
2384
2385    fn primary_span(&self) -> Span {
2386        self.type_specifier
2387    }
2388
2389    fn title(&self) -> Cow<'static, str> {
2390        format!("invalid type specifier for `{}` nodes", self.node_type).into()
2391    }
2392}
2393
2394#[derive(Debug)]
2395pub struct InvalidTypeConversion {
2396    pub node_type: Spanned<NodeType>,
2397    pub type_conversion: Span,
2398}
2399
2400impl Diagnostic for InvalidTypeConversion {
2401    fn severity(&self) -> Severity {
2402        Severity::Error
2403    }
2404
2405    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2406        [
2407            self.title_snippet().element(
2408                Snippet::source(source)
2409                    .path(path)
2410                    .annotation(AnnotationKind::Visible.span(self.node_type.span.into()))
2411                    .annotation(
2412                        AnnotationKind::Primary
2413                            .span(self.type_conversion.into())
2414                            .label("no type conversion is allowed on this node"),
2415                    ),
2416            ),
2417            Level::HELP
2418                .secondary_title("remove the type conversion")
2419                .element(
2420                    Snippet::source(source)
2421                        .path(path)
2422                        .patch(Patch::new(self.type_conversion.into(), "")),
2423                ),
2424        ]
2425        .to_vec()
2426    }
2427
2428    fn primary_span(&self) -> Span {
2429        self.type_conversion
2430    }
2431
2432    fn title(&self) -> Cow<'static, str> {
2433        format!("invalid type conversion for `{}` nodes", self.node_type).into()
2434    }
2435}
2436
2437#[derive(Debug)]
2438pub struct InvalidFieldsetRef {
2439    pub reference: Span,
2440    pub pointee: Option<Span>,
2441}
2442
2443impl Diagnostic for InvalidFieldsetRef {
2444    fn severity(&self) -> Severity {
2445        Severity::Error
2446    }
2447
2448    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2449        [self.title_snippet().element(
2450            Snippet::source(source)
2451                .path(path)
2452                .annotation(
2453                    AnnotationKind::Primary
2454                        .span(self.reference.into())
2455                        .label("no fieldset found with this name"),
2456                )
2457                .annotations(self.pointee.map(|pointee| {
2458                    AnnotationKind::Context
2459                        .span(pointee.into())
2460                        .label("reference points to this non-fieldset object instead")
2461                })),
2462        )]
2463        .to_vec()
2464    }
2465
2466    fn primary_span(&self) -> Span {
2467        self.reference
2468    }
2469
2470    fn title(&self) -> Cow<'static, str> {
2471        "invalid fieldset reference".into()
2472    }
2473}
2474
2475#[derive(Debug)]
2476pub struct InvalidRepeat {
2477    pub repeat: Span,
2478    pub node_type: Spanned<NodeType>,
2479}
2480
2481impl Diagnostic for InvalidRepeat {
2482    fn severity(&self) -> Severity {
2483        Severity::Error
2484    }
2485
2486    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2487        [
2488            self.title_snippet().element(
2489                Snippet::source(source)
2490                    .path(path)
2491                    .annotation(
2492                        AnnotationKind::Primary
2493                            .span(self.repeat.into())
2494                            .label(format!(
2495                                "repeats can't be applied on {} nodes",
2496                                self.node_type
2497                            )),
2498                    )
2499                    .annotation(AnnotationKind::Visible.span(self.node_type.span.into())),
2500            ),
2501            Level::HELP.secondary_title("remove the repeat").element(
2502                Snippet::source(source)
2503                    .path(path)
2504                    .patch(Patch::new(self.repeat.into(), "")),
2505            ),
2506        ]
2507        .to_vec()
2508    }
2509
2510    fn primary_span(&self) -> Span {
2511        self.repeat
2512    }
2513
2514    fn title(&self) -> Cow<'static, str> {
2515        "invalid repeat for node".into()
2516    }
2517}
2518
2519#[derive(Debug)]
2520pub struct ZeroStrideRepeat {
2521    pub stride: Span,
2522}
2523
2524impl Diagnostic for ZeroStrideRepeat {
2525    fn severity(&self) -> Severity {
2526        Severity::Error
2527    }
2528
2529    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2530        const INFO_TEXT: &str = "a stride of 0 means the address doesn't change. So the repeat is useless and thus rejected";
2531
2532        [
2533            self.title_snippet().element(
2534                Snippet::source(source).path(path).annotation(
2535                    AnnotationKind::Primary
2536                        .span(self.stride.into())
2537                        .label("stride is 0"),
2538                ),
2539            ),
2540            Level::HELP
2541                .secondary_title("change to a non-zero value")
2542                .element(
2543                    Snippet::source(source)
2544                        .path(path)
2545                        .patch(Patch::new(self.stride.into(), "1")),
2546                ),
2547            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
2548        ]
2549        .to_vec()
2550    }
2551
2552    fn primary_span(&self) -> Span {
2553        self.stride
2554    }
2555
2556    fn title(&self) -> Cow<'static, str> {
2557        "repeat stride cannot be 0".into()
2558    }
2559}
2560
2561#[derive(Debug)]
2562pub struct ReservedOperationNameUsed {
2563    pub name: Span,
2564    pub operation_name: String,
2565    pub reserved_names: &'static [&'static str],
2566}
2567
2568impl Diagnostic for ReservedOperationNameUsed {
2569    fn severity(&self) -> Severity {
2570        Severity::Error
2571    }
2572
2573    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2574        let info_text: String = format!(
2575            "reserved names are: {}",
2576            self.reserved_names
2577                .iter()
2578                .map(|name| format!("`{name}`"))
2579                .join(", ")
2580        );
2581
2582        [
2583            self.title_snippet().element(
2584                Snippet::source(source).path(path).annotation(
2585                    AnnotationKind::Primary
2586                        .span(self.name.into())
2587                        .label(format!(
2588                            "`{}` is a reserved name for operations. Change it to something else",
2589                            self.operation_name
2590                        )),
2591                ),
2592            ),
2593            Group::with_title(Level::INFO.secondary_title(info_text)),
2594        ]
2595        .to_vec()
2596    }
2597
2598    fn primary_span(&self) -> Span {
2599        self.name
2600    }
2601
2602    fn title(&self) -> Cow<'static, str> {
2603        "reserved operation name used".into()
2604    }
2605}
2606
2607#[derive(Debug)]
2608pub struct FieldSetterNameCollision {
2609    pub field: Span,
2610    pub setter_name: String,
2611    pub collision_field: Span,
2612}
2613
2614impl Diagnostic for FieldSetterNameCollision {
2615    fn severity(&self) -> Severity {
2616        Severity::Error
2617    }
2618
2619    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2620        const HELP_TEXT: &str = "writable fields generate setter functions that have the word `set` prepended. This can collide with other field names.\nAvoid this by changing the name of one of the fields or by making the field read only so it doesn't generate a setter";
2621
2622        [
2623            self.title_snippet().element(
2624                Snippet::source(source)
2625                    .path(path)
2626                    .annotation(
2627                        AnnotationKind::Primary
2628                            .span(self.field.into())
2629                            .label(format!(
2630                                "this field is writable and generates a setter with a name that collides with another field: `{}`",
2631                                self.setter_name
2632                            )),
2633                    )
2634                    .annotation(
2635                        AnnotationKind::Context
2636                            .span(self.collision_field.into())
2637                            .label("collides with this field"),
2638                    ),
2639            ),
2640            Group::with_title(Level::HELP.secondary_title(HELP_TEXT)),
2641        ]
2642        .to_vec()
2643    }
2644
2645    fn primary_span(&self) -> Span {
2646        self.field
2647    }
2648
2649    fn title(&self) -> Cow<'static, str> {
2650        "field setter name collision".into()
2651    }
2652}