about summary refs log tree commit diff
diff options
context:
space:
mode:
authorcameron <cameron.studdstreet@gmail.com>2022-02-01 11:21:42 +0000
committercameron <cameron.studdstreet@gmail.com>2022-02-01 11:21:42 +0000
commitcb29e3effbf72db2e1f5177336bfb3309ec8805e (patch)
tree79020a9422bf3fd7a800ac288f2ecf021dcc0fa3
parent7bb69c0ae024eef65acb7fd6551fdd99f1563d38 (diff)
downloadrust-cb29e3effbf72db2e1f5177336bfb3309ec8805e.tar.gz
rust-cb29e3effbf72db2e1f5177336bfb3309ec8805e.zip
add doc_link_with_quotes lint
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/doc_link_with_quotes.rs60
-rw-r--r--clippy_lints/src/lib.register_lints.rs1
-rw-r--r--clippy_lints/src/lib.register_pedantic.rs1
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--tests/ui/doc_link_with_quotes.rs12
-rw-r--r--tests/ui/doc_link_with_quotes.stderr10
7 files changed, 87 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9548366daf9..42b002407b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2941,6 +2941,7 @@ Released 2018-09-13
 [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 [`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_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
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs
new file mode 100644
index 00000000000..cb07f57e870
--- /dev/null
+++ b/clippy_lints/src/doc_link_with_quotes.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint;
+use itertools::Itertools;
+use rustc_ast::{AttrKind, Attribute};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
+    /// outside of code blocks
+    /// ### Why is this bad?
+    /// It is likely a typo when defining an intra-doc link
+    ///
+    /// ### Example
+    /// ```rust
+    /// /// See also: ['foo']
+    /// fn bar() {}
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// /// See also: [`foo`]
+    /// fn bar() {}
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub DOC_LINK_WITH_QUOTES,
+    pedantic,
+    "possible typo for an intra-doc link"
+}
+declare_lint_pass!(DocLinkWithQuotes => [DOC_LINK_WITH_QUOTES]);
+
+impl EarlyLintPass for DocLinkWithQuotes {
+    fn check_attribute(&mut self, ctx: &EarlyContext<'_>, attr: &Attribute) {
+        if let AttrKind::DocComment(_, symbol) = attr.kind {
+            if contains_quote_link(symbol.as_str()) {
+                span_lint(
+                    ctx,
+                    DOC_LINK_WITH_QUOTES,
+                    attr.span,
+                    "possible intra-doc link using quotes instead of backticks",
+                );
+            }
+        }
+    }
+}
+
+fn contains_quote_link(s: &str) -> bool {
+    let mut in_backticks = false;
+    let mut found_opening = false;
+
+    for c in s.chars().tuple_windows::<(char, char)>() {
+        match c {
+            ('`', _) => in_backticks = !in_backticks,
+            ('[', '\'') if !in_backticks => found_opening = true,
+            ('\'', ']') if !in_backticks && found_opening => return true,
+            _ => {},
+        }
+    }
+
+    false
+}
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index e5e1c052c15..42c530428f3 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -109,6 +109,7 @@ store.register_lints(&[
     doc::MISSING_PANICS_DOC,
     doc::MISSING_SAFETY_DOC,
     doc::NEEDLESS_DOCTEST_MAIN,
+    doc_link_with_quotes::DOC_LINK_WITH_QUOTES,
     double_comparison::DOUBLE_COMPARISONS,
     double_parens::DOUBLE_PARENS,
     drop_forget_ref::DROP_COPY,
diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs
index 1292675f4a9..de72420706b 100644
--- a/clippy_lints/src/lib.register_pedantic.rs
+++ b/clippy_lints/src/lib.register_pedantic.rs
@@ -28,6 +28,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(doc::DOC_MARKDOWN),
     LintId::of(doc::MISSING_ERRORS_DOC),
     LintId::of(doc::MISSING_PANICS_DOC),
+    LintId::of(doc_link_with_quotes::DOC_LINK_WITH_QUOTES),
     LintId::of(empty_enum::EMPTY_ENUM),
     LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
     LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 9d42185dc0e..644c2418289 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -197,6 +197,7 @@ mod disallowed_methods;
 mod disallowed_script_idents;
 mod disallowed_types;
 mod doc;
+mod doc_link_with_quotes;
 mod double_comparison;
 mod double_parens;
 mod drop_forget_ref;
@@ -861,6 +862,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
     store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
     store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
+    store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/tests/ui/doc_link_with_quotes.rs b/tests/ui/doc_link_with_quotes.rs
new file mode 100644
index 00000000000..ab52fb1a4a6
--- /dev/null
+++ b/tests/ui/doc_link_with_quotes.rs
@@ -0,0 +1,12 @@
+#![warn(clippy::doc_link_with_quotes)]
+
+fn main() {
+    foo()
+}
+
+/// Calls ['bar']
+pub fn foo() {
+    bar()
+}
+
+pub fn bar() {}
diff --git a/tests/ui/doc_link_with_quotes.stderr b/tests/ui/doc_link_with_quotes.stderr
new file mode 100644
index 00000000000..bf6d57d8afe
--- /dev/null
+++ b/tests/ui/doc_link_with_quotes.stderr
@@ -0,0 +1,10 @@
+error: possible intra-doc link using quotes instead of backticks
+  --> $DIR/doc_link_with_quotes.rs:7:1
+   |
+LL | /// Calls ['bar']
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::doc-link-with-quotes` implied by `-D warnings`
+
+error: aborting due to previous error
+