1+ mod must_use;
12mod not_unsafe_ptr_arg_deref;
23mod too_many_arguments;
34mod too_many_lines;
45
5- use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_then} ;
6- use clippy_utils:: source:: snippet_opt;
7- use clippy_utils:: ty:: { is_must_use_ty, is_type_diagnostic_item} ;
8- use clippy_utils:: { attr_by_name, attrs:: is_proc_macro, match_def_path, must_use_attr, return_ty, trait_ref_of_method} ;
6+ use clippy_utils:: diagnostics:: span_lint_and_help;
7+ use clippy_utils:: trait_ref_of_method;
8+ use clippy_utils:: ty:: is_type_diagnostic_item;
99use if_chain:: if_chain;
10- use rustc_ast:: ast:: Attribute ;
11- use rustc_data_structures:: fx:: FxHashSet ;
12- use rustc_errors:: Applicability ;
1310use rustc_hir as hir;
1411use rustc_hir:: intravisit;
15- use rustc_hir:: { def:: Res , def_id:: DefId , QPath } ;
1612use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
17- use rustc_middle:: hir:: map:: Map ;
1813use rustc_middle:: lint:: in_external_macro;
19- use rustc_middle:: ty:: { self , Ty } ;
14+ use rustc_middle:: ty;
2015use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
2116use rustc_span:: { sym, Span } ;
2217use rustc_typeck:: hir_ty_to_ty;
@@ -260,88 +255,38 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
260255 }
261256
262257 fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' _ > ) {
263- let attrs = cx. tcx . hir ( ) . attrs ( item. hir_id ( ) ) ;
264- let attr = must_use_attr ( attrs) ;
265- if let hir:: ItemKind :: Fn ( ref sig, ref _generics, ref body_id) = item. kind {
258+ must_use:: check_item ( cx, item) ;
259+ if let hir:: ItemKind :: Fn ( ref sig, ref _generics, _) = item. kind {
266260 let is_public = cx. access_levels . is_exported ( item. hir_id ( ) ) ;
267261 let fn_header_span = item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ;
268262 if is_public {
269263 check_result_unit_err ( cx, & sig. decl , item. span , fn_header_span) ;
270264 }
271- if let Some ( attr) = attr {
272- check_needless_must_use ( cx, & sig. decl , item. hir_id ( ) , item. span , fn_header_span, attr) ;
273- return ;
274- }
275- if is_public && !is_proc_macro ( cx. sess ( ) , attrs) && attr_by_name ( attrs, "no_mangle" ) . is_none ( ) {
276- check_must_use_candidate (
277- cx,
278- & sig. decl ,
279- cx. tcx . hir ( ) . body ( * body_id) ,
280- item. span ,
281- item. hir_id ( ) ,
282- item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ,
283- "this function could have a `#[must_use]` attribute" ,
284- ) ;
285- }
286265 }
287266 }
288267
289268 fn check_impl_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: ImplItem < ' _ > ) {
290- if let hir:: ImplItemKind :: Fn ( ref sig, ref body_id) = item. kind {
269+ must_use:: check_impl_item ( cx, item) ;
270+ if let hir:: ImplItemKind :: Fn ( ref sig, _) = item. kind {
291271 let is_public = cx. access_levels . is_exported ( item. hir_id ( ) ) ;
292272 let fn_header_span = item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ;
293273 if is_public && trait_ref_of_method ( cx, item. hir_id ( ) ) . is_none ( ) {
294274 check_result_unit_err ( cx, & sig. decl , item. span , fn_header_span) ;
295275 }
296- let attrs = cx. tcx . hir ( ) . attrs ( item. hir_id ( ) ) ;
297- let attr = must_use_attr ( attrs) ;
298- if let Some ( attr) = attr {
299- check_needless_must_use ( cx, & sig. decl , item. hir_id ( ) , item. span , fn_header_span, attr) ;
300- } else if is_public && !is_proc_macro ( cx. sess ( ) , attrs) && trait_ref_of_method ( cx, item. hir_id ( ) ) . is_none ( )
301- {
302- check_must_use_candidate (
303- cx,
304- & sig. decl ,
305- cx. tcx . hir ( ) . body ( * body_id) ,
306- item. span ,
307- item. hir_id ( ) ,
308- item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ,
309- "this method could have a `#[must_use]` attribute" ,
310- ) ;
311- }
312276 }
313277 }
314278
315279 fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: TraitItem < ' _ > ) {
316280 too_many_arguments:: check_trait_item ( cx, item, self . too_many_arguments_threshold ) ;
317281 not_unsafe_ptr_arg_deref:: check_trait_item ( cx, item) ;
282+ must_use:: check_trait_item ( cx, item) ;
318283
319- if let hir:: TraitItemKind :: Fn ( ref sig, ref eid ) = item. kind {
284+ if let hir:: TraitItemKind :: Fn ( ref sig, _ ) = item. kind {
320285 let is_public = cx. access_levels . is_exported ( item. hir_id ( ) ) ;
321286 let fn_header_span = item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ;
322287 if is_public {
323288 check_result_unit_err ( cx, & sig. decl , item. span , fn_header_span) ;
324289 }
325-
326- let attrs = cx. tcx . hir ( ) . attrs ( item. hir_id ( ) ) ;
327- let attr = must_use_attr ( attrs) ;
328- if let Some ( attr) = attr {
329- check_needless_must_use ( cx, & sig. decl , item. hir_id ( ) , item. span , fn_header_span, attr) ;
330- }
331- if let hir:: TraitFn :: Provided ( eid) = * eid {
332- let body = cx. tcx . hir ( ) . body ( eid) ;
333- if attr. is_none ( ) && is_public && !is_proc_macro ( cx. sess ( ) , attrs) {
334- check_must_use_candidate (
335- cx,
336- & sig. decl ,
337- body,
338- item. span ,
339- item. hir_id ( ) ,
340- item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ,
341- "this method could have a `#[must_use]` attribute" ,
342- ) ;
343- }
344- }
345290 }
346291 }
347292}
@@ -367,185 +312,3 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span
367312 }
368313 }
369314}
370-
371- fn check_needless_must_use (
372- cx : & LateContext < ' _ > ,
373- decl : & hir:: FnDecl < ' _ > ,
374- item_id : hir:: HirId ,
375- item_span : Span ,
376- fn_header_span : Span ,
377- attr : & Attribute ,
378- ) {
379- if in_external_macro ( cx. sess ( ) , item_span) {
380- return ;
381- }
382- if returns_unit ( decl) {
383- span_lint_and_then (
384- cx,
385- MUST_USE_UNIT ,
386- fn_header_span,
387- "this unit-returning function has a `#[must_use]` attribute" ,
388- |diag| {
389- diag. span_suggestion (
390- attr. span ,
391- "remove the attribute" ,
392- "" . into ( ) ,
393- Applicability :: MachineApplicable ,
394- ) ;
395- } ,
396- ) ;
397- } else if !attr. is_value_str ( ) && is_must_use_ty ( cx, return_ty ( cx, item_id) ) {
398- span_lint_and_help (
399- cx,
400- DOUBLE_MUST_USE ,
401- fn_header_span,
402- "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`" ,
403- None ,
404- "either add some descriptive text or remove the attribute" ,
405- ) ;
406- }
407- }
408-
409- fn check_must_use_candidate < ' tcx > (
410- cx : & LateContext < ' tcx > ,
411- decl : & ' tcx hir:: FnDecl < ' _ > ,
412- body : & ' tcx hir:: Body < ' _ > ,
413- item_span : Span ,
414- item_id : hir:: HirId ,
415- fn_span : Span ,
416- msg : & str ,
417- ) {
418- if has_mutable_arg ( cx, body)
419- || mutates_static ( cx, body)
420- || in_external_macro ( cx. sess ( ) , item_span)
421- || returns_unit ( decl)
422- || !cx. access_levels . is_exported ( item_id)
423- || is_must_use_ty ( cx, return_ty ( cx, item_id) )
424- {
425- return ;
426- }
427- span_lint_and_then ( cx, MUST_USE_CANDIDATE , fn_span, msg, |diag| {
428- if let Some ( snippet) = snippet_opt ( cx, fn_span) {
429- diag. span_suggestion (
430- fn_span,
431- "add the attribute" ,
432- format ! ( "#[must_use] {}" , snippet) ,
433- Applicability :: MachineApplicable ,
434- ) ;
435- }
436- } ) ;
437- }
438-
439- fn returns_unit ( decl : & hir:: FnDecl < ' _ > ) -> bool {
440- match decl. output {
441- hir:: FnRetTy :: DefaultReturn ( _) => true ,
442- hir:: FnRetTy :: Return ( ref ty) => match ty. kind {
443- hir:: TyKind :: Tup ( ref tys) => tys. is_empty ( ) ,
444- hir:: TyKind :: Never => true ,
445- _ => false ,
446- } ,
447- }
448- }
449-
450- fn has_mutable_arg ( cx : & LateContext < ' _ > , body : & hir:: Body < ' _ > ) -> bool {
451- let mut tys = FxHashSet :: default ( ) ;
452- body. params . iter ( ) . any ( |param| is_mutable_pat ( cx, & param. pat , & mut tys) )
453- }
454-
455- fn is_mutable_pat ( cx : & LateContext < ' _ > , pat : & hir:: Pat < ' _ > , tys : & mut FxHashSet < DefId > ) -> bool {
456- if let hir:: PatKind :: Wild = pat. kind {
457- return false ; // ignore `_` patterns
458- }
459- if cx. tcx . has_typeck_results ( pat. hir_id . owner . to_def_id ( ) ) {
460- is_mutable_ty ( cx, & cx. tcx . typeck ( pat. hir_id . owner ) . pat_ty ( pat) , pat. span , tys)
461- } else {
462- false
463- }
464- }
465-
466- static KNOWN_WRAPPER_TYS : & [ & [ & str ] ] = & [ & [ "alloc" , "rc" , "Rc" ] , & [ "std" , "sync" , "Arc" ] ] ;
467-
468- fn is_mutable_ty < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , span : Span , tys : & mut FxHashSet < DefId > ) -> bool {
469- match * ty. kind ( ) {
470- // primitive types are never mutable
471- ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Str => false ,
472- ty:: Adt ( ref adt, ref substs) => {
473- tys. insert ( adt. did ) && !ty. is_freeze ( cx. tcx . at ( span) , cx. param_env )
474- || KNOWN_WRAPPER_TYS . iter ( ) . any ( |path| match_def_path ( cx, adt. did , path) )
475- && substs. types ( ) . any ( |ty| is_mutable_ty ( cx, ty, span, tys) )
476- } ,
477- ty:: Tuple ( ref substs) => substs. types ( ) . any ( |ty| is_mutable_ty ( cx, ty, span, tys) ) ,
478- ty:: Array ( ty, _) | ty:: Slice ( ty) => is_mutable_ty ( cx, ty, span, tys) ,
479- ty:: RawPtr ( ty:: TypeAndMut { ty, mutbl } ) | ty:: Ref ( _, ty, mutbl) => {
480- mutbl == hir:: Mutability :: Mut || is_mutable_ty ( cx, ty, span, tys)
481- } ,
482- // calling something constitutes a side effect, so return true on all callables
483- // also never calls need not be used, so return true for them, too
484- _ => true ,
485- }
486- }
487-
488- struct StaticMutVisitor < ' a , ' tcx > {
489- cx : & ' a LateContext < ' tcx > ,
490- mutates_static : bool ,
491- }
492-
493- impl < ' a , ' tcx > intravisit:: Visitor < ' tcx > for StaticMutVisitor < ' a , ' tcx > {
494- type Map = Map < ' tcx > ;
495-
496- fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' _ > ) {
497- use hir:: ExprKind :: { AddrOf , Assign , AssignOp , Call , MethodCall } ;
498-
499- if self . mutates_static {
500- return ;
501- }
502- match expr. kind {
503- Call ( _, args) | MethodCall ( _, _, args, _) => {
504- let mut tys = FxHashSet :: default ( ) ;
505- for arg in args {
506- if self . cx . tcx . has_typeck_results ( arg. hir_id . owner . to_def_id ( ) )
507- && is_mutable_ty (
508- self . cx ,
509- self . cx . tcx . typeck ( arg. hir_id . owner ) . expr_ty ( arg) ,
510- arg. span ,
511- & mut tys,
512- )
513- && is_mutated_static ( arg)
514- {
515- self . mutates_static = true ;
516- return ;
517- }
518- tys. clear ( ) ;
519- }
520- } ,
521- Assign ( ref target, ..) | AssignOp ( _, ref target, _) | AddrOf ( _, hir:: Mutability :: Mut , ref target) => {
522- self . mutates_static |= is_mutated_static ( target)
523- } ,
524- _ => { } ,
525- }
526- }
527-
528- fn nested_visit_map ( & mut self ) -> intravisit:: NestedVisitorMap < Self :: Map > {
529- intravisit:: NestedVisitorMap :: None
530- }
531- }
532-
533- fn is_mutated_static ( e : & hir:: Expr < ' _ > ) -> bool {
534- use hir:: ExprKind :: { Field , Index , Path } ;
535-
536- match e. kind {
537- Path ( QPath :: Resolved ( _, path) ) => !matches ! ( path. res, Res :: Local ( _) ) ,
538- Path ( _) => true ,
539- Field ( ref inner, _) | Index ( ref inner, _) => is_mutated_static ( inner) ,
540- _ => false ,
541- }
542- }
543-
544- fn mutates_static < ' tcx > ( cx : & LateContext < ' tcx > , body : & ' tcx hir:: Body < ' _ > ) -> bool {
545- let mut v = StaticMutVisitor {
546- cx,
547- mutates_static : false ,
548- } ;
549- intravisit:: walk_expr ( & mut v, & body. value ) ;
550- v. mutates_static
551- }
0 commit comments