4
4
#![ allow( rustc:: untranslatable_diagnostic) ]
5
5
6
6
use either:: Either ;
7
+ use hir:: Path ;
7
8
use rustc_data_structures:: captures:: Captures ;
8
9
use rustc_data_structures:: fx:: FxIndexSet ;
9
10
use rustc_errors:: { codes:: * , struct_span_code_err, Applicability , Diag , MultiSpan } ;
@@ -27,11 +28,13 @@ use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
27
28
use rustc_span:: def_id:: LocalDefId ;
28
29
use rustc_span:: hygiene:: DesugaringKind ;
29
30
use rustc_span:: symbol:: { kw, sym, Ident } ;
31
+ use rustc_span:: FileName ;
30
32
use rustc_span:: { BytePos , Span , Symbol } ;
31
33
use rustc_trait_selection:: infer:: InferCtxtExt ;
32
34
use rustc_trait_selection:: traits:: error_reporting:: FindExprBySpan ;
33
35
use rustc_trait_selection:: traits:: ObligationCtxt ;
34
36
use std:: iter;
37
+ use std:: path:: PathBuf ;
35
38
36
39
use crate :: borrow_set:: TwoPhaseActivation ;
37
40
use crate :: borrowck_errors;
@@ -463,19 +466,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
463
466
self . suggest_cloning ( err, ty, expr, move_span) ;
464
467
}
465
468
}
469
+
470
+ self . suggest_ref_for_dbg_args ( expr, span, move_span, err) ;
471
+
466
472
if let Some ( pat) = finder. pat {
467
- * in_pattern = true ;
468
- let mut sugg = vec ! [ ( pat. span. shrink_to_lo( ) , "ref " . to_string( ) ) ] ;
469
- if let Some ( pat) = finder. parent_pat {
470
- sugg. insert ( 0 , ( pat. span . shrink_to_lo ( ) , "ref " . to_string ( ) ) ) ;
471
- }
472
- err. multipart_suggestion_verbose (
473
- "borrow this binding in the pattern to avoid moving the value" ,
474
- sugg,
475
- Applicability :: MachineApplicable ,
473
+ // FIXME: any better way to check this?
474
+ let from_std = self . infcx . tcx . sess . opts . real_rust_source_base_dir . clone ( ) . map_or (
475
+ false ,
476
+ |root| {
477
+ let file_path =
478
+ match self . infcx . tcx . sess . source_map ( ) . span_to_filename ( move_span) {
479
+ FileName :: Real ( name) => {
480
+ name. clone ( ) . into_local_path ( ) . unwrap_or_default ( )
481
+ }
482
+ other => PathBuf :: from ( other. prefer_local ( ) . to_string ( ) ) ,
483
+ } ;
484
+ file_path. starts_with ( & root. join ( "library/std/" ) )
485
+ } ,
476
486
) ;
487
+ // it's useless to suggest inserting `ref` when the span comes from std library
488
+ // anyway, user can not modify std library in most cases, so let's keep it quite?
489
+ if !from_std {
490
+ * in_pattern = true ;
491
+ let mut sugg = vec ! [ ( pat. span. shrink_to_lo( ) , "ref " . to_string( ) ) ] ;
492
+ if let Some ( pat) = finder. parent_pat {
493
+ sugg. insert ( 0 , ( pat. span . shrink_to_lo ( ) , "ref " . to_string ( ) ) ) ;
494
+ }
495
+ err. multipart_suggestion_verbose (
496
+ "borrow this binding in the pattern to avoid moving the value" ,
497
+ sugg,
498
+ Applicability :: MachineApplicable ,
499
+ ) ;
500
+ }
501
+ }
502
+ }
503
+ }
504
+
505
+ // for dbg!(x) which may take onwership, suggest dbg!(&x) instead
506
+ // but here we actually does not checking the macro name is `dbg!`
507
+ // so that we may extend the scope a bit larger to cover more cases
508
+ fn suggest_ref_for_dbg_args (
509
+ & self ,
510
+ body : & hir:: Expr < ' _ > ,
511
+ span : Option < Span > ,
512
+ move_span : Span ,
513
+ err : & mut Diag < ' tcx > ,
514
+ ) {
515
+ // only suggest for macro
516
+ if move_span. source_callsite ( ) == move_span {
517
+ return ;
518
+ }
519
+ let sm = self . infcx . tcx . sess . source_map ( ) ;
520
+ let arg_code = if let Some ( span) = span
521
+ && let Ok ( code) = sm. span_to_snippet ( span)
522
+ {
523
+ code
524
+ } else {
525
+ return ;
526
+ } ;
527
+ struct MatchArgFinder {
528
+ expr_span : Span ,
529
+ match_arg_span : Option < Span > ,
530
+ arg_code : String ,
531
+ }
532
+ impl Visitor < ' _ > for MatchArgFinder {
533
+ fn visit_expr ( & mut self , e : & hir:: Expr < ' _ > ) {
534
+ // dbg! is expanded into a match pattern, we need to find the right argument span
535
+ if let hir:: ExprKind :: Match ( expr, ..) = & e. kind
536
+ && let hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
537
+ _,
538
+ path @ Path { segments : [ seg] , .. } ,
539
+ ) ) = & expr. kind
540
+ && seg. ident . name . as_str ( ) == & self . arg_code
541
+ && self . expr_span . source_callsite ( ) . contains ( expr. span )
542
+ {
543
+ self . match_arg_span = Some ( path. span ) ;
544
+ }
545
+ hir:: intravisit:: walk_expr ( self , e) ;
477
546
}
478
547
}
548
+
549
+ let mut finder = MatchArgFinder { expr_span : move_span, match_arg_span : None , arg_code } ;
550
+ finder. visit_expr ( body) ;
551
+ if let Some ( macro_arg_span) = finder. match_arg_span {
552
+ err. span_suggestion_verbose (
553
+ macro_arg_span. shrink_to_lo ( ) ,
554
+ "consider borrowing instead of transferring ownership" ,
555
+ "&" ,
556
+ Applicability :: MachineApplicable ,
557
+ ) ;
558
+ }
479
559
}
480
560
481
561
fn report_use_of_uninitialized (
0 commit comments