Skip to content

Commit db2fbb1

Browse files
committed
Auto merge of rust-lang#5181 - daxpedda:future-missing-errors-doc, r=flip1995
Expand `missing_errors_doc` to also work on async functions This adds the `missing_errors_doc` lint to async functions. changelog: Make [`missing_errors_doc`] lint also trigger on `async` functions
2 parents b91ae16 + ea5ac40 commit db2fbb1

File tree

4 files changed

+105
-17
lines changed

4 files changed

+105
-17
lines changed

clippy_lints/src/doc.rs

+39-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use crate::utils::{is_entrypoint_fn, match_type, paths, return_ty, span_lint};
1+
use crate::utils::{get_trait_def_id, implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint};
2+
use if_chain::if_chain;
23
use itertools::Itertools;
34
use rustc::lint::in_external_macro;
5+
use rustc::ty;
46
use rustc_data_structures::fx::FxHashSet;
57
use rustc_hir as hir;
68
use rustc_lint::{LateContext, LateLintPass};
@@ -152,11 +154,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown {
152154
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
153155
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
154156
match item.kind {
155-
hir::ItemKind::Fn(ref sig, ..) => {
157+
hir::ItemKind::Fn(ref sig, _, body_id) => {
156158
if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id))
157159
|| in_external_macro(cx.tcx.sess, item.span))
158160
{
159-
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
161+
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
160162
}
161163
},
162164
hir::ItemKind::Impl {
@@ -179,7 +181,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown {
179181
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
180182
if let hir::TraitItemKind::Method(ref sig, ..) = item.kind {
181183
if !in_external_macro(cx.tcx.sess, item.span) {
182-
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
184+
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None);
183185
}
184186
}
185187
}
@@ -189,8 +191,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown {
189191
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
190192
return;
191193
}
192-
if let hir::ImplItemKind::Method(ref sig, ..) = item.kind {
193-
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
194+
if let hir::ImplItemKind::Method(ref sig, body_id) = item.kind {
195+
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
194196
}
195197
}
196198
}
@@ -201,6 +203,7 @@ fn lint_for_missing_headers<'a, 'tcx>(
201203
span: impl Into<MultiSpan> + Copy,
202204
sig: &hir::FnSig<'_>,
203205
headers: DocHeaders,
206+
body_id: Option<hir::BodyId>,
204207
) {
205208
if !cx.access_levels.is_exported(hir_id) {
206209
return; // Private functions do not require doc comments
@@ -213,13 +216,36 @@ fn lint_for_missing_headers<'a, 'tcx>(
213216
"unsafe function's docs miss `# Safety` section",
214217
);
215218
}
216-
if !headers.errors && match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
217-
span_lint(
218-
cx,
219-
MISSING_ERRORS_DOC,
220-
span,
221-
"docs for function returning `Result` missing `# Errors` section",
222-
);
219+
if !headers.errors {
220+
if match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
221+
span_lint(
222+
cx,
223+
MISSING_ERRORS_DOC,
224+
span,
225+
"docs for function returning `Result` missing `# Errors` section",
226+
);
227+
} else {
228+
if_chain! {
229+
if let Some(body_id) = body_id;
230+
if let Some(future) = get_trait_def_id(cx, &paths::FUTURE);
231+
let def_id = cx.tcx.hir().body_owner_def_id(body_id);
232+
let mir = cx.tcx.optimized_mir(def_id);
233+
let ret_ty = mir.return_ty();
234+
if implements_trait(cx, ret_ty, future, &[]);
235+
if let ty::Opaque(_, subs) = ret_ty.kind;
236+
if let Some(gen) = subs.types().next();
237+
if let ty::Generator(_, subs, _) = gen.kind;
238+
if match_type(cx, subs.as_generator().return_ty(def_id, cx.tcx), &paths::RESULT);
239+
then {
240+
span_lint(
241+
cx,
242+
MISSING_ERRORS_DOC,
243+
span,
244+
"docs for function returning `Result` missing `# Errors` section",
245+
);
246+
}
247+
}
248+
}
223249
}
224250
}
225251

clippy_lints/src/utils/paths.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments
3636
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
3737
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
3838
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
39+
pub const FUTURE: [&str; 3] = ["std", "future", "Future"];
3940
pub const HASH: [&str; 2] = ["hash", "Hash"];
4041
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
4142
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];

