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;
23use itertools:: Itertools ;
34use rustc:: lint:: in_external_macro;
5+ use rustc:: ty;
46use rustc_data_structures:: fx:: FxHashSet ;
57use rustc_hir as hir;
68use 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
@@ -398,7 +424,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
398424 headers
399425}
400426
401- static LEAVE_MAIN_PATTERNS : & [ & str ] = & [ "static" , "fn main() {}" , "extern crate" ] ;
427+ static LEAVE_MAIN_PATTERNS : & [ & str ] = & [ "static" , "fn main() {}" , "extern crate" , "async fn main() {" ] ;
402428
403429fn check_code ( cx : & LateContext < ' _ , ' _ > , text : & str , span : Span ) {
404430 if text. contains ( "fn main() {" ) && !LEAVE_MAIN_PATTERNS . iter ( ) . any ( |p| text. contains ( p) ) {
0 commit comments