1- use crate :: utils:: paths;
2- use crate :: utils:: { is_copy, match_type, snippet, span_lint , span_note_and_lint } ;
1+ use crate :: utils:: { differing_macro_contexts , paths, snippet_with_applicability , span_lint_and_then } ;
2+ use crate :: utils:: { is_copy, match_type, snippet} ;
33use rustc:: hir:: intravisit:: { walk_path, NestedVisitorMap , Visitor } ;
44use rustc:: hir:: { self , * } ;
55use rustc:: lint:: LateContext ;
66use rustc_data_structures:: fx:: FxHashSet ;
7+ use rustc_errors:: Applicability ;
8+ use syntax:: source_map:: Span ;
79use syntax_pos:: symbol:: Symbol ;
810
911use super :: OPTION_MAP_UNWRAP_OR ;
@@ -14,6 +16,7 @@ pub(super) fn lint<'a, 'tcx>(
1416 expr : & hir:: Expr ,
1517 map_args : & ' tcx [ hir:: Expr ] ,
1618 unwrap_args : & ' tcx [ hir:: Expr ] ,
19+ map_span : Span ,
1720) {
1821 // lint if the caller of `map()` is an `Option`
1922 if match_type ( cx, cx. tables . expr_ty ( & map_args[ 0 ] ) , & paths:: OPTION ) {
@@ -39,9 +42,13 @@ pub(super) fn lint<'a, 'tcx>(
3942 }
4043 }
4144
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) ;
4552 // lint message
4653 // comparing the snippet from source to raw text ("None") below is safe
4754 // because we already have checked the type.
@@ -56,24 +63,20 @@ pub(super) fn lint<'a, 'tcx>(
5663 This can be done more directly by calling `{}` instead",
5764 arg, suggest
5865 ) ;
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
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,
7278 ) ;
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- } ;
79+ } ) ;
7780 }
7881}
7982
0 commit comments