Skip to content

Commit b82cfd5

Browse files
committed
WIP: par_iter almost working
1 parent a993954 commit b82cfd5

File tree

3 files changed

+211
-45
lines changed

3 files changed

+211
-45
lines changed

lints/par_iter/src/lib.rs

+92-32
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@
33
#![feature(let_chains)]
44

55
extern crate rustc_hir;
6-
// extern crate rustc_middle;
76
extern crate rustc_span;
87

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+
};
1314
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;
1816
use utils::span_to_snippet_macro;
17+
1918
dylint_linting::declare_late_lint! {
2019
/// ### What it does
2120
///
@@ -37,11 +36,54 @@ dylint_linting::declare_late_lint! {
3736
"suggest using par iter"
3837
}
3938

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> {
4175
fn visit_expr(&mut self, ex: &Expr) {
4276
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+
}
4587
}
4688
_ => walk_expr(self, ex),
4789
}
@@ -50,34 +92,52 @@ impl Visitor<'_> for ParIter {
5092

5193
impl<'tcx> LateLintPass<'tcx> for ParIter {
5294
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))
5599
{
56-
let src_map = cx.sess().source_map();
57100
let ty = cx.typeck_results().expr_ty(expr);
58101

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, &[]);
71116
}
72-
// @todo check that all types inside the closures are Send and sync or Copy
117+
}
73118

74-
let id_snip = span_to_snippet_macro(src_map, expr.span);
75-
dbg!(id_snip);
119+
if !implements_par_iter {
120+
return;
76121
}
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();
77127

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+
}
79139

80-
// @todo par_iter_mut
140+
dbg!("the END");
81141
}
82142
}
83143
}

lints/par_iter/ui/main.fixed

+62-5
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,71 @@
22

33
#[allow(unused_imports)]
44
use rayon::prelude::*;
5+
// use std::collections::LinkedList;
6+
// use std::rc::Rc;
57

68
fn main() {
9+
// warn_par_iter_simple();
10+
// warn_par_iter_simple_no_send();
11+
// warn_par_iter_simple_no_send_in_closure_body();
12+
// move_inside_closure();
13+
// warn_par_iter_simple_into_parallel_ref_iterator();
714
// warn_par_iter();
8-
warn_par_iter_simple();
15+
warn_par_complex();
16+
}
17+
18+
// fn warn_par_iter_simple() {
19+
// (0..100).into_iter().for_each(|x| println!("{:?}", x));
20+
// }
21+
22+
// fn move_inside_closure() {
23+
// let y = 100;
24+
// (0..100)
25+
// .into_iter()
26+
// .for_each(|x| println!("{:?}{:?}", x, y));
27+
// }
28+
// fn warn_par_iter_simple_no_send() {
29+
// let list: Vec<Rc<i32>> = (0..100).map(Rc::new).collect();
30+
// list.iter().for_each(|y| println!("{:?}", y));
31+
// }
32+
33+
// fn warn_par_iter_simple_no_send_in_closure_body() {
34+
// let mut list: Vec<Rc<i32>> = (0..100).map(Rc::new).collect();
35+
// (0..100).into_iter().for_each(|x| list.push(Rc::new(x)));
36+
// }
37+
38+
// fn warn_par_iter_simple_into_parallel_ref_iterator() {
39+
// let list: LinkedList<i32> = (0..100).collect();
40+
// list.into_iter().for_each(|x| println!("{:?}", x));
41+
// }
42+
43+
struct Person {
44+
name: String,
45+
age: u32,
46+
}
47+
48+
fn warn_par_complex() {
49+
let vec = vec![1, 2, 3, 4, 5, 6];
50+
let a = 10;
51+
let b = 20;
52+
let c = "Hello";
53+
let d = 3.14;
54+
let e = true;
55+
let person = Person {
56+
name: String::from("Alice"),
57+
age: 30,
58+
};
59+
60+
vec.iter().for_each(|x| {
61+
let sum = x + a + b;
62+
let message = if e { c } else { "Goodbye" };
63+
let product = d * (*x as f64);
64+
let person_info = format!("{} is {} years old.", person.name, person.age);
65+
println!(
66+
"Sum: {:?}, Message: {:?}, Product: {:?}, Person: {:?}",
67+
sum, message, product, person_info
68+
);
69+
});
970
}
1071

