4
4
#![ allow( rustc:: untranslatable_diagnostic) ]
5
5
6
6
use either:: Either ;
7
- use hir:: ClosureKind ;
7
+ use hir:: { ClosureKind , Path } ;
8
8
use rustc_data_structures:: captures:: Captures ;
9
9
use rustc_data_structures:: fx:: FxIndexSet ;
10
10
use rustc_errors:: { codes:: * , struct_span_code_err, Applicability , Diag , MultiSpan } ;
@@ -31,12 +31,14 @@ use rustc_span::def_id::DefId;
31
31
use rustc_span:: def_id:: LocalDefId ;
32
32
use rustc_span:: hygiene:: DesugaringKind ;
33
33
use rustc_span:: symbol:: { kw, sym, Ident } ;
34
+ use rustc_span:: FileName ;
34
35
use rustc_span:: { BytePos , Span , Symbol } ;
35
36
use rustc_trait_selection:: infer:: InferCtxtExt ;
36
37
use rustc_trait_selection:: traits:: error_reporting:: suggestions:: TypeErrCtxtExt ;
37
38
use rustc_trait_selection:: traits:: error_reporting:: FindExprBySpan ;
38
39
use rustc_trait_selection:: traits:: { Obligation , ObligationCause , ObligationCtxt } ;
39
40
use std:: iter;
41
+ use std:: path:: PathBuf ;
40
42
41
43
use crate :: borrow_set:: TwoPhaseActivation ;
42
44
use crate :: borrowck_errors;
@@ -498,21 +500,98 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
498
500
self . suggest_cloning ( err, ty, expr, None ) ;
499
501
}
500
502
}
503
+
504
+ self . suggest_ref_for_dbg_args ( expr, span, move_span, err) ;
505
+
501
506
if let Some ( pat) = finder. pat {
502
- * in_pattern = true ;
503
- let mut sugg = vec ! [ ( pat. span. shrink_to_lo( ) , "ref " . to_string( ) ) ] ;
504
- if let Some ( pat) = finder. parent_pat {
505
- sugg. insert ( 0 , ( pat. span . shrink_to_lo ( ) , "ref " . to_string ( ) ) ) ;
506
- }
507
- err. multipart_suggestion_verbose (
508
- "borrow this binding in the pattern to avoid moving the value" ,
509
- sugg,
510
- Applicability :: MachineApplicable ,
507
+ // FIXME: any better way to check this?
508
+ let from_std = self . infcx . tcx . sess . opts . real_rust_source_base_dir . clone ( ) . map_or (
509
+ false ,
510
+ |root| {
511
+ let file_path =
512
+ match self . infcx . tcx . sess . source_map ( ) . span_to_filename ( move_span) {
513
+ FileName :: Real ( name) => {
514
+ name. clone ( ) . into_local_path ( ) . unwrap_or_default ( )
515
+ }
516
+ other => PathBuf :: from ( other. prefer_local ( ) . to_string ( ) ) ,
517
+ } ;
518
+ file_path. starts_with ( & root. join ( "library/std/" ) )
519
+ } ,
511
520
) ;
521
+ // it's useless to suggest inserting `ref` when the span comes from std library
522
+ // anyway, user can not modify std library in most cases, so let's keep it quite?
523
+ if !from_std {
524
+ * in_pattern = true ;
525
+ let mut sugg = vec ! [ ( pat. span. shrink_to_lo( ) , "ref " . to_string( ) ) ] ;
526
+ if let Some ( pat) = finder. parent_pat {
527
+ sugg. insert ( 0 , ( pat. span . shrink_to_lo ( ) , "ref " . to_string ( ) ) ) ;
528
+ }
529
+ err. multipart_suggestion_verbose (
530
+ "borrow this binding in the pattern to avoid moving the value" ,
531
+ sugg,
532
+ Applicability :: MachineApplicable ,
533
+ ) ;
534
+ }
512
535
}
513
536
}
514
537
}
515
538
539
+ // for dbg!(x) which may take onwership, suggest dbg!(&x) instead
540
+ // but here we actually does not checking the macro name is `dbg!`
541
+ // so that we may extend the scope a bit larger to cover more cases
542
+ fn suggest_ref_for_dbg_args (
543
+ & self ,
544
+ body : & hir:: Expr < ' _ > ,
545
+ span : Option < Span > ,
546
+ move_span : Span ,
547
+ err : & mut Diag < ' tcx > ,
548
+ ) {
549
+ // only suggest for macro
550
+ if move_span. source_callsite ( ) == move_span {
551
+ return ;
552
+ }
553
+ let sm = self . infcx . tcx . sess . source_map ( ) ;
554
+ let arg_code = if let Some ( span) = span
555
+ && let Ok ( code) = sm. span_to_snippet ( span)
556
+ {
557
+ code
558
+ } else {
559
+ return ;
560
+ } ;
561
+ struct MatchArgFinder {
562
+ expr_span : Span ,
563
+ match_arg_span : Option < Span > ,
564
+ arg_code : String ,
565
+ }
566
+ impl Visitor < ' _ > for MatchArgFinder {
567
+ fn visit_expr ( & mut self , e : & hir:: Expr < ' _ > ) {
568
+ // dbg! is expanded into a match pattern, we need to find the right argument span
569
+ if let hir:: ExprKind :: Match ( expr, ..) = & e. kind
570
+ && let hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
571
+ _,
572
+ path @ Path { segments : [ seg] , .. } ,
573
+ ) ) = & expr. kind
574
+ && seg. ident . name . as_str ( ) == & self . arg_code
575
+ && self . expr_span . source_callsite ( ) . contains ( expr. span )
576
+ {
577
+ self . match_arg_span = Some ( path. span ) ;
578
+ }
579
+ hir:: intravisit:: walk_expr ( self , e) ;
580
+ }
581
+ }
582
+
583
+ let mut finder = MatchArgFinder { expr_span : move_span, match_arg_span : None , arg_code } ;
584
+ finder. visit_expr ( body) ;
585
+ if let Some ( macro_arg_span) = finder. match_arg_span {
586
+ err. span_suggestion_verbose (
587
+ macro_arg_span. shrink_to_lo ( ) ,
588
+ "consider borrowing instead of transferring ownership" ,
589
+ "&" ,
590
+ Applicability :: MachineApplicable ,
591
+ ) ;
592
+ }
593
+ }
594
+
516
595
fn report_use_of_uninitialized (
517
596
& self ,
518
597
mpi : MovePathIndex ,
0 commit comments