//! This lint is **warn** by default
use crate::utils::sugg::Sugg;
-use crate::utils::{in_macro, span_lint, span_lint_and_sugg};
+use crate::utils::{higher, span_lint, span_lint_and_sugg};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_tool_lint, lint_array};
+use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ast::LitKind;
use syntax::source_map::Spanned;
-/// **What it does:** Checks for expressions of the form `if c { true } else {
-/// false }`
-/// (or vice versa) and suggest using the condition directly.
-///
-/// **Why is this bad?** Redundant code.
-///
-/// **Known problems:** Maybe false positives: Sometimes, the two branches are
-/// painstakingly documented (which we of course do not detect), so they *may*
-/// have some value. Even then, the documentation can be rewritten to match the
-/// shorter code.
-///
-/// **Example:**
-/// ```rust
-/// if x {
-/// false
-/// } else {
-/// true
-/// }
-/// ```
declare_clippy_lint! {
+ /// **What it does:** Checks for expressions of the form `if c { true } else {
+ /// false }`
+ /// (or vice versa) and suggest using the condition directly.
+ ///
+ /// **Why is this bad?** Redundant code.
+ ///
+ /// **Known problems:** Maybe false positives: Sometimes, the two branches are
+ /// painstakingly documented (which we, of course, do not detect), so they *may*
+ /// have some value. Even then, the documentation can be rewritten to match the
+ /// shorter code.
+ ///
+ /// **Example:**
+ /// ```rust,ignore
+ /// if x {
+ /// false
+ /// } else {
+ /// true
+ /// }
+ /// ```
+ /// Could be written as
+ /// ```rust,ignore
+ /// !x
+ /// ```
pub NEEDLESS_BOOL,
complexity,
- "if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`"
+ "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`"
}
-/// **What it does:** Checks for expressions of the form `x == true`,
-/// `x != true` and order comparisons such as `x < true` (or vice versa) and
-/// suggest using the variable directly.
-///
-/// **Why is this bad?** Unnecessary code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if x == true {} // could be `if x { }`
-/// ```
declare_clippy_lint! {
+ /// **What it does:** Checks for expressions of the form `x == true`,
+ /// `x != true` and order comparisons such as `x < true` (or vice versa) and
+ /// suggest using the variable directly.
+ ///
+ /// **Why is this bad?** Unnecessary code.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// ```rust,ignore
+ /// if x == true {} // could be `if x { }`
+ /// ```
pub BOOL_COMPARISON,
complexity,
- "comparing a variable to a boolean, e.g. `if x == true` or `if x != true`"
+ "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
}
-#[derive(Copy, Clone)]
-pub struct NeedlessBool;
-
-impl LintPass for NeedlessBool {
- fn get_lints(&self) -> LintArray {
- lint_array!(NEEDLESS_BOOL)
- }
-}
+declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
use self::Expression::*;
- if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.node {
-
+ if let Some((ref pred, ref then_block, Some(ref else_expr))) = higher::if_block(&e) {
let reduce = |ret, not| {
let mut applicability = Applicability::MachineApplicable;
let snip = Sugg::hir_with_applicability(cx, pred, "<predicate>", &mut applicability);
- let snip = if not { !snip } else { snip };
+ let mut snip = if not { !snip } else { snip };
- let mut hint = if ret {
- format!("return {}", snip)
- } else {
- snip.to_string()
- };
+ if ret {
+ snip = snip.make_return();
+ }
if parent_node_is_if_expr(&e, &cx) {
- hint = format!("{{ {} }}", hint);
+ snip = snip.blockify()
}
span_lint_and_sugg(
e.span,
"this if-then-else expression returns a bool literal",
"you can reduce it to",
- hint,
+ snip.to_string(),
applicability,
);
};
}
fn parent_node_is_if_expr<'a, 'b>(expr: &Expr, cx: &LateContext<'a, 'b>) -> bool {
- let parent_id = cx.tcx.hir().get_parent_node(expr.id);
+ let parent_id = cx.tcx.hir().get_parent_node(expr.hir_id);
let parent_node = cx.tcx.hir().get(parent_id);
- if let rustc::hir::Node::Expr(e) = parent_node {
- if let ExprKind::If(_,_,_) = e.node {
- return true;
- }
+ match parent_node {
+ rustc::hir::Node::Expr(e) => higher::if_block(&e).is_some(),
+ rustc::hir::Node::Arm(e) => higher::if_block(&e.body).is_some(),
+ _ => false,
}
-
- false
}
-#[derive(Copy, Clone)]
-pub struct BoolComparison;
-
-impl LintPass for BoolComparison {
- fn get_lints(&self) -> LintArray {
- lint_array!(BOOL_COMPARISON)
- }
-}
+declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
- if in_macro(e.span) {
+ if e.span.from_expansion() {
return;
}
use self::Expression::*;
if let ExprKind::Binary(_, ref left_side, ref right_side) = e.node {
- let mut applicability = Applicability::MachineApplicable;
- match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
- (Bool(true), Other) => left_true.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, right_side, applicability, m, h)
- }),
- (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, left_side, applicability, m, h)
- }),
- (Bool(false), Other) => left_false.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, right_side, applicability, m, h)
- }),
- (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, left_side, applicability, m, h)
- }),
- (Other, Other) => no_literal.map_or((), |(h, m)| {
- let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
- if l_ty.is_bool() && r_ty.is_bool() {
+ let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
+ if l_ty.is_bool() && r_ty.is_bool() {
+ let mut applicability = Applicability::MachineApplicable;
+ match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
+ (Bool(true), Other) => left_true.map_or((), |(h, m)| {
+ suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+ }),
+ (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
+ suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+ }),
+ (Bool(false), Other) => left_false.map_or((), |(h, m)| {
+ suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+ }),
+ (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
+ suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+ }),
+ (Other, Other) => no_literal.map_or((), |(h, m)| {
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
span_lint_and_sugg(
h(left_side, right_side).to_string(),
applicability,
)
- }
- }),
- _ => (),
+ }),
+ _ => (),
+ }
}
}
}
match (&*block.stmts, block.expr.as_ref()) {
(&[], Some(e)) => fetch_bool_expr(&**e),
(&[ref e], None) => {
- if let StmtKind::Semi(ref e, _) = e.node {
+ if let StmtKind::Semi(ref e) = e.node {
if let ExprKind::Ret(_) = e.node {
fetch_bool_expr(&**e)
} else {