@@ -24,6 +24,7 @@ use rustc_span::edition::Edition;
24
24
use std:: ops:: Range ;
25
25
use url:: Url ;
26
26
27
+ mod broken_link;
27
28
mod doc_comment_double_space_linebreaks;
28
29
mod doc_suspicious_footnotes;
29
30
mod include_in_doc_without_cfg;
@@ -292,6 +293,34 @@ declare_clippy_lint! {
292
293
"possible typo for an intra-doc link"
293
294
}
294
295
296
+ declare_clippy_lint ! {
297
+ /// ### What it does
298
+ /// Checks the doc comments have unbroken links, mostly caused
299
+ /// by bad formatted links such as broken across multiple lines.
300
+ ///
301
+ /// ### Why is this bad?
302
+ /// Because documentation generated by rustdoc will be broken
303
+ /// since expected links won't be links and just text.
304
+ ///
305
+ /// ### Examples
306
+ /// This link is broken:
307
+ /// ```no_run
308
+ /// /// [example of a bad link](https://
309
+ /// /// github.com/rust-lang/rust-clippy/)
310
+ /// pub fn do_something() {}
311
+ /// ```
312
+ ///
313
+ /// It shouldn't be broken across multiple lines to work:
314
+ /// ```no_run
315
+ /// /// [example of a good link](https://github.com/rust-lang/rust-clippy/)
316
+ /// pub fn do_something() {}
317
+ /// ```
318
+ #[ clippy:: version = "1.84.0" ]
319
+ pub DOC_BROKEN_LINK ,
320
+ pedantic,
321
+ "broken document link"
322
+ }
323
+
295
324
declare_clippy_lint ! {
296
325
/// ### What it does
297
326
/// Checks for the doc comments of publicly visible
@@ -656,6 +685,7 @@ impl Documentation {
656
685
impl_lint_pass ! ( Documentation => [
657
686
DOC_LINK_CODE ,
658
687
DOC_LINK_WITH_QUOTES ,
688
+ DOC_BROKEN_LINK ,
659
689
DOC_MARKDOWN ,
660
690
DOC_NESTED_REFDEFS ,
661
691
MISSING_SAFETY_DOC ,
@@ -786,9 +816,9 @@ struct DocHeaders {
786
816
/// back in the various late lint pass methods if they need the final doc headers, like "Safety" or
787
817
/// "Panics" sections.
788
818
fn check_attrs ( cx : & LateContext < ' _ > , valid_idents : & FxHashSet < String > , attrs : & [ Attribute ] ) -> Option < DocHeaders > {
789
- /// We don't want the parser to choke on intra doc links. Since we don't
790
- /// actually care about rendering them, just pretend that all broken links
791
- /// point to a fake address.
819
+ // We don't want the parser to choke on intra doc links. Since we don't
820
+ // actually care about rendering them, just pretend that all broken links
821
+ // point to a fake address.
792
822
#[ expect( clippy:: unnecessary_wraps) ] // we're following a type signature
793
823
fn fake_broken_link_callback < ' a > ( _: BrokenLink < ' _ > ) -> Option < ( CowStr < ' a > , CowStr < ' a > ) > {
794
824
Some ( ( "fake" . into ( ) , "fake" . into ( ) ) )
@@ -828,14 +858,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
828
858
return Some ( DocHeaders :: default ( ) ) ;
829
859
}
830
860
831
- let mut cb = fake_broken_link_callback;
832
-
833
861
check_for_code_clusters (
834
862
cx,
835
863
pulldown_cmark:: Parser :: new_with_broken_link_callback (
836
864
& doc,
837
865
main_body_opts ( ) - Options :: ENABLE_SMART_PUNCTUATION ,
838
- Some ( & mut cb ) ,
866
+ Some ( & mut fake_broken_link_callback ) ,
839
867
)
840
868
. into_offset_iter ( ) ,
841
869
& doc,
@@ -845,9 +873,17 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
845
873
} ,
846
874
) ;
847
875
876
+ // NOTE: check_doc uses it own cb function,
877
+ // to avoid causing duplicated diagnostics for the broken link checker.
878
+ let mut full_fake_broken_link_callback = |bl : BrokenLink < ' _ > | -> Option < ( CowStr < ' _ > , CowStr < ' _ > ) > {
879
+ broken_link:: check ( cx, & bl, & doc, & fragments) ;
880
+ Some ( ( "fake" . into ( ) , "fake" . into ( ) ) )
881
+ } ;
882
+
848
883
// disable smart punctuation to pick up ['link'] more easily
849
884
let opts = main_body_opts ( ) - Options :: ENABLE_SMART_PUNCTUATION ;
850
- let parser = pulldown_cmark:: Parser :: new_with_broken_link_callback ( & doc, opts, Some ( & mut cb) ) ;
885
+ let parser =
886
+ pulldown_cmark:: Parser :: new_with_broken_link_callback ( & doc, opts, Some ( & mut full_fake_broken_link_callback) ) ;
851
887
852
888
Some ( check_doc (
853
889
cx,
0 commit comments