Skip to content

Commit cee1293

Browse files
committed
Add missing_examples_doc lint
1 parent 432dad4 commit cee1293

File tree

7 files changed

+99
-2
lines changed

7 files changed

+99
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6622,6 +6622,7 @@ Released 2018-09-13
66226622
[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
66236623
[`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
66246624
[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
6625+
[`missing_examples_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_examples_doc
66256626
[`missing_fields_in_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_fields_in_debug
66266627
[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
66276628
[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
122122
crate::doc::DOC_SUSPICIOUS_FOOTNOTES_INFO,
123123
crate::doc::EMPTY_DOCS_INFO,
124124
crate::doc::MISSING_ERRORS_DOC_INFO,
125+
crate::doc::MISSING_EXAMPLES_DOC_INFO,
125126
crate::doc::MISSING_PANICS_DOC_INFO,
126127
crate::doc::MISSING_SAFETY_DOC_INFO,
127128
crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,

clippy_lints/src/doc/missing_headers.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
1+
use super::{
2+
DocHeaders, MISSING_ERRORS_DOC, MISSING_EXAMPLES_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC,
3+
UNNECESSARY_SAFETY_DOC,
4+
};
25
use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
36
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
47
use clippy_utils::res::MaybeDef;
@@ -34,6 +37,9 @@ pub fn check(
3437
}
3538

3639
let span = cx.tcx.def_span(owner_id);
40+
if !headers.examples {
41+
span_lint(cx, MISSING_EXAMPLES_DOC, span, "docs missing `# Examples` section");
42+
}
3743
match (headers.safety, sig.header.safety()) {
3844
(false, Safety::Unsafe) => span_lint(
3945
cx,

clippy_lints/src/doc/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,33 @@ declare_clippy_lint! {
211211
"`pub fn` may panic without `# Panics` in doc comment"
212212
}
213213

214+
declare_clippy_lint! {
215+
/// ### What it does
216+
/// Checks the doc comments of publicly visible functions and warns if
217+
/// there is no `# Examples` section.
218+
///
219+
/// ### Why is this bad?
220+
/// Examples help readers better understand how and why to use the function.
221+
///
222+
/// ### Examples
223+
/// The following function has an `# Examples` section in its doc comment:
224+
///
225+
/// ```
226+
/// /// # Examples
227+
/// ///
228+
/// /// ```
229+
/// /// assert_eq!(bikeshed_color(), "blue");
230+
/// /// ```
231+
/// pub fn bikeshed_color() -> &str {
232+
/// "blue"
233+
/// }
234+
/// ```
235+
#[clippy::version = "1.92.0"]
236+
pub MISSING_EXAMPLES_DOC,
237+
pedantic,
238+
"`pub fn` without `# Examples` in doc comment"
239+
}
240+
214241
declare_clippy_lint! {
215242
/// ### What it does
216243
/// Checks for `fn main() { .. }` in doctests
@@ -721,6 +748,7 @@ impl_lint_pass!(Documentation => [
721748
MISSING_SAFETY_DOC,
722749
MISSING_ERRORS_DOC,
723750
MISSING_PANICS_DOC,
751+
MISSING_EXAMPLES_DOC,
724752
NEEDLESS_DOCTEST_MAIN,
725753
TEST_ATTR_IN_DOCTEST,
726754
UNNECESSARY_SAFETY_DOC,
@@ -832,10 +860,12 @@ impl Fragments<'_> {
832860
}
833861

834862
#[derive(Copy, Clone, Default)]
863+
#[expect(clippy::struct_excessive_bools)]
835864
struct DocHeaders {
836865
safety: bool,
837866
errors: bool,
838867
panics: bool,
868+
examples: bool,
839869
first_paragraph_len: usize,
840870
}
841871

@@ -1282,6 +1312,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
12821312
headers.safety |= in_heading && trimmed_text == "Implementation Safety";
12831313
headers.errors |= in_heading && trimmed_text == "Errors";
12841314
headers.panics |= in_heading && trimmed_text == "Panics";
1315+
headers.examples |= in_heading && trimmed_text == "Examples";
12851316

12861317
if let Some(tags) = code {
12871318
if tags.rust && !tags.compile_fail && !tags.ignore {

tests/dogfood.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,16 @@ fn run_clippy_for_package(project: &str) -> bool {
8282

8383
command.arg("--");
8484
command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
85-
command.args(["-D", "clippy::all", "-D", "clippy::pedantic", "-D", "clippy::dbg_macro"]);
85+
command.args([
86+
"-D",
87+
"clippy::all",
88+
"-D",
89+
"clippy::pedantic",
90+
"-D",
91+
"clippy::dbg_macro",
92+
"-A",
93+
"clippy::missing_examples_doc",
94+
]);
8695
if !cfg!(feature = "internal") {
8796
// running a clippy built without internal lints on the clippy source
8897
// that contains e.g. `allow(clippy::symbol_as_str)`

tests/ui/doc_examples.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![warn(clippy::missing_examples_doc)]
2+
3+
pub fn pub_fn_missing_docs() {
4+
//~^ missing_examples_doc
5+
unimplemented!();
6+
}
7+
8+
/// Docs without examples
9+
pub fn pub_fn_missing_examples() {
10+
//~^ missing_examples_doc
11+
unimplemented!();
12+
}
13+
14+
/// Docs with examples
15+
///
16+
/// # Examples
17+
///
18+
/// ```
19+
/// pub_fn_missing_examples()
20+
/// ```
21+
pub fn pub_fn_with_examples() {
22+
unimplemented!();
23+
}
24+
25+
fn priv_fn_missing_docs() {
26+
unimplemented!();
27+
}
28+
29+
#[doc(hidden)]
30+
pub fn hidden_fn_missing_docs() {
31+
unimplemented!();
32+
}

tests/ui/doc_examples.stderr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: docs missing `# Examples` section
2+
--> tests/ui/doc_examples.rs:3:1
3+
|
4+
LL | pub fn pub_fn_missing_docs() {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::missing-examples-doc` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::missing_examples_doc)]`
9+
10+
error: docs missing `# Examples` section
11+
--> tests/ui/doc_examples.rs:9:1
12+
|
13+
LL | pub fn pub_fn_missing_examples() {
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error: aborting due to 2 previous errors
17+

0 commit comments

Comments
 (0)