tests/ui/doc_errors.rs

+37
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// compile-flags: --edition 2018
12
#![warn(clippy::missing_errors_doc)]
23

34
use std::io;
@@ -6,22 +7,42 @@ pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
67
unimplemented!();
78
}
89

10+
pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
11+
unimplemented!();
12+
}
13+
914
/// This is not sufficiently documented.
1015
pub fn pub_fn_returning_io_result() -> io::Result<()> {
1116
unimplemented!();
1217
}
1318

19+
/// This is not sufficiently documented.
20+
pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
21+
unimplemented!();
22+
}
23+
1424
/// # Errors
1525
/// A description of the errors goes here.
1626
pub fn pub_fn_with_errors_header() -> Result<(), ()> {
1727
unimplemented!();
1828
}
1929

30+
/// # Errors
31+
/// A description of the errors goes here.
32+
pub async fn async_pub_fn_with_errors_header() -> Result<(), ()> {
33+
unimplemented!();
34+
}
35+
2036
/// This function doesn't require the documentation because it is private
2137
fn priv_fn_missing_errors_header() -> Result<(), ()> {
2238
unimplemented!();
2339
}
2440

41+
/// This function doesn't require the documentation because it is private
42+
async fn async_priv_fn_missing_errors_header() -> Result<(), ()> {
43+
unimplemented!();
44+
}
45+
2546
pub struct Struct1;
2647

2748
impl Struct1 {
@@ -30,16 +51,32 @@ impl Struct1 {
3051
unimplemented!();
3152
}
3253

54+
/// This is not sufficiently documented.
55+
pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
56+
unimplemented!();
57+
}
58+
3359
/// # Errors
3460
/// A description of the errors goes here.
3561
pub fn pub_method_with_errors_header() -> Result<(), ()> {
3662
unimplemented!();
3763
}
3864

65+
/// # Errors
66+
/// A description of the errors goes here.
67+
pub async fn async_pub_method_with_errors_header() -> Result<(), ()> {
68+
unimplemented!();
69+
}
70+
3971
/// This function doesn't require the documentation because it is private.
4072
fn priv_method_missing_errors_header() -> Result<(), ()> {
4173
unimplemented!();
4274
}
75+
76+
/// This function doesn't require the documentation because it is private.
77+
async fn async_priv_method_missing_errors_header() -> Result<(), ()> {
78+
unimplemented!();
79+
}
4380
}
4481

4582
pub trait Trait1 {

tests/ui/doc_errors.stderr

+28-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: docs for function returning `Result` missing `# Errors` section
2-
--> $DIR/doc_errors.rs:5:1
2+
--> $DIR/doc_errors.rs:6:1
33
|
44
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
55
LL | | unimplemented!();
@@ -11,24 +11,48 @@ LL | | }
1111
error: docs for function returning `Result` missing `# Errors` section
1212
--> $DIR/doc_errors.rs:10:1
1313
|
14+
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
15+
LL | | unimplemented!();
16+
LL | | }
17+
| |_^
18+
19+
error: docs for function returning `Result` missing `# Errors` section
20+
--> $DIR/doc_errors.rs:15:1
21+
|
1422
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
1523
LL | | unimplemented!();
1624
LL | | }
1725
| |_^
1826

1927
error: docs for function returning `Result` missing `# Errors` section
20-
--> $DIR/doc_errors.rs:29:5
28+
--> $DIR/doc_errors.rs:20:1
29+
|
30+
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
31+
LL | | unimplemented!();
32+
LL | | }
33+
| |_^
34+
35+
error: docs for function returning `Result` missing `# Errors` section
36+
--> $DIR/doc_errors.rs:50:5
2137
|
2238
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
2339
LL | | unimplemented!();
2440
LL | | }
2541
| |_____^
2642

2743
error: docs for function returning `Result` missing `# Errors` section
28-
--> $DIR/doc_errors.rs:47:5
44+
--> $DIR/doc_errors.rs:55:5
45+
|
46+
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
47+
LL | | unimplemented!();
48+
LL | | }
49+
| |_____^
50+
51+
error: docs for function returning `Result` missing `# Errors` section
52+
--> $DIR/doc_errors.rs:84:5
2953
|
3054
LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
3155
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3256

33-
error: aborting due to 4 previous errors
57+
error: aborting due to 7 previous errors
3458

0 commit comments

Comments
 (0)