1172
// struct LocalQueue {}
@@ -17,7 +78,3 @@ fn main() {
1778
// locals.push(LocalQueue {});
1879
// });
1980
// }
20-
21-
fn warn_par_iter_simple() {
22-
(0..100).into_iter().for_each(|x| println!("{:?}", x));
23-
}

lints/par_iter/ui/main.rs

+57-8
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,70 @@
22

33
#[allow(unused_imports)]
44
use rayon::prelude::*;
5-
use std::collections::LinkedList;
5+
// use std::collections::LinkedList;
6+
// use std::rc::Rc;
67

78
fn main() {
8-
warn_par_iter_simple();
9-
warn_par_iter_simple_no_send();
9+
// warn_par_iter_simple();
10+
// warn_par_iter_simple_no_send();
11+
// warn_par_iter_simple_no_send_in_closure_body();
12+
// move_inside_closure();
13+
// warn_par_iter_simple_into_parallel_ref_iterator();
1014
// warn_par_iter();
15+
warn_par_complex();
1116
}
1217

13-
fn warn_par_iter_simple() {
14-
(0..100).into_iter().for_each(|x| println!("{:?}", x));
18+
// fn warn_par_iter_simple() {
19+
// (0..100).into_iter().for_each(|x| println!("{:?}", x));
20+
// }
21+
22+
// fn move_inside_closure() {
23+
// let y = 100;
24+
// (0..100)
25+
// .into_iter()
26+
// .for_each(|x| println!("{:?}{:?}", x, y));
27+
// }
28+
// fn warn_par_iter_simple_no_send() {
29+
// let list: Vec<Rc<i32>> = (0..100).map(Rc::new).collect();
30+
// list.iter().for_each(|y| println!("{:?}", y));
31+
// }
32+
33+
// fn warn_par_iter_simple_no_send_in_closure_body() {
34+
// let mut list: Vec<Rc<i32>> = (0..100).map(Rc::new).collect();
35+
// (0..100).into_iter().for_each(|x| list.push(Rc::new(x)));
36+
// }
37+
38+
// fn warn_par_iter_simple_into_parallel_ref_iterator() {
39+
// let list: LinkedList<i32> = (0..100).collect();
40+
// list.into_iter().for_each(|x| println!("{:?}", x));
41+
// }
42+
43+
struct Person {
44+
name: String,
45+
age: u32,
1546
}
1647

17-
fn warn_par_iter_simple_no_send() {
18-
let list: LinkedList<i32> = (0..100).collect();
19-
list.into_iter().for_each(|x| println!("{:?}", x));
48+
fn warn_par_complex() {
49+
let vec = vec![1, 2, 3, 4, 5, 6];
50+
let a = 10;
51+
let b = 20;
52+
let c = "Hello";
53+
let d = 3.14;
54+
let e = true;
55+
let person = Person {
56+
name: String::from("Alice"),
57+
age: 30,
58+
};
59+
60+
(0..10).into_iter().for_each(|x| {
61+
let sum = x + a + b;
62+
let message = if e { c } else { "Goodbye" };
63+
let product = d * (x as f64);
64+
let person_info = format!("{} is {} years old.", person.name, person.age);
65+
println!(
66+
"Sum: {sum}, Message: {message}, Product: {product}, Person: {person_info}, Vec: {vec:?}",
67+
);
68+
});
2069
}
2170

2271
// struct LocalQueue {}

0 commit comments

Comments
 (0)