Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expands manual_memcpy to lint ones with loop counters #5727

Merged
merged 35 commits into from
Oct 10, 2020
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
dc89bb1
Use if_chain in Increment/InitializeVisitor
rail-rain Jun 10, 2020
116f30d
Use else blocks instead of return statements in Increment/InitializeV…
rail-rain Jun 10, 2020
b2d5b89
Check if it's after the loop earlier
rail-rain Jun 10, 2020
31cb110
add concinient methods to Increment/InitializeVisitor
rail-rain Jun 10, 2020
c599e2f
Split VarState
rail-rain Jun 10, 2020
13c207d
Generalise `InitializeVisitor`
rail-rain Jun 10, 2020
9573a0d
Rename variables
rail-rain Jun 10, 2020
1026b42
Rename a struct and variables
rail-rain Jun 10, 2020
b4b4da1
Introduce Start and StartKind
rail-rain Jun 10, 2020
720f19f
Implement detecting `manual_memcpy` with loop counters
rail-rain Jun 10, 2020
de56279
Implement building the `manual_memcpy` sugggestion with loop counters
rail-rain Jun 10, 2020
8da6cfd
fmt
rail-rain Jun 11, 2020
d9a88be
Rename `get_offset` and its private items
rail-rain Jun 17, 2020
774e82a
Add the tests for `manual_memcpy` with loop counters
rail-rain Jun 10, 2020
9aad38b
Update `manual_memcpy.stderr` to reflect additional parentheses
rail-rain Jun 17, 2020
4ea4a97
Add tests for bitwise operations
rail-rain Jun 18, 2020
eb3ffe6
make use of macros in operator overloading
rail-rain Jun 23, 2020
10d7a18
fmt
rail-rain Jun 23, 2020
174065f
fix the multiple counters test
rail-rain Jun 23, 2020
4418738
Use operator overloading instead of direct calls of `make_binop`
rail-rain Jun 24, 2020
f410df3
make clippy happy (`needless_pass_by_value`, `filter_map` and `find_m…
rail-rain Jun 27, 2020
ce653d6
use `#[derive]` instead of the manual implementation
rail-rain Jul 1, 2020
e855fe3
Reflect the changes that has been made and fmt
rail-rain Aug 16, 2020
4918e7a
Replace `snippet_opt` + `unwrap_or_else` with `snippet`
rail-rain Sep 27, 2020
5c71352
Prevent unnecessary lints from triggering
rail-rain Sep 27, 2020
99aceeb
Use the spans of the entire `for` loops for suggestions
rail-rain Sep 27, 2020
9725f00
Use the `From` trait to make `MinifyingSugg`
rail-rain Sep 27, 2020
ec94bd6
split up the `manual_memcpy` test
rail-rain Sep 27, 2020
3883841
document `MinifyingSugg` and `Offset`
rail-rain Oct 2, 2020
94d7b82
simplify the code
rail-rain Oct 2, 2020
1402d8a
fix a FN where incr exprs with no semicolon at ends
rail-rain Oct 2, 2020
41a0ccb
add comments around `loop_counters`
rail-rain Oct 2, 2020
2a0e45b
supress `clippy::filter_map`
rail-rain Oct 2, 2020
7820cb1
Add tests for
rail-rain Oct 2, 2020
b541884
remove the explicit return value of `print_limit`
rail-rain Oct 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
659 changes: 448 additions & 211 deletions clippy_lints/src/loops.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clippy_lints/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>,
}

/// Gets the parent expression, if any –- this is useful to constrain a lint.
pub fn get_parent_expr<'c>(cx: &'c LateContext<'_>, e: &Expr<'_>) -> Option<&'c Expr<'c>> {
pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
let map = &cx.tcx.hir();
let hir_id = e.hir_id;
let parent_id = map.get_parent_node(hir_id);
Expand Down
59 changes: 52 additions & 7 deletions clippy_lints/src/utils/sugg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ use rustc_span::{BytePos, Pos};
use std::borrow::Cow;
use std::convert::TryInto;
use std::fmt::Display;
use std::ops::{Add, Neg, Not, Sub};

/// A helper type to build suggestion correctly handling parenthesis.
#[derive(Clone, PartialEq)]
pub enum Sugg<'a> {
/// An expression that never needs parenthesis such as `1337` or `[0; 42]`.
NonParen(Cow<'a, str>),
Expand All @@ -25,8 +27,12 @@ pub enum Sugg<'a> {
BinOp(AssocOp, Cow<'a, str>),
}

/// Literal constant `0`, for convenience.
pub const ZERO: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("0"));
/// Literal constant `1`, for convenience.
pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1"));
/// a constant represents an empty string, for convenience.
pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed(""));

impl Display for Sugg<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
Expand Down Expand Up @@ -267,21 +273,60 @@ impl<'a> Sugg<'a> {
}
}

impl<'a, 'b> std::ops::Add<Sugg<'b>> for Sugg<'a> {
// Copied from the rust standart library, and then edited
macro_rules! forward_binop_impls_to_ref {
(impl $imp:ident, $method:ident for $t:ty, type Output = $o:ty) => {
impl $imp<$t> for &$t {
type Output = $o;

fn $method(self, other: $t) -> $o {
$imp::$method(self, &other)
}
}

impl $imp<&$t> for $t {
type Output = $o;

fn $method(self, other: &$t) -> $o {
$imp::$method(&self, other)
}
}

impl $imp for $t {
type Output = $o;

fn $method(self, other: $t) -> $o {
$imp::$method(&self, &other)
}
}
};
}

impl Add for &Sugg<'_> {
rail-rain marked this conversation as resolved.
Show resolved Hide resolved
type Output = Sugg<'static>;
fn add(self, rhs: Sugg<'b>) -> Sugg<'static> {
make_binop(ast::BinOpKind::Add, &self, &rhs)
fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> {
make_binop(ast::BinOpKind::Add, self, rhs)
}
}

impl<'a, 'b> std::ops::Sub<Sugg<'b>> for Sugg<'a> {
impl Sub for &Sugg<'_> {
type Output = Sugg<'static>;
fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> {
make_binop(ast::BinOpKind::Sub, self, rhs)
}
}

forward_binop_impls_to_ref!(impl Add, add for Sugg<'_>, type Output = Sugg<'static>);
forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'static>);

impl Neg for Sugg<'_> {
type Output = Sugg<'static>;
fn sub(self, rhs: Sugg<'b>) -> Sugg<'static> {
make_binop(ast::BinOpKind::Sub, &self, &rhs)
fn neg(self) -> Sugg<'static> {
make_unop("-", self)
}
}

impl<'a> std::ops::Not for Sugg<'a> {
impl Not for Sugg<'_> {
type Output = Sugg<'static>;
fn not(self) -> Sugg<'static> {
make_unop("!", self)
Expand Down
88 changes: 0 additions & 88 deletions tests/ui/manual_memcpy.stderr

This file was deleted.

71 changes: 71 additions & 0 deletions tests/ui/manual_memcpy/with_loop_counters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#![warn(clippy::needless_range_loop, clippy::manual_memcpy)]

pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
let mut count = 0;
for i in 3..src.len() {
dst[i] = src[count];
count += 1;
}

let mut count = 0;
for i in 3..src.len() {
dst[count] = src[i];
count += 1;
}

let mut count = 3;
for i in 0..src.len() {
dst[count] = src[i];
count += 1;
}

let mut count = 3;
for i in 0..src.len() {
dst[i] = src[count];
count += 1;
}

let mut count = 0;
for i in 3..(3 + src.len()) {
dst[i] = src[count];
count += 1;
}

let mut count = 3;
for i in 5..src.len() {
dst[i] = src[count - 2];
count += 1;
}

let mut count = 5;
for i in 3..10 {
dst[i] = src[count];
count += 1;
}

let mut count = 3;
let mut count2 = 30;
for i in 0..src.len() {
dst[count] = src[i];
dst2[count2] = src[i];
count += 1;
count2 += 1;
}

// make sure parentheses are added properly to bitwise operators, which have lower precedence than
// arithmetric ones
let mut count = 0 << 1;
for i in 0..1 << 1 {
dst[count] = src[i + 2];
count += 1;
}

// make sure incrementing expressions without semicolons at the end of loops are handled correctly.
let mut count = 0;
for i in 3..src.len() {
dst[i] = src[count];
count += 1
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the last review round:

I would like two more tests (correct me if they won't make sense):

  1. Use dst.len() instead of src.len()
  2. put count += 1; in front of dst[i] = src[count];

Copy link
Contributor Author

@rail-rain rail-rain Oct 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably thought it was fine because the dst.len() case is tested in without_loop_counters.rs, and the 'loop counters at the top of the loop' (am I understand what you said correctly?) case is the almost same as #6076, a FP in expilcit_counter_loop which shares the same visitor to check this case. Having said that, I cannot say these cases don't make sense. So I will add these. Done.

}

fn main() {}
102 changes: 102 additions & 0 deletions tests/ui/manual_memcpy/with_loop_counters.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:5:5
|
LL | / for i in 3..src.len() {
LL | | dst[i] = src[count];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);`
|
= note: `-D clippy::manual-memcpy` implied by `-D warnings`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:11:5
|
LL | / for i in 3..src.len() {
LL | | dst[count] = src[i];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:17:5
|
LL | / for i in 0..src.len() {
LL | | dst[count] = src[i];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:23:5
|
LL | / for i in 0..src.len() {
LL | | dst[i] = src[count];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:29:5
|
LL | / for i in 3..(3 + src.len()) {
LL | | dst[i] = src[count];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:35:5
|
LL | / for i in 5..src.len() {
LL | | dst[i] = src[count - 2];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:41:5
|
LL | / for i in 3..10 {
LL | | dst[i] = src[count];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:48:5
|
LL | / for i in 0..src.len() {
LL | | dst[count] = src[i];
LL | | dst2[count2] = src[i];
LL | | count += 1;
LL | | count2 += 1;
LL | | }
| |_____^
|
help: try replacing the loop by
|
LL | dst[3..(src.len() + 3)].clone_from_slice(&src[..]);
LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]);
|

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:58:5
|
LL | / for i in 0..1 << 1 {
LL | | dst[count] = src[i + 2];
LL | | count += 1;
LL | | }
| |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);`

error: it looks like you're manually copying between slices
--> $DIR/with_loop_counters.rs:65:5
|
LL | / for i in 3..src.len() {
LL | | dst[i] = src[count];
LL | | count += 1
LL | | }
| |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);`

error: aborting due to 10 previous errors

File renamed without changes.
Loading