Merge pull request #1060 from Manishearth/sugg

Improve suggestions
This commit is contained in:
llogiq 2016-07-10 00:06:30 +02:00 committed by GitHub
commit ad1cd99054
33 changed files with 1064 additions and 465 deletions

View file

@ -8,15 +8,31 @@ fn main() {
i += 2; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i + 2
i += 2 + 17; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i + 2 + 17
i -= 6; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i - 6
i -= 2 - 1;
//~^ ERROR assign operation detected
//~| HELP replace it with
//~| SUGGESTION i = i - (2 - 1)
i *= 5; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i * 5
i *= 1+5; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i * (1+5)
i /= 32; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i / 32
i /= 32 | 5; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i / (32 | 5)
i /= 32 / 5; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i / (32 / 5)
i %= 42; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i % 42
@ -26,6 +42,10 @@ fn main() {
i <<= 9 + 6 - 7; //~ ERROR assign operation detected
//~^ HELP replace it with
//~| SUGGESTION i = i << (9 + 6 - 7)
i += 1 << 5;
//~^ ERROR assign operation detected
//~| HELP replace it with
//~| SUGGESTION i = i + (1 << 5)
}
#[allow(dead_code, unused_assignments)]

View file

@ -23,6 +23,42 @@ fn main() {
}
}
if x == "hello" && x == "world" {
//~^ ERROR this if statement can be collapsed
//~| HELP try
//~| SUGGESTION if x == "hello" && x == "world" && (y == "world" || y == "hello") {
if y == "world" || y == "hello" {
println!("Hello world!");
}
}
if x == "hello" || x == "world" {
//~^ ERROR this if statement can be collapsed
//~| HELP try
//~| SUGGESTION if (x == "hello" || x == "world") && y == "world" && y == "hello" {
if y == "world" && y == "hello" {
println!("Hello world!");
}
}
if x == "hello" && x == "world" {
//~^ ERROR this if statement can be collapsed
//~| HELP try
//~| SUGGESTION if x == "hello" && x == "world" && y == "world" && y == "hello" {
if y == "world" && y == "hello" {
println!("Hello world!");
}
}
if 42 == 1337 {
//~^ ERROR this if statement can be collapsed
//~| HELP try
//~| SUGGESTION if 42 == 1337 && 'a' != 'A' {
if 'a' != 'A' {
println!("world!")
}
}
// Collaspe `else { if .. }` to `else if ..`
if x == "hello" {
print!("Hello ");

View file

@ -11,45 +11,51 @@ fn foo() {}
fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
if !m.contains_key(&k) { m.insert(k, v); }
//~^ ERROR usage of `contains_key` followed by `insert` on `HashMap`
//~| HELP Consider
//~^ ERROR usage of `contains_key` followed by `insert` on a `HashMap`
//~| HELP consider
//~| SUGGESTION m.entry(k).or_insert(v)
}
fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
if !m.contains_key(&k) { foo(); m.insert(k, v); }
//~^ ERROR usage of `contains_key` followed by `insert` on `HashMap`
//~| NOTE Consider using `m.entry(k)`
//~^ ERROR usage of `contains_key` followed by `insert` on a `HashMap`
//~| HELP consider
//~| SUGGESTION m.entry(k)
}
fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
if !m.contains_key(&k) { m.insert(k, v) } else { None };
//~^ ERROR usage of `contains_key` followed by `insert` on `HashMap`
//~| NOTE Consider using `m.entry(k)`
//~^ ERROR usage of `contains_key` followed by `insert` on a `HashMap`
//~| HELP consider
//~| SUGGESTION m.entry(k)
}
fn insert_if_present2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
if m.contains_key(&k) { None } else { m.insert(k, v) };
//~^ ERROR usage of `contains_key` followed by `insert` on `HashMap`
//~| NOTE Consider using `m.entry(k)`
//~^ ERROR usage of `contains_key` followed by `insert` on a `HashMap`
//~| HELP consider
//~| SUGGESTION m.entry(k)
}
fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
//~^ ERROR usage of `contains_key` followed by `insert` on `HashMap`
//~| NOTE Consider using `m.entry(k)`
//~^ ERROR usage of `contains_key` followed by `insert` on a `HashMap`
//~| HELP consider
//~| SUGGESTION m.entry(k)
}
fn insert_if_present3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
if m.contains_key(&k) { None } else { foo(); m.insert(k, v) };
//~^ ERROR usage of `contains_key` followed by `insert` on `HashMap`
//~| NOTE Consider using `m.entry(k)`
//~^ ERROR usage of `contains_key` followed by `insert` on a `HashMap`
//~| HELP consider
//~| SUGGESTION m.entry(k)
}
fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) {
if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
//~^ ERROR usage of `contains_key` followed by `insert` on `BTreeMap`
//~| NOTE Consider using `m.entry(k)`
//~^ ERROR usage of `contains_key` followed by `insert` on a `BTreeMap`
//~| HELP consider
//~| SUGGESTION m.entry(k)
}
fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) {

View file

@ -40,23 +40,47 @@ fn main() {
ZERO == 0.0; //no error, comparison with zero is ok
ZERO + ZERO != 1.0; //no error, comparison with zero is ok
ONE == 1f32; //~ERROR ==-comparison of f32 or f64
ONE == (1.0 + 0.0); //~ERROR ==-comparison of f32 or f64
ONE == 1f32;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (ONE - 1f32).abs() < error
ONE == 1.0 + 0.0;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (ONE - (1.0 + 0.0)).abs() < error
ONE + ONE == (ZERO + ONE + ONE); //~ERROR ==-comparison of f32 or f64
ONE + ONE == ZERO + ONE + ONE;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (ONE + ONE - (ZERO + ONE + ONE)).abs() < error
ONE != 2.0; //~ERROR !=-comparison of f32 or f64
ONE != 2.0;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (ONE - 2.0).abs() < error
ONE != 0.0; // no error, comparison with zero is ok
twice(ONE) != ONE; //~ERROR !=-comparison of f32 or f64
ONE as f64 != 2.0; //~ERROR !=-comparison of f32 or f64
twice(ONE) != ONE;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (twice(ONE) - ONE).abs() < error
ONE as f64 != 2.0;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (ONE as f64 - 2.0).abs() < error
ONE as f64 != 0.0; // no error, comparison with zero is ok
let x : f64 = 1.0;
x == 1.0; //~ERROR ==-comparison of f32 or f64
x == 1.0;
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (x - 1.0).abs() < error
x != 0f64; // no error, comparison with zero is ok
twice(x) != twice(ONE as f64); //~ERROR !=-comparison of f32 or f64
twice(x) != twice(ONE as f64);
//~^ ERROR strict comparison of f32 or f64
//~| HELP within some error
//~| SUGGESTION (twice(x) - twice(ONE as f64)).abs() < error
x < 0.0; // no errors, lower or greater comparisons need no fuzzyness

View file

@ -2,6 +2,7 @@
#![plugin(clippy)]
use std::collections::*;
use std::rc::Rc;
static STATIC: [usize; 4] = [ 0, 1, 8, 16 ];
const CONST: [usize; 4] = [ 0, 1, 8, 16 ];
@ -96,23 +97,41 @@ fn main() {
let mut vec = vec![1, 2, 3, 4];
let vec2 = vec![1, 2, 3, 4];
for i in 0..vec.len() {
//~^ ERROR `i` is only used to index `vec`. Consider using `for item in &vec`
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in &vec {
println!("{}", vec[i]);
}
for i in 0..vec.len() { let _ = vec[i]; }
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in &vec { let _ = vec[i]; }
// ICE #746
for j in 0..4 {
//~^ ERROR `j` is only used to index `STATIC`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in STATIC.iter().take(4) {
println!("{:?}", STATIC[j]);
}
for j in 0..4 {
//~^ ERROR `j` is only used to index `CONST`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in CONST.iter().take(4) {
println!("{:?}", CONST[j]);
}
for i in 0..vec.len() {
//~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate()`
//~^ ERROR `i` is used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for (i, <item>) in vec.iter().enumerate() {
println!("{} {}", vec[i], i);
}
for i in 0..vec.len() { // not an error, indexing more than one variable
@ -120,42 +139,66 @@ fn main() {
}
for i in 0..vec.len() {
//~^ ERROR `i` is only used to index `vec2`. Consider using `for item in vec2.iter().take(vec.len())`
//~^ ERROR `i` is only used to index `vec2`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in vec2.iter().take(vec.len()) {
println!("{}", vec2[i]);
}
for i in 5..vec.len() {
//~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().skip(5)`
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in vec.iter().skip(5) {
println!("{}", vec[i]);
}
for i in 0..MAX_LEN {
//~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(MAX_LEN)`
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in vec.iter().take(MAX_LEN) {
println!("{}", vec[i]);
}
for i in 0...MAX_LEN {
//~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(MAX_LEN)`
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in vec.iter().take(MAX_LEN + 1) {
println!("{}", vec[i]);
}
for i in 5..10 {
//~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(10).skip(5)`
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in vec.iter().take(10).skip(5) {
println!("{}", vec[i]);
}
for i in 5...10 {
//~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(10).skip(5)`
//~^ ERROR `i` is only used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for <item> in vec.iter().take(10 + 1).skip(5) {
println!("{}", vec[i]);
}
for i in 5..vec.len() {
//~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate().skip(5)`
//~^ ERROR `i` is used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for (i, <item>) in vec.iter().enumerate().skip(5) {
println!("{} {}", vec[i], i);
}
for i in 5..10 {
//~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate().take(10).skip(5)`
//~^ ERROR `i` is used to index `vec`
//~| HELP consider
//~| HELP consider
//~| SUGGESTION for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
println!("{} {}", vec[i], i);
}
@ -346,10 +389,22 @@ fn main() {
for (_, v) in &m {
//~^ you seem to want to iterate on a map's values
//~| HELP use the corresponding method
//~| SUGGESTION for v in m.values()
//~| HELP use the corresponding method
//~| SUGGESTION for v in m.values() {
let _v = v;
}
let m : Rc<HashMap<u64, u64>> = Rc::new(HashMap::new());
for (_, v) in &*m {
//~^ you seem to want to iterate on a map's values
//~| HELP use the corresponding method
//~| HELP use the corresponding method
//~| SUGGESTION for v in (*m).values() {
let _v = v;
// Here the `*` is not actually necesarry, but the test tests that we don't suggest
// `in *m.values()` as we used to
}
let mut m : HashMap<u64, u64> = HashMap::new();
for (_, v) in &mut m {
// Ok, there is no values_mut method or equivalent
@ -361,7 +416,8 @@ fn main() {
for (k, _value) in rm {
//~^ you seem to want to iterate on a map's keys
//~| HELP use the corresponding method
//~| SUGGESTION for k in rm.keys()
//~| HELP use the corresponding method
//~| SUGGESTION for k in rm.keys() {
let _k = k;
}

View file

@ -112,7 +112,7 @@ fn match_bool() {
match test {
//~^ ERROR you seem to be trying to match on a boolean expression
//~| HELP try
//~| HELP consider
//~| SUGGESTION if test { 0 } else { 42 };
true => 0,
false => 42,
@ -121,7 +121,7 @@ fn match_bool() {
let option = 1;
match option == 1 {
//~^ ERROR you seem to be trying to match on a boolean expression
//~| HELP try
//~| HELP consider
//~| SUGGESTION if option == 1 { 1 } else { 0 };
true => 1,
false => 0,
@ -129,23 +129,32 @@ fn match_bool() {
match test {
//~^ ERROR you seem to be trying to match on a boolean expression
//~| HELP try
//~^^ SUGGESTION if !test { println!("Noooo!"); };
//~| HELP consider
//~| SUGGESTION if !test { println!("Noooo!"); };
true => (),
false => { println!("Noooo!"); }
};
match test {
//~^ ERROR you seem to be trying to match on a boolean expression
//~| HELP try
//~^^ SUGGESTION if !test { println!("Noooo!"); };
//~| HELP consider
//~| SUGGESTION if !test { println!("Noooo!"); };
false => { println!("Noooo!"); }
_ => (),
};
match test && test {
//~^ ERROR you seem to be trying to match on a boolean expression
//~| HELP consider
//~| SUGGESTION if !(test && test) { println!("Noooo!"); };
//~| ERROR equal expressions as operands
false => { println!("Noooo!"); }
_ => (),
};
match test {
//~^ ERROR you seem to be trying to match on a boolean expression
//~| HELP try
//~| HELP consider
//~| SUGGESTION if test { println!("Yes!"); } else { println!("Noooo!"); };
false => { println!("Noooo!"); }
true => { println!("Yes!"); }

View file

@ -5,21 +5,28 @@
#[allow(if_same_then_else)]
fn main() {
let x = true;
let y = false;
if x { true } else { true }; //~ERROR this if-then-else expression will always return true
if x { false } else { false }; //~ERROR this if-then-else expression will always return false
if x { true } else { false };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION `x`
//~| SUGGESTION x
if x { false } else { true };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION `!x`
//~| SUGGESTION !x
if x && y { false } else { true };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION !(x && y)
if x { x } else { false }; // would also be questionable, but we don't catch this yet
bool_ret(x);
bool_ret2(x);
bool_ret3(x);
bool_ret5(x, x);
bool_ret4(x);
bool_ret6(x, x);
}
#[allow(if_same_then_else, needless_return)]
@ -39,7 +46,15 @@ fn bool_ret3(x: bool) -> bool {
if x { return true } else { return false };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION `return x`
//~| SUGGESTION return x
}
#[allow(needless_return)]
fn bool_ret5(x: bool, y: bool) -> bool {
if x && y { return true } else { return false };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION return x && y
}
#[allow(needless_return)]
@ -47,5 +62,13 @@ fn bool_ret4(x: bool) -> bool {
if x { return false } else { return true };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION `return !x`
//~| SUGGESTION return !x
}
#[allow(needless_return)]
fn bool_ret6(x: bool, y: bool) -> bool {
if x && y { return false } else { return true };
//~^ ERROR this if-then-else expression returns a bool literal
//~| HELP you can reduce it to
//~| SUGGESTION return !(x && y)
}

View file

@ -20,11 +20,16 @@ fn main() {
//~| HELP try
//~| SUGGESTION let x = &1;
let ref y : (&_, u8) = (&1, 2);
let ref y: (&_, u8) = (&1, 2);
//~^ ERROR `ref` on an entire `let` pattern is discouraged
//~| HELP try
//~| SUGGESTION let y: (&_, u8) = &(&1, 2);
let ref z = 1 + 2;
//~^ ERROR `ref` on an entire `let` pattern is discouraged
//~| HELP try
//~| SUGGESTION let z = &(1 + 2);
let (ref x, _) = (1,2); // okay, not top level
println!("The answer is {}.", x);
}

View file

@ -62,6 +62,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
//~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
//~| HELP try
//~| SUGGESTION = &mut *(p as *mut T);
let _ = &mut *(p as *mut T);
let _: &T = std::mem::transmute(o);
//~^ ERROR transmute from a pointer type (`*const U`) to a reference type (`&T`)
@ -110,6 +111,13 @@ fn useless() {
//~^ ERROR transmute from an integer to a pointer
//~| HELP try
//~| SUGGESTION 5_isize as *const usize
let _ = 5_isize as *const usize;
let _: *const usize = std::mem::transmute(1+1usize);
//~^ ERROR transmute from an integer to a pointer
//~| HELP try
//~| SUGGESTION (1+1usize) as *const usize
let _ = (1+1_usize) as *const usize;
}
}