@@ -587,7 +587,9 @@ pub(crate) struct LinkOrdinalOutOfRange {
587587}
588588
589589pub ( crate ) enum AttributeParseErrorReason < ' a > {
590- ExpectedNoArgs ,
590+ ExpectedNoArgs {
591+ path : & ' a AttrPath ,
592+ } ,
591593 ExpectedStringLiteral {
592594 byte_string : Option < Span > ,
593595 } ,
@@ -605,6 +607,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
605607 list : bool ,
606608 } ,
607609 ExpectedIdentifier ,
610+ ExpectedEnd {
611+ last : Span ,
612+ } ,
608613}
609614
610615pub ( crate ) struct AttributeParseError < ' a > {
@@ -616,13 +621,28 @@ pub(crate) struct AttributeParseError<'a> {
616621 pub ( crate ) reason : AttributeParseErrorReason < ' a > ,
617622}
618623
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+
619636impl < ' a , G : EmissionGuarantee > Diagnostic < ' a , G > for AttributeParseError < ' _ > {
620637 fn into_diag ( self , dcx : DiagCtxtHandle < ' a > , level : Level ) -> Diag < ' a , G > {
621638 let name = self . attribute . to_string ( ) ;
622639
623640 let mut diag = Diag :: new ( dcx, level, format ! ( "malformed `{name}` attribute input" ) ) ;
624641 diag. span ( self . attr_span ) ;
625642 diag. code ( E0539 ) ;
643+
644+ let mut show_default_suggestions = DefaultSuggestionStyle :: Suggestion ;
645+
626646 match self . reason {
627647 AttributeParseErrorReason :: ExpectedStringLiteral { byte_string } => {
628648 if let Some ( start_point_span) = byte_string {
@@ -634,7 +654,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
634654 ) ;
635655 diag. note ( "expected a normal string literal, not a byte string literal" ) ;
636656
637- return diag ;
657+ show_default_suggestions = DefaultSuggestionStyle :: None ;
638658 } else {
639659 diag. span_label ( self . span , "expected a string literal here" ) ;
640660 }
@@ -660,9 +680,19 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
660680 diag. span_label ( self . span , "didn't expect a literal here" ) ;
661681 diag. code ( E0565 ) ;
662682 }
663- AttributeParseErrorReason :: ExpectedNoArgs => {
683+ AttributeParseErrorReason :: ExpectedNoArgs { path } => {
664684 diag. span_label ( self . span , "didn't expect any arguments here" ) ;
665685 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+ }
666696 }
667697 AttributeParseErrorReason :: ExpectedNameValue ( None ) => {
668698 // 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<'_> {
744774 AttributeParseErrorReason :: ExpectedIdentifier => {
745775 diag. span_label ( self . span , "expected a valid identifier here" ) ;
746776 }
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+ }
747781 }
748782
749783 if let Some ( link) = self . template . docs {
750784 diag. note ( format ! ( "for more information, visit <{link}>" ) ) ;
751785 }
786+
752787 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+ } ;
753805
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 ) ;
764807
765808 diag
766809 }
0 commit comments