about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/doc.rs22
-rw-r--r--tests/ui/needless_doc_main.rs36
-rw-r--r--tests/ui/needless_doc_main.stderr14
3 files changed, 65 insertions, 7 deletions
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 35578ae68a4..754d38f4015 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -367,6 +367,8 @@ fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet<String>, a
     check_doc(cx, valid_idents, events, &spans)
 }
 
+const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail", "edition2018"];
+
 fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
     cx: &LateContext<'_, '_>,
     valid_idents: &FxHashSet<String>,
@@ -374,6 +376,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     spans: &[(usize, Span)],
 ) -> DocHeaders {
     // true if a safety header was found
+    use pulldown_cmark::CodeBlockKind;
     use pulldown_cmark::Event::{
         Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
     };
@@ -386,11 +389,20 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut in_code = false;
     let mut in_link = None;
     let mut in_heading = false;
-
+    let mut is_rust = false;
     for (event, range) in events {
         match event {
-            Start(CodeBlock(_)) => in_code = true,
-            End(CodeBlock(_)) => in_code = false,
+            Start(CodeBlock(ref kind)) => {
+                in_code = true;
+                if let CodeBlockKind::Fenced(lang) = kind {
+                    is_rust =
+                        lang.is_empty() || !lang.contains("ignore") && lang.split(',').any(|i| RUST_CODE.contains(&i));
+                }
+            },
+            End(CodeBlock(_)) => {
+                in_code = false;
+                is_rust = false;
+            },
             Start(Link(_, url, _)) => in_link = Some(url),
             End(Link(..)) => in_link = None,
             Start(Heading(_)) => in_heading = true,
@@ -413,7 +425,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 };
                 let (begin, span) = spans[index];
                 if in_code {
-                    check_code(cx, &text, span);
+                    if is_rust {
+                        check_code(cx, &text, span);
+                    }
                 } else {
                     // Adjust for the beginning of the current `Event`
                     let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
diff --git a/tests/ui/needless_doc_main.rs b/tests/ui/needless_doc_main.rs
index 813d2606153..682d7b3c4ce 100644
--- a/tests/ui/needless_doc_main.rs
+++ b/tests/ui/needless_doc_main.rs
@@ -8,7 +8,23 @@
 ///     unimplemented!();
 /// }
 /// ```
-fn bad_doctest() {}
+///
+/// This should, too.
+///
+/// ```rust
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+///
+/// This one too.
+///
+/// ```no_run
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+fn bad_doctests() {}
 
 /// # Examples
 ///
@@ -34,9 +50,25 @@ fn bad_doctest() {}
 ///     assert_eq(1u8, test::black_box(1));
 /// }
 /// ```
+///
+/// We should not lint ignored examples:
+///
+/// ```rust,ignore
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+///
+/// Or even non-rust examples:
+///
+/// ```text
+/// fn main() {
+///     is what starts the program
+/// }
+/// ```
 fn no_false_positives() {}
 
 fn main() {
-    bad_doctest();
+    bad_doctests();
     no_false_positives();
 }
diff --git a/tests/ui/needless_doc_main.stderr b/tests/ui/needless_doc_main.stderr
index 22d145aad58..65d40ee6832 100644
--- a/tests/ui/needless_doc_main.stderr
+++ b/tests/ui/needless_doc_main.stderr
@@ -6,5 +6,17 @@ LL | /// fn main() {
    |
    = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
 
-error: aborting due to previous error
+error: needless `fn main` in doctest
+  --> $DIR/needless_doc_main.rs:15:4
+   |
+LL | /// fn main() {
+   |    ^^^^^^^^^^^^
+
+error: needless `fn main` in doctest
+  --> $DIR/needless_doc_main.rs:23:4
+   |
+LL | /// fn main() {
+   |    ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors