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

Rollup of 2 pull requests #4149

Merged
merged 9 commits into from
May 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 26 additions & 11 deletions clippy_lints/src/copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
let eq: &dyn Fn(&&Expr, &&Expr) -> bool =
&|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };

if let Some((i, j)) = search_same(conds, hash, eq) {
for (i, j) in search_same(conds, hash, eq) {
span_note_and_lint(
cx,
IFS_SAME_COND,
Expand Down Expand Up @@ -185,7 +185,7 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
};

let indexed_arms: Vec<(usize, &Arm)> = arms.iter().enumerate().collect();
if let Some((&(_, i), &(_, j))) = search_same(&indexed_arms, hash, eq) {
for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
span_lint_and_then(
cx,
MATCH_SAME_ARMS,
Expand Down Expand Up @@ -217,7 +217,10 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
),
);
} else {
db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
db.span_help(
i.pats[0].span,
&format!("consider refactoring into `{} | {}`", lhs, rhs),
);
}
}
},
Expand Down Expand Up @@ -323,21 +326,33 @@ where
None
}

fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)>
fn search_common_cases<'a, T, Eq>(exprs: &'a [T], eq: &Eq) -> Option<(&'a T, &'a T)>
where
Hash: Fn(&T) -> u64,
Eq: Fn(&T, &T) -> bool,
{
// common cases
if exprs.len() < 2 {
return None;
None
} else if exprs.len() == 2 {
return if eq(&exprs[0], &exprs[1]) {
if eq(&exprs[0], &exprs[1]) {
Some((&exprs[0], &exprs[1]))
} else {
None
};
}
} else {
None
}
}

fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
where
Hash: Fn(&T) -> u64,
Eq: Fn(&T, &T) -> bool,
{
if let Some(expr) = search_common_cases(&exprs, &eq) {
return vec![expr];
}

let mut match_expr_list: Vec<(&T, &T)> = Vec::new();

let mut map: FxHashMap<_, Vec<&_>> =
FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
Expand All @@ -347,7 +362,7 @@ where
Entry::Occupied(mut o) => {
for o in o.get() {
if eq(o, expr) {
return Some((o, expr));
match_expr_list.push((o, expr));
}
}
o.get_mut().push(expr);
Expand All @@ -358,5 +373,5 @@ where
}
}

None
match_expr_list
}
44 changes: 23 additions & 21 deletions clippy_lints/src/unicode.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::utils::{is_allowed, snippet, span_help_and_lint};
use crate::utils::{is_allowed, snippet, span_lint_and_sugg};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ast::LitKind;
use syntax::source_map::Span;
use unicode_normalization::UnicodeNormalization;
Expand Down Expand Up @@ -34,7 +35,11 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// let x = "Hä?"
/// let x = String::from("€");
/// ```
/// Could be written as:
/// ```rust
/// let x = String::from("\u{20ac}");
/// ```
pub NON_ASCII_LITERAL,
pedantic,
Expand Down Expand Up @@ -87,43 +92,40 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
fn check_str(cx: &LateContext<'_, '_>, span: Span, id: HirId) {
let string = snippet(cx, span, "");
if string.contains('\u{200B}') {
span_help_and_lint(
span_lint_and_sugg(
cx,
ZERO_WIDTH_SPACE,
span,
"zero-width space detected",
&format!(
"Consider replacing the string with:\n\"{}\"",
string.replace("\u{200B}", "\\u{200B}")
),
"consider replacing the string with",
string.replace("\u{200B}", "\\u{200B}"),
Applicability::MachineApplicable,
);
}
if string.chars().any(|c| c as u32 > 0x7F) {
span_help_and_lint(
span_lint_and_sugg(
cx,
NON_ASCII_LITERAL,
span,
"literal non-ASCII character detected",
&format!(
"Consider replacing the string with:\n\"{}\"",
if is_allowed(cx, UNICODE_NOT_NFC, id) {
escape(string.chars())
} else {
escape(string.nfc())
}
),
"consider replacing the string with",
if is_allowed(cx, UNICODE_NOT_NFC, id) {
escape(string.chars())
} else {
escape(string.nfc())
},
Applicability::MachineApplicable,
);
}
if is_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) {
span_help_and_lint(
span_lint_and_sugg(
cx,
UNICODE_NOT_NFC,
span,
"non-nfc unicode sequence detected",
&format!(
"Consider replacing the string with:\n\"{}\"",
string.nfc().collect::<String>()
),
"consider replacing the string with",
string.nfc().collect::<String>(),
Applicability::MachineApplicable,
);
}
}
14 changes: 14 additions & 0 deletions tests/ui/if_same_then_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,20 @@ fn if_same_then_else() -> Result<&'static str, ()> {
return Ok(&foo[0..]);
}

if true {
let foo = "";
return Ok(&foo[0..]);
} else if false {
let foo = "bar";
return Ok(&foo[0..]);
} else if true {
let foo = "";
return Ok(&foo[0..]);
} else {
let foo = "";
return Ok(&foo[0..]);
}

// False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559.
if true {
let foo = "";
Expand Down
35 changes: 34 additions & 1 deletion tests/ui/if_same_then_else.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -210,5 +210,38 @@ LL | | try!(Ok("foo"));
LL | | } else {
| |_____^

error: aborting due to 10 previous errors
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:244:12
|
LL | } else {
| ____________^
LL | | let foo = "";
LL | | return Ok(&foo[0..]);
LL | | }
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:241:20
|
LL | } else if true {
| ____________________^
LL | | let foo = "";
LL | | return Ok(&foo[0..]);
LL | | } else {
| |_____^

error: this `if` has the same condition as a previous if
--> $DIR/if_same_then_else.rs:241:15
|
LL | } else if true {
| ^^^^
|
= note: #[deny(clippy::ifs_same_cond)] on by default
note: same as this
--> $DIR/if_same_then_else.rs:235:8
|
LL | if true {
| ^^^^

error: aborting due to 12 previous errors

16 changes: 16 additions & 0 deletions tests/ui/match_same_arms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,22 @@ fn match_same_arms() {
(None, Some(a)) => bar(a), // bindings have different types
_ => (),
}

let _ = match 42 {
42 => 1,
51 => 1, //~ ERROR match arms have same body
41 => 2,
52 => 2, //~ ERROR match arms have same body
_ => 0,
};

let _ = match 42 {
1 => 2,
2 => 2, //~ ERROR 2nd matched arms have same body
3 => 2, //~ ERROR 3rd matched arms have same body
4 => 3,
_ => 0,
};
}

fn main() {}
Loading