1
- use crate :: utils:: paths;
2
- use crate :: utils:: { is_copy, match_type, snippet, span_lint , span_note_and_lint } ;
1
+ use crate :: utils:: { paths, span_lint_and_then , snippet_with_applicability , differing_macro_contexts } ;
2
+ use crate :: utils:: { is_copy, match_type, snippet} ;
3
3
use rustc:: hir:: intravisit:: { walk_path, NestedVisitorMap , Visitor } ;
4
4
use rustc:: hir:: { self , * } ;
5
5
use rustc:: lint:: LateContext ;
6
6
use rustc_data_structures:: fx:: FxHashSet ;
7
7
use syntax_pos:: symbol:: Symbol ;
8
+ use syntax:: source_map:: Span ;
9
+ use rustc_errors:: Applicability ;
8
10
9
11
use super :: OPTION_MAP_UNWRAP_OR ;
10
12
@@ -14,6 +16,7 @@ pub(super) fn lint<'a, 'tcx>(
14
16
expr : & hir:: Expr ,
15
17
map_args : & ' tcx [ hir:: Expr ] ,
16
18
unwrap_args : & ' tcx [ hir:: Expr ] ,
19
+ map_span : Span ,
17
20
) {
18
21
// lint if the caller of `map()` is an `Option`
19
22
if match_type ( cx, cx. tables . expr_ty ( & map_args[ 0 ] ) , & paths:: OPTION ) {
@@ -39,9 +42,13 @@ pub(super) fn lint<'a, 'tcx>(
39
42
}
40
43
}
41
44
42
- // get snippets for args to map() and unwrap_or()
43
- let map_snippet = snippet ( cx, map_args[ 1 ] . span , ".." ) ;
44
- let unwrap_snippet = snippet ( cx, unwrap_args[ 1 ] . span , ".." ) ;
45
+ if differing_macro_contexts ( unwrap_args[ 1 ] . span , map_span) {
46
+ return ;
47
+ }
48
+
49
+ let mut applicability = Applicability :: MachineApplicable ;
50
+ // get snippet for unwrap_or()
51
+ let unwrap_snippet = snippet_with_applicability ( cx, unwrap_args[ 1 ] . span , ".." , & mut applicability) ;
45
52
// lint message
46
53
// comparing the snippet from source to raw text ("None") below is safe
47
54
// because we already have checked the type.
@@ -56,24 +63,21 @@ pub(super) fn lint<'a, 'tcx>(
56
63
This can be done more directly by calling `{}` instead",
57
64
arg, suggest
58
65
) ;
59
- // lint, with note if neither arg is > 1 line and both map() and
60
- // unwrap_or() have the same span
61
- let multiline = map_snippet. lines ( ) . count ( ) > 1 || unwrap_snippet. lines ( ) . count ( ) > 1 ;
62
- let same_span = map_args[ 1 ] . span . ctxt ( ) == unwrap_args[ 1 ] . span . ctxt ( ) ;
63
- if same_span && !multiline {
64
- let suggest = if unwrap_snippet == "None" {
65
- format ! ( "and_then({})" , map_snippet)
66
- } else {
67
- format ! ( "map_or({}, {})" , unwrap_snippet, map_snippet)
68
- } ;
69
- let note = format ! (
70
- "replace `map({}).unwrap_or({})` with `{}`" ,
71
- map_snippet, unwrap_snippet, suggest
72
- ) ;
73
- span_note_and_lint ( cx, OPTION_MAP_UNWRAP_OR , expr. span , msg, expr. span , & note) ;
74
- } else if same_span && multiline {
75
- span_lint ( cx, OPTION_MAP_UNWRAP_OR , expr. span , msg) ;
76
- } ;
66
+
67
+ span_lint_and_then ( cx, OPTION_MAP_UNWRAP_OR , expr. span , msg, |db| {
68
+ let map_arg_span = map_args[ 1 ] . span ;
69
+
70
+ db. multipart_suggestion (
71
+ "use `map_or` instead" ,
72
+ vec ! [
73
+ ( map_span, String :: from( "map_or" ) ) ,
74
+ ( expr. span. with_lo( unwrap_args[ 0 ] . span. hi( ) ) , String :: from( "" ) ) ,
75
+ ( map_arg_span. with_hi( map_arg_span. lo( ) ) , format!( "{}, " , unwrap_snippet) )
76
+ ] ,
77
+ applicability
78
+ ) ;
79
+ }
80
+ ) ;
77
81
}
78
82
}
79
83
0 commit comments