@@ -559,7 +559,9 @@ pub(crate) struct LinkOrdinalOutOfRange {
559
559
}
560
560
561
561
pub ( crate ) enum AttributeParseErrorReason < ' a > {
562
- ExpectedNoArgs ,
562
+ ExpectedNoArgs {
563
+ path : & ' a AttrPath ,
564
+ } ,
563
565
ExpectedStringLiteral {
564
566
byte_string : Option < Span > ,
565
567
} ,
@@ -577,6 +579,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
577
579
list : bool ,
578
580
} ,
579
581
ExpectedIdentifier ,
582
+ ExpectedEnd {
583
+ last : Span ,
584
+ } ,
580
585
}
581
586
582
587
pub ( crate ) struct AttributeParseError < ' a > {
@@ -588,13 +593,28 @@ pub(crate) struct AttributeParseError<'a> {
588
593
pub ( crate ) reason : AttributeParseErrorReason < ' a > ,
589
594
}
590
595
596
+ /// based on the attribute's template we add relevant suggestions to the error automatically.
597
+ enum DefaultSuggestionStyle {
598
+ /// give a hint about the valid forms of the attribute.
599
+ /// Useful if there's already a better suggestion given than the automatic ones can provide
600
+ /// but we'd still like to show which syntax forms are valid.
601
+ Hint ,
602
+ /// Use the template to suggest changes to the attribute
603
+ Suggestion ,
604
+ /// Don't show any default suggestions
605
+ None ,
606
+ }
607
+
591
608
impl < ' a , G : EmissionGuarantee > Diagnostic < ' a , G > for AttributeParseError < ' _ > {
592
609
fn into_diag ( self , dcx : DiagCtxtHandle < ' a > , level : Level ) -> Diag < ' a , G > {
593
610
let name = self . attribute . to_string ( ) ;
594
611
595
612
let mut diag = Diag :: new ( dcx, level, format ! ( "malformed `{name}` attribute input" ) ) ;
596
613
diag. span ( self . attr_span ) ;
597
614
diag. code ( E0539 ) ;
615
+
616
+ let mut show_default_suggestions = DefaultSuggestionStyle :: Suggestion ;
617
+
598
618
match self . reason {
599
619
AttributeParseErrorReason :: ExpectedStringLiteral { byte_string } => {
600
620
if let Some ( start_point_span) = byte_string {
@@ -606,7 +626,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
606
626
) ;
607
627
diag. note ( "expected a normal string literal, not a byte string literal" ) ;
608
628
609
- return diag ;
629
+ show_default_suggestions = DefaultSuggestionStyle :: None ;
610
630
} else {
611
631
diag. span_label ( self . span , "expected a string literal here" ) ;
612
632
}
@@ -632,9 +652,19 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
632
652
diag. span_label ( self . span , "didn't expect a literal here" ) ;
633
653
diag. code ( E0565 ) ;
634
654
}
635
- AttributeParseErrorReason :: ExpectedNoArgs => {
655
+ AttributeParseErrorReason :: ExpectedNoArgs { path } => {
636
656
diag. span_label ( self . span , "didn't expect any arguments here" ) ;
637
657
diag. code ( E0565 ) ;
658
+
659
+ if path. span != self . attribute . span {
660
+ diag. span_suggestion (
661
+ path. span . to ( self . span ) ,
662
+ "remove this argument" ,
663
+ path,
664
+ Applicability :: MachineApplicable ,
665
+ ) ;
666
+ show_default_suggestions = DefaultSuggestionStyle :: Hint ;
667
+ }
638
668
}
639
669
AttributeParseErrorReason :: ExpectedNameValue ( None ) => {
640
670
// If the span is the entire attribute, the suggestion we add below this match already contains enough information
@@ -716,23 +746,36 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
716
746
AttributeParseErrorReason :: ExpectedIdentifier => {
717
747
diag. span_label ( self . span , "expected a valid identifier here" ) ;
718
748
}
749
+ AttributeParseErrorReason :: ExpectedEnd { last } => {
750
+ diag. span_label ( last, "expected no more arguments after this" ) ;
751
+ diag. span_label ( self . span , "remove this argument" ) ;
752
+ }
719
753
}
720
754
721
755
if let Some ( link) = self . template . docs {
722
756
diag. note ( format ! ( "for more information, visit <{link}>" ) ) ;
723
757
}
758
+
724
759
let suggestions = self . template . suggestions ( self . attr_style , & name) ;
760
+ let text = match show_default_suggestions {
761
+ DefaultSuggestionStyle :: Hint => {
762
+ if suggestions. len ( ) == 1 {
763
+ "the only valid form of the attribute is"
764
+ } else {
765
+ "these are the valid forms of the attribute"
766
+ }
767
+ }
768
+ DefaultSuggestionStyle :: Suggestion => {
769
+ if suggestions. len ( ) == 1 {
770
+ "must be of the form"
771
+ } else {
772
+ "try changing it to one of the following valid forms of the attribute"
773
+ }
774
+ }
775
+ DefaultSuggestionStyle :: None => return diag,
776
+ } ;
725
777
726
- diag. span_suggestions (
727
- self . attr_span ,
728
- if suggestions. len ( ) == 1 {
729
- "must be of the form"
730
- } else {
731
- "try changing it to one of the following valid forms of the attribute"
732
- } ,
733
- suggestions,
734
- Applicability :: HasPlaceholders ,
735
- ) ;
778
+ diag. span_suggestions ( self . attr_span , text, suggestions, Applicability :: HasPlaceholders ) ;
736
779
737
780
diag
738
781
}
0 commit comments