3
3
#![ feature( let_chains) ]
4
4
5
5
extern crate rustc_hir;
6
- // extern crate rustc_middle;
7
6
extern crate rustc_span;
8
7
9
- use clippy_utils:: sym;
10
- use clippy_utils:: ty:: implements_trait;
11
- use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
12
- use rustc_hir:: { Expr , ExprKind } ;
8
+ use clippy_utils:: { get_trait_def_id, sym, ty:: implements_trait} ;
9
+ use rustc_hir:: {
10
+ def:: Res ,
11
+ intravisit:: { walk_expr, Visitor } ,
12
+ Expr , ExprKind , Node ,
13
+ } ;
13
14
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
14
- use rustc_span:: sym;
15
- // use rustc_middle::ty::TyKind;
16
- // use rustc_session::{declare_lint, declare_lint_pass};
17
- // use rustc_span::{Span, Symbol};
15
+ use rustc_span:: source_map:: SourceMap ;
18
16
use utils:: span_to_snippet_macro;
17
+
19
18
dylint_linting:: declare_late_lint! {
20
19
/// ### What it does
21
20
///
@@ -37,11 +36,54 @@ dylint_linting::declare_late_lint! {
37
36
"suggest using par iter"
38
37
}
39
38
40
- impl Visitor < ' _ > for ParIter {
39
+ struct ClosureVisitor < ' a , ' tcx > {
40
+ cx : & ' a LateContext < ' tcx > ,
41
+ is_valid : bool ,
42
+ }
43
+
44
+ struct Validator < ' a , ' tcx > {
45
+ cx : & ' a LateContext < ' tcx > ,
46
+ is_valid : bool ,
47
+ }
48
+ impl < ' a , ' tcx > Visitor < ' _ > for ClosureVisitor < ' a , ' tcx > {
49
+ fn visit_expr ( & mut self , ex : & Expr ) {
50
+ match ex. kind {
51
+ ExprKind :: Path ( path) => {
52
+ let res: Res = self . cx . typeck_results ( ) . qpath_res ( & path, ex. hir_id ) ;
53
+
54
+ if let Res :: Local ( hir_id) = res {
55
+ let ty = self . cx . tcx . type_of ( hir_id) ;
56
+
57
+ let hir = self . cx . tcx . hir ( ) ;
58
+ if let Some ( node) = hir. find ( hir_id) {
59
+ if let rustc_hir:: Node :: Pat ( pat) = node {
60
+ let ty = self . cx . tcx . pat_ty ( pat) ;
61
+ let ty = typeck_results. pat_ty ( pat) ;
62
+
63
+ implements_trait ( self . cx , ty, trait_id, args) ;
64
+ self . is_valid = true ;
65
+ }
66
+ }
67
+ }
68
+ }
69
+ _ => walk_expr ( self , ex) ,
70
+ }
71
+ }
72
+ }
73
+
74
+ impl < ' a , ' tcx > Visitor < ' _ > for Validator < ' a , ' tcx > {
41
75
fn visit_expr ( & mut self , ex : & Expr ) {
42
76
match ex. kind {
43
- ExprKind :: Closure ( _c) => {
44
- dbg ! ( "got a closure" ) ;
77
+ ExprKind :: Closure ( closure) => {
78
+ let hir = self . cx . tcx . hir ( ) ;
79
+ let node = hir. get ( closure. body . hir_id ) ;
80
+ if let Node :: Expr ( expr) = node {
81
+ let mut closure_visitor = ClosureVisitor {
82
+ cx : self . cx ,
83
+ is_valid : true ,
84
+ } ;
85
+ closure_visitor. visit_expr ( expr) ;
86
+ }
45
87
}
46
88
_ => walk_expr ( self , ex) ,
47
89
}
@@ -50,34 +92,52 @@ impl Visitor<'_> for ParIter {
50
92
51
93
impl < ' tcx > LateLintPass < ' tcx > for ParIter {
52
94
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
53
- if let ExprKind :: MethodCall ( path, _recv, args, span) = & expr. kind
54
- && path. ident . name == sym ! ( into_iter)
95
+ if let ExprKind :: MethodCall ( path, _recv, _args, _span) = & expr. kind
96
+ && ( path. ident . name == sym ! ( into_iter)
97
+ || path. ident . name == sym ! ( iter)
98
+ || path. ident . name == sym ! ( iter_mut) )
55
99
{
56
- let src_map = cx. sess ( ) . source_map ( ) ;
57
100
let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
58
101
59
- // into_par_iter
60
- let trait_def_id =
61
- clippy_utils:: get_trait_def_id ( cx, & [ "rayon" , "iter" , "IntoParallelIterator" ] )
62
- . unwrap ( ) ;
63
-
64
- if implements_trait ( cx, ty, trait_def_id, & [ ] ) {
65
- // check that iterator type is Send
66
- let is_send = cx. tcx . get_diagnostic_item ( sym:: Send ) . map_or ( false , |id| {
67
- implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( expr) , id, & [ ] )
68
- } ) ;
69
- if !is_send {
70
- return ;
102
+ let mut implements_par_iter = false ;
103
+
104
+ let trait_defs = vec ! [
105
+ get_trait_def_id( cx, & [ "rayon" , "iter" , "IntoParallelIterator" ] ) ,
106
+ get_trait_def_id( cx, & [ "rayon" , "iter" , "ParallelIterator" ] ) ,
107
+ // @todo get_trait_def_id(cx, &["rayon", "iter", "IndexedParallelIterator"]),
108
+ // @todo get_trait_def_id(cx, &["rayon", "iter", "IntoParallelRefIterator"]),
109
+ // @todo get_trait_def_id(cx, &["rayon", "iter", "IntoParallelRefMutIterator"]),
110
+ ] ;
111
+
112
+ for t in trait_defs {
113
+ if let Some ( trait_def_id) = t {
114
+ implements_par_iter =
115
+ implements_par_iter || implements_trait ( cx, ty, trait_def_id, & [ ] ) ;
71
116
}
72
- // @todo check that all types inside the closures are Send and sync or Copy
117
+ }
73
118
74
- let id_snip = span_to_snippet_macro ( src_map , expr . span ) ;
75
- dbg ! ( id_snip ) ;
119
+ if !implements_par_iter {
120
+ return ;
76
121
}
122
+ dbg ! ( "implements_par_iter" ) ;
123
+
124
+ // @todo check that all types inside the closures are Send and sync or Copy
125
+ let mut validator = Validator { cx, is_valid : true } ;
126
+ let hir = cx. tcx . hir ( ) ;
77
127
78
- // @todo par_iter
128
+ let parent_node = hir. get_parent ( expr. hir_id ) ;
129
+ match parent_node {
130
+ Node :: Expr ( expr) => {
131
+ validator. visit_expr ( expr) ;
132
+ }
133
+ // Handle other kinds of parent nodes as needed
134
+ _ => { }
135
+ }
136
+ if !validator. is_valid {
137
+ return ;
138
+ }
79
139
80
- // @todo par_iter_mut
140
+ dbg ! ( "the END" ) ;
81
141
}
82
142
}
83
143
}
0 commit comments