1
+ mod must_use;
1
2
mod not_unsafe_ptr_arg_deref;
2
3
mod too_many_arguments;
3
4
mod too_many_lines;
4
5
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;
9
9
use if_chain:: if_chain;
10
- use rustc_ast:: ast:: Attribute ;
11
- use rustc_data_structures:: fx:: FxHashSet ;
12
- use rustc_errors:: Applicability ;
13
10
use rustc_hir as hir;
14
11
use rustc_hir:: intravisit;
15
- use rustc_hir:: { def:: Res , def_id:: DefId , QPath } ;
16
12
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
17
- use rustc_middle:: hir:: map:: Map ;
18
13
use rustc_middle:: lint:: in_external_macro;
19
- use rustc_middle:: ty:: { self , Ty } ;
14
+ use rustc_middle:: ty;
20
15
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
21
16
use rustc_span:: { sym, Span } ;
22
17
use rustc_typeck:: hir_ty_to_ty;
@@ -260,88 +255,38 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
260
255
}
261
256
262
257
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 {
266
260
let is_public = cx. access_levels . is_exported ( item. hir_id ( ) ) ;
267
261
let fn_header_span = item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ;
268
262
if is_public {
269
263
check_result_unit_err ( cx, & sig. decl , item. span , fn_header_span) ;
270
264
}
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
- }
286
265
}
287
266
}
288
267
289
268
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 {
291
271
let is_public = cx. access_levels . is_exported ( item. hir_id ( ) ) ;
292
272
let fn_header_span = item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ;
293
273
if is_public && trait_ref_of_method ( cx, item. hir_id ( ) ) . is_none ( ) {
294
274
check_result_unit_err ( cx, & sig. decl , item. span , fn_header_span) ;
295
275
}
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
- }
312
276
}
313
277
}
314
278
315
279
fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: TraitItem < ' _ > ) {
316
280
too_many_arguments:: check_trait_item ( cx, item, self . too_many_arguments_threshold ) ;
317
281
not_unsafe_ptr_arg_deref:: check_trait_item ( cx, item) ;
282
+ must_use:: check_trait_item ( cx, item) ;
318
283
319
- if let hir:: TraitItemKind :: Fn ( ref sig, ref eid ) = item. kind {
284
+ if let hir:: TraitItemKind :: Fn ( ref sig, _ ) = item. kind {
320
285
let is_public = cx. access_levels . is_exported ( item. hir_id ( ) ) ;
321
286
let fn_header_span = item. span . with_hi ( sig. decl . output . span ( ) . hi ( ) ) ;
322
287
if is_public {
323
288
check_result_unit_err ( cx, & sig. decl , item. span , fn_header_span) ;
324
289
}
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
- }
345
290
}
346
291
}
347
292
}
@@ -367,185 +312,3 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span
367
312
}
368
313
}
369
314
}
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