Skip to content

Commit

Permalink
Add lint for broken doc links
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcnunes committed Nov 16, 2024
1 parent 5f05ce4 commit 8d859c9
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5441,6 +5441,7 @@ Released 2018-09-13
[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
[`doc_broken_link`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_broken_link
[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::disallowed_names::DISALLOWED_NAMES_INFO,
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
crate::disallowed_types::DISALLOWED_TYPES_INFO,
crate::doc::DOC_BROKEN_LINK_INFO,
crate::doc::DOC_LAZY_CONTINUATION_INFO,
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
crate::doc::DOC_MARKDOWN_INFO,
Expand Down
14 changes: 14 additions & 0 deletions clippy_lints/src/doc/broken_link.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use super::{DOC_BROKEN_LINK, Fragments};
use clippy_utils::diagnostics::span_lint;
use rustc_lint::LateContext;
use std::ops::Range;

// Check broken links in code docs.
pub fn check(cx: &LateContext<'_>, _trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>, link: &str) {
if let Some(span) = fragments.span(cx, range) {
// Broken links are replaced with "fake" value by `fake_broken_link_callback` at `doc/mod.rs`.
if link == "fake" {
span_lint(cx, DOC_BROKEN_LINK, span, "possible broken doc link");
}
}
}
32 changes: 32 additions & 0 deletions clippy_lints/src/doc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use rustc_span::{Span, sym};
use std::ops::Range;
use url::Url;

mod broken_link;
mod empty_line_after;
mod link_with_quotes;
mod markdown;
Expand Down Expand Up @@ -261,6 +262,33 @@ declare_clippy_lint! {
"possible typo for an intra-doc link"
}

declare_clippy_lint! {
/// ### What it does
/// Checks the doc comments have unbroken links, mostly caused
/// by bad formatted links such as broken across multiple lines.
///
/// ### Why is this bad?
/// Because documentation generated by rustdoc will be broken
/// since expected links won't be links and just text.
///
/// ### Examples
/// This link is broken:
/// ```no_run
/// /// [example of a bad link](https://
/// /// github.com/rust-lang/rust-clippy/)
/// pub fn do_something() {}
///
/// It shouldn't be broken across multiple lines to work:
/// ```no_run
/// /// [example of a good link](https://github.com/rust-lang/rust-clippy/)
/// pub fn do_something() {}
/// ```
#[clippy::version = "1.82.0"]
pub DOC_BROKEN_LINK,
pedantic,
"broken document link"
}

declare_clippy_lint! {
/// ### What it does
/// Checks for the doc comments of publicly visible
Expand Down Expand Up @@ -548,6 +576,7 @@ impl Documentation {

impl_lint_pass!(Documentation => [
DOC_LINK_WITH_QUOTES,
DOC_BROKEN_LINK,
DOC_MARKDOWN,
MISSING_SAFETY_DOC,
MISSING_ERRORS_DOC,
Expand Down Expand Up @@ -929,6 +958,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
} else {
if in_link.is_some() {
link_with_quotes::check(cx, trimmed_text, range.clone(), fragments);
if let Some(link) = in_link.as_ref() {
broken_link::check(cx, trimmed_text, range.clone(), fragments, &link);
}
}
if let Some(link) = in_link.as_ref()
&& let Ok(url) = Url::parse(link)
Expand Down
36 changes: 36 additions & 0 deletions tests/ui/doc_broken_link.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![warn(clippy::doc_broken_link)]

fn main() {
doc_valid_link();
doc_valid_link_broken_title();
doc_valid_link_broken_url_tag();
doc_invalid_link_broken_url_scheme_part();
doc_invalid_link_broken_url_host_part();
}

/// Test valid link, whole link single line.
/// [doc valid link](https://test.fake/doc_valid_link)
pub fn doc_valid_link() {}

/// Test valid link, title tag broken across multiple lines.
/// [doc invalid link broken
/// title](https://test.fake/doc_valid_link_broken_title)
pub fn doc_valid_link_broken_title() {}

/// Test valid link, url tag broken across multiple lines, but
/// the whole url part in a single line.
/// [doc valid link broken url tag](
/// https://test.fake/doc_valid_link_broken_url_tag)
pub fn doc_valid_link_broken_url_tag() {}

/// Test invalid link, url part broken across multiple lines.
/// [doc invalid link broken url scheme part part](https://
/// test.fake/doc_invalid_link_broken_url_scheme_part)
//~^^ ERROR: possible broken doc link
pub fn doc_invalid_link_broken_url_scheme_part() {}

/// Test invalid link, url part broken across multiple lines.
/// [doc invalid link broken url host part](https://test
/// .fake/doc_invalid_link_broken_url_host_part)
//~^^ ERROR: possible broken doc link
pub fn doc_invalid_link_broken_url_host_part() {}
17 changes: 17 additions & 0 deletions tests/ui/doc_broken_link.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: possible broken doc link
--> tests/ui/doc_broken_link.rs:27:6
|
LL | /// [doc invalid link broken url scheme part part](https://
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::doc-broken-link` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::doc_broken_link)]`

error: possible broken doc link
--> tests/ui/doc_broken_link.rs:33:6
|
LL | /// [doc invalid link broken url host part](https://test
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

0 comments on commit 8d859c9

Please sign in to comment.