@@ -25,8 +25,12 @@ use rustc_span::Span;
2525use std:: ops:: Range ;
2626use url:: Url ;
2727
28+ use doc_link_code:: LinkCode ;
29+ use doc_paragraphs_missing_punctuation:: MissingPunctuation ;
30+
2831mod broken_link;
2932mod doc_comment_double_space_linebreaks;
33+ mod doc_link_code;
3034mod doc_paragraphs_missing_punctuation;
3135mod doc_suspicious_footnotes;
3236mod include_in_doc_without_cfg;
@@ -847,14 +851,6 @@ struct DocHeaders {
847851/// back in the various late lint pass methods if they need the final doc headers, like "Safety" or
848852/// "Panics" sections.
849853fn check_attrs ( cx : & LateContext < ' _ > , valid_idents : & FxHashSet < String > , attrs : & [ Attribute ] ) -> Option < DocHeaders > {
850- // We don't want the parser to choke on intra doc links. Since we don't
851- // actually care about rendering them, just pretend that all broken links
852- // point to a fake address.
853- #[ expect( clippy:: unnecessary_wraps) ] // we're following a type signature
854- fn fake_broken_link_callback < ' a > ( _: BrokenLink < ' _ > ) -> Option < ( CowStr < ' a > , CowStr < ' a > ) > {
855- Some ( ( "fake" . into ( ) , "fake" . into ( ) ) )
856- }
857-
858854 if suspicious_doc_comments:: check ( cx, attrs) || is_doc_hidden ( attrs) {
859855 return None ;
860856 }
@@ -889,32 +885,16 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
889885 return Some ( DocHeaders :: default ( ) ) ;
890886 }
891887
892- check_for_code_clusters (
893- cx,
894- pulldown_cmark:: Parser :: new_with_broken_link_callback (
895- & doc,
896- main_body_opts ( ) - Options :: ENABLE_SMART_PUNCTUATION ,
897- Some ( & mut fake_broken_link_callback) ,
898- )
899- . into_offset_iter ( ) ,
900- & doc,
901- Fragments {
902- doc : & doc,
903- fragments : & fragments,
904- } ,
905- ) ;
906-
907888 // NOTE: check_doc uses it own cb function,
908889 // to avoid causing duplicated diagnostics for the broken link checker.
909- let mut full_fake_broken_link_callback = |bl : BrokenLink < ' _ > | -> Option < ( CowStr < ' _ > , CowStr < ' _ > ) > {
890+ let mut broken_link_callback = |bl : BrokenLink < ' _ > | -> Option < ( CowStr < ' _ > , CowStr < ' _ > ) > {
910891 broken_link:: check ( cx, & bl, & doc, & fragments) ;
911892 Some ( ( "fake" . into ( ) , "fake" . into ( ) ) )
912893 } ;
913894
914895 // disable smart punctuation to pick up ['link'] more easily
915896 let opts = main_body_opts ( ) - Options :: ENABLE_SMART_PUNCTUATION ;
916- let parser =
917- pulldown_cmark:: Parser :: new_with_broken_link_callback ( & doc, opts, Some ( & mut full_fake_broken_link_callback) ) ;
897+ let parser = pulldown_cmark:: Parser :: new_with_broken_link_callback ( & doc, opts, Some ( & mut broken_link_callback) ) ;
918898
919899 Some ( check_doc (
920900 cx,
@@ -934,65 +914,6 @@ enum Container {
934914 List ( usize ) ,
935915}
936916
937- /// Scan the documentation for code links that are back-to-back with code spans.
938- ///
939- /// This is done separately from the rest of the docs, because that makes it easier to produce
940- /// the correct messages.
941- fn check_for_code_clusters < ' a , Events : Iterator < Item = ( pulldown_cmark:: Event < ' a > , Range < usize > ) > > (
942- cx : & LateContext < ' _ > ,
943- events : Events ,
944- doc : & str ,
945- fragments : Fragments < ' _ > ,
946- ) {
947- let mut events = events. peekable ( ) ;
948- let mut code_starts_at = None ;
949- let mut code_ends_at = None ;
950- let mut code_includes_link = false ;
951- while let Some ( ( event, range) ) = events. next ( ) {
952- match event {
953- Start ( Link { .. } ) if matches ! ( events. peek( ) , Some ( ( Code ( _) , _range) ) ) => {
954- if code_starts_at. is_some ( ) {
955- code_ends_at = Some ( range. end ) ;
956- } else {
957- code_starts_at = Some ( range. start ) ;
958- }
959- code_includes_link = true ;
960- // skip the nested "code", because we're already handling it here
961- let _ = events. next ( ) ;
962- } ,
963- Code ( _) => {
964- if code_starts_at. is_some ( ) {
965- code_ends_at = Some ( range. end ) ;
966- } else {
967- code_starts_at = Some ( range. start ) ;
968- }
969- } ,
970- End ( TagEnd :: Link ) => { } ,
971- _ => {
972- if let Some ( start) = code_starts_at
973- && let Some ( end) = code_ends_at
974- && code_includes_link
975- && let Some ( span) = fragments. span ( cx, start..end)
976- {
977- span_lint_and_then ( cx, DOC_LINK_CODE , span, "code link adjacent to code text" , |diag| {
978- let sugg = format ! ( "<code>{}</code>" , doc[ start..end] . replace( '`' , "" ) ) ;
979- diag. span_suggestion_verbose (
980- span,
981- "wrap the entire group in `<code>` tags" ,
982- sugg,
983- Applicability :: MaybeIncorrect ,
984- ) ;
985- diag. help ( "separate code snippets will be shown with a gap" ) ;
986- } ) ;
987- }
988- code_includes_link = false ;
989- code_starts_at = None ;
990- code_ends_at = None ;
991- } ,
992- }
993- }
994- }
995-
996917#[ derive( Clone , Copy ) ]
997918#[ expect( clippy:: struct_excessive_bools) ]
998919struct CodeTags {
@@ -1070,7 +991,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
1070991 fragments : Fragments < ' _ > ,
1071992 attrs : & [ Attribute ] ,
1072993) -> DocHeaders {
1073- let mut missing_punctuation = doc_paragraphs_missing_punctuation:: MissingPunctuation :: default ( ) ;
994+ let mut missing_punctuation = MissingPunctuation :: default ( ) ;
995+ let mut link_code = LinkCode :: default ( ) ;
1074996
1075997 // true if a safety header was found
1076998 let mut headers = DocHeaders :: default ( ) ;
@@ -1092,6 +1014,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
10921014
10931015 while let Some ( ( event, range) ) = events. next ( ) {
10941016 missing_punctuation. check ( cx, & event, range. clone ( ) , doc, fragments) ;
1017+ link_code. check ( cx, & event, range. clone ( ) , doc, fragments) ;
10951018
10961019 match event {
10971020 Html ( tag) | InlineHtml ( tag) => {
0 commit comments