@@ -587,7 +587,9 @@ pub(crate) struct LinkOrdinalOutOfRange {
587
587
}
588
588
589
589
pub ( crate ) enum AttributeParseErrorReason < ' a > {
590
- ExpectedNoArgs ,
590
+ ExpectedNoArgs {
591
+ path : & ' a AttrPath ,
592
+ } ,
591
593
ExpectedStringLiteral {
592
594
byte_string : Option < Span > ,
593
595
} ,
@@ -605,6 +607,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
605
607
list : bool ,
606
608
} ,
607
609
ExpectedIdentifier ,
610
+ ExpectedEnd {
611
+ last : Span ,
612
+ } ,
608
613
}
609
614
610
615
pub ( crate ) struct AttributeParseError < ' a > {
@@ -616,13 +621,28 @@ pub(crate) struct AttributeParseError<'a> {
616
621
pub ( crate ) reason : AttributeParseErrorReason < ' a > ,
617
622
}
618
623
624
+ /// based on the attribute's template we add relevant suggestions to the error automatically.
625
+ enum DefaultSuggestionStyle {
626
+ /// give a hint about the valid forms of the attribute.
627
+ /// Useful if there's already a better suggestion given than the automatic ones can provide
628
+ /// but we'd still like to show which syntax forms are valid.
629
+ Hint ,
630
+ /// Use the template to suggest changes to the attribute
631
+ Suggestion ,
632
+ /// Don't show any default suggestions
633
+ None ,
634
+ }
635
+
619
636
impl < ' a , G : EmissionGuarantee > Diagnostic < ' a , G > for AttributeParseError < ' _ > {
620
637
fn into_diag ( self , dcx : DiagCtxtHandle < ' a > , level : Level ) -> Diag < ' a , G > {
621
638
let name = self . attribute . to_string ( ) ;
622
639
623
640
let mut diag = Diag :: new ( dcx, level, format ! ( "malformed `{name}` attribute input" ) ) ;
624
641
diag. span ( self . attr_span ) ;
625
642
diag. code ( E0539 ) ;
643
+
644
+ let mut show_default_suggestions = DefaultSuggestionStyle :: Suggestion ;
645
+
626
646
match self . reason {
627
647
AttributeParseErrorReason :: ExpectedStringLiteral { byte_string } => {
628
648
if let Some ( start_point_span) = byte_string {
@@ -634,7 +654,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
634
654
) ;
635
655
diag. note ( "expected a normal string literal, not a byte string literal" ) ;
636
656
637
- return diag ;
657
+ show_default_suggestions = DefaultSuggestionStyle :: None ;
638
658
} else {
639
659
diag. span_label ( self . span , "expected a string literal here" ) ;
640
660
}
@@ -660,9 +680,19 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
660
680
diag. span_label ( self . span , "didn't expect a literal here" ) ;
661
681
diag. code ( E0565 ) ;
662
682
}
663
- AttributeParseErrorReason :: ExpectedNoArgs => {
683
+ AttributeParseErrorReason :: ExpectedNoArgs { path } => {
664
684
diag. span_label ( self . span , "didn't expect any arguments here" ) ;
665
685
diag. code ( E0565 ) ;
686
+
687
+ if path. span != self . attribute . span {
688
+ diag. span_suggestion (
689
+ path. span . to ( self . span ) ,
690
+ "remove this argument" ,
691
+ path,
692
+ Applicability :: MachineApplicable ,
693
+ ) ;
694
+ show_default_suggestions = DefaultSuggestionStyle :: Hint ;
695
+ }
666
696
}
667
697
AttributeParseErrorReason :: ExpectedNameValue ( None ) => {
668
698
// If the span is the entire attribute, the suggestion we add below this match already contains enough information
@@ -744,23 +774,36 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
744
774
AttributeParseErrorReason :: ExpectedIdentifier => {
745
775
diag. span_label ( self . span , "expected a valid identifier here" ) ;
746
776
}
777
+ AttributeParseErrorReason :: ExpectedEnd { last } => {
778
+ diag. span_label ( last, "expected no more arguments after this" ) ;
779
+ diag. span_label ( self . span , "remove this argument" ) ;
780
+ }
747
781
}
748
782
749
783
if let Some ( link) = self . template . docs {
750
784
diag. note ( format ! ( "for more information, visit <{link}>" ) ) ;
751
785
}
786
+
752
787
let suggestions = self . template . suggestions ( self . attr_style , & name) ;
788
+ let text = match show_default_suggestions {
789
+ DefaultSuggestionStyle :: Hint => {
790
+ if suggestions. len ( ) == 1 {
791
+ "the only valid form of the attribute is"
792
+ } else {
793
+ "these are the valid forms of the attribute"
794
+ }
795
+ }
796
+ DefaultSuggestionStyle :: Suggestion => {
797
+ if suggestions. len ( ) == 1 {
798
+ "must be of the form"
799
+ } else {
800
+ "try changing it to one of the following valid forms of the attribute"
801
+ }
802
+ }
803
+ DefaultSuggestionStyle :: None => return diag,
804
+ } ;
753
805
754
- diag. span_suggestions (
755
- self . attr_span ,
756
- if suggestions. len ( ) == 1 {
757
- "must be of the form"
758
- } else {
759
- "try changing it to one of the following valid forms of the attribute"
760
- } ,
761
- suggestions,
762
- Applicability :: HasPlaceholders ,
763
- ) ;
806
+ diag. span_suggestions ( self . attr_span , text, suggestions, Applicability :: HasPlaceholders ) ;
764
807
765
808
diag
766
809
}
0 commit comments