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 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 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#[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 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 ),
1408 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 ), )
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 ), ),
1638 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}