@@ -12,36 +12,91 @@ pub(super) fn check<'tcx>(
12
12
cx : & LateContext < ' _ > ,
13
13
map_span : Span ,
14
14
map_name : & str ,
15
- map_clos : & ' tcx Expr < ' _ > ,
15
+ map_param : & ' tcx Expr < ' _ > ,
16
16
transformer_name : & str ,
17
- transformer_clos : & ' tcx Expr < ' _ > ,
17
+ // Use the last parameter of the transformer because the transfomer may be `fold(_, _)`
18
+ transformer_last_param : & ' tcx Expr < ' _ > ,
18
19
) {
19
- if_chain ! (
20
- // takes a closure of the `map`
21
- if let ExprKind :: Closure ( _, _, map_clos_body_id, _, _) = & map_clos. kind;
22
- // checks if the body of the closure of the `map` is an one-line expression
23
- let map_clos_val = & cx. tcx. hir( ) . body( * map_clos_body_id) . value;
24
- if is_one_line( cx, map_clos_val. span) ;
20
+ match & transformer_last_param. kind {
21
+ ExprKind :: Closure ( _, _, transformer_clos_body_id, _, _) => {
22
+ match & map_param. kind {
23
+ // map(Closure).<transformer>(Closure)
24
+ ExprKind :: Closure ( _, _, map_clos_body_id, _, _) => {
25
+ let map_clos_val = & cx. tcx . hir ( ) . body ( * map_clos_body_id) . value ;
26
+ if_chain ! (
27
+ // checks if the body of the closure of the `map` is an one-line expression
28
+ if is_one_line( cx, map_clos_val. span) ;
29
+ // checks if the parameter of the closure of the transformer appears once in its body
30
+ if let Some ( refd_param_span) = refd_param_span( cx, * transformer_clos_body_id) ;
31
+ then {
32
+ span_lint_and_then(
33
+ cx,
34
+ MAP_THEN_IDENTITY_TRANSFORMER ,
35
+ MultiSpan :: from_span( map_span) ,
36
+ & format!( "this `{map_name}` can be collapsed into the `{transformer_name}`" ) ,
37
+ |diag| {
38
+ let mut help_span = MultiSpan :: from_spans( vec![ map_clos_val. span, refd_param_span] ) ;
39
+ help_span. push_span_label( refd_param_span, "replace this variable" . into( ) ) ;
40
+ help_span. push_span_label( map_clos_val. span, "with this expression" . into( ) ) ;
41
+ diag. span_help( help_span, & format!( "these `{map_name}` and `{transformer_name}` can be merged into a single `{transformer_name}`" ) ) ;
42
+ } ,
43
+ ) ;
44
+ }
25
45
26
- // takes a closure of the transformer
27
- if let ExprKind :: Closure ( _, _, transformer_clos_body_id, _, _) = & transformer_clos. kind;
28
- // checks if the parameter of the closure of the transformer appears once in its body
29
- if let Some ( refd_param_span) = refd_param_span( cx, * transformer_clos_body_id) ;
30
- then {
31
- span_lint_and_then(
32
- cx,
33
- MAP_THEN_IDENTITY_TRANSFORMER ,
34
- MultiSpan :: from_span( map_span) ,
35
- & format!( "this `{map_name}` can be collapsed into the `{transformer_name}`" ) ,
36
- |diag| {
37
- let mut help_span = MultiSpan :: from_spans( vec![ map_clos_val. span, refd_param_span] ) ;
38
- help_span. push_span_label( refd_param_span, "replace this variable" . into( ) ) ;
39
- help_span. push_span_label( map_clos_val. span, "with this expression" . into( ) ) ;
40
- diag. span_help( help_span, & format!( "these `{map_name}` and `{transformer_name}` can be merged into a single `{transformer_name}`" ) ) ;
46
+ ) ;
47
+ } ,
48
+ // map(Path).<transformer>(Closure)
49
+ ExprKind :: Path ( _) => {
50
+ if_chain ! (
51
+ // checks if the parameter of the `map` fits within one line
52
+ if is_one_line( cx, map_param. span) ;
53
+ // checks if the parameter of the closure of the transformer appears once in its body
54
+ if let Some ( refd_param_span) = refd_param_span( cx, * transformer_clos_body_id) ;
55
+ then {
56
+ span_lint_and_then(
57
+ cx,
58
+ MAP_THEN_IDENTITY_TRANSFORMER ,
59
+ MultiSpan :: from_span( map_span) ,
60
+ & format!( "this `{map_name}` can be collapsed into the `{transformer_name}`" ) ,
61
+ |diag| {
62
+ let mut help_span = MultiSpan :: from_spans( vec![ map_param. span, refd_param_span] ) ;
63
+ help_span. push_span_label( map_param. span, "apply this" . into( ) ) ;
64
+ help_span. push_span_label( refd_param_span, "to this variable" . into( ) ) ;
65
+ diag. span_help( help_span, & format!( "these `{map_name}` and `{transformer_name}` can be merged into a single `{transformer_name}`" ) ) ;
66
+ } ,
67
+ ) ;
68
+ }
69
+
70
+ ) ;
41
71
} ,
72
+ _ => ( ) ,
73
+ }
74
+ } ,
75
+ // map(Path).<transformer>(Path) or map(Closure).<transformer>(Path)
76
+ ExprKind :: Path ( _) => {
77
+ if_chain ! (
78
+ // checks if the parameter of the `map` fits within one line
79
+ if is_one_line( cx, map_param. span) ;
80
+ then {
81
+ span_lint_and_then(
82
+ cx,
83
+ MAP_THEN_IDENTITY_TRANSFORMER ,
84
+ MultiSpan :: from_span( map_span) ,
85
+ & format!( "this `{map_name}` can be collapsed into the `{transformer_name}`" ) ,
86
+ |diag| {
87
+ let mut help_span = MultiSpan :: from_spans(
88
+ vec![ map_param. span, transformer_last_param. span]
89
+ ) ;
90
+ help_span. push_span_label( map_param. span, format!( "and use this in the `{transformer_name}`" ) ) ;
91
+ help_span. push_span_label( transformer_last_param. span, "change this to a closure" . into( ) ) ;
92
+ diag. span_help( help_span, & format!( "these `{map_name}` and `{transformer_name}` can be merged into a single `{transformer_name}`" ) ) ;
93
+ } ,
94
+ ) ;
95
+ }
42
96
) ;
43
- }
44
- ) ;
97
+ } ,
98
+ _ => ( ) ,
99
+ }
45
100
}
46
101
47
102
// Given a closure `|.., x| y`, checks if `x` is referenced just exactly once in `y` and returns
0 commit comments