Run rustfmt on clippy_lints

This commit is contained in:
flip1995 2018-11-27 21:14:15 +01:00
parent 5c5e8cc942
commit 1751d2496d
No known key found for this signature in database
GPG Key ID: E8E897A5870E41C2
134 changed files with 3005 additions and 2731 deletions

View File

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::utils::span_lint;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use std::f64::consts as f64;
use crate::syntax::ast::{FloatTy, Lit, LitKind};
use crate::syntax::symbol;
use crate::utils::span_lint;
use std::f64::consts as f64;
/// **What it does:** Checks for floating point literals that approximate
/// constants which are defined in

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::utils::span_lint;
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::utils::span_lint;
/// **What it does:** Checks for plain integer arithmetic.
///
@ -52,7 +51,8 @@ declare_clippy_lint! {
#[derive(Copy, Clone, Default)]
pub struct Arithmetic {
expr_span: Option<Span>,
/// This field is used to check whether expressions are constants, such as in enum discriminants and consts
/// This field is used to check whether expressions are constants, such as in enum discriminants
/// and consts
const_span: Option<Span>,
}
@ -124,8 +124,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
let body_owner = cx.tcx.hir.body_owner(body.id());
match cx.tcx.hir.body_owner_kind(body_owner) {
hir::BodyOwnerKind::Static(_)
| hir::BodyOwnerKind::Const => {
hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
let body_span = cx.tcx.hir.span(body_owner);
if let Some(span) = self.const_span {
@ -134,7 +133,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
}
}
self.const_span = Some(body_span);
}
},
hir::BodyOwnerKind::Fn => (),
}
}

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use crate::utils::{higher, sugg};
use crate::rustc::hir;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast;
use crate::rustc_errors::Applicability;
use crate::syntax::ast;
use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use crate::utils::{higher, sugg};
use if_chain::if_chain;
/// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
/// patterns.
@ -217,7 +216,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
// a = b commutative_op a
// Limited to primitive type as these ops are know to be commutative
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
&& cx.tables.expr_ty(assignee).is_primitive_ty() {
&& cx.tables.expr_ty(assignee).is_primitive_ty()
{
match op.node {
hir::BinOpKind::Add
| hir::BinOpKind::Mul

View File

@ -7,27 +7,24 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! checks for attributes
use crate::reexport::*;
use crate::utils::{
in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_sugg,
span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::rustc::lint::{
CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
};
use crate::rustc::ty::{self, TyCtxt};
use crate::rustc::{declare_tool_lint, lint_array};
use semver::Version;
use crate::syntax::ast::{
AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind,
};
use crate::syntax::source_map::Span;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use crate::syntax::source_map::Span;
use crate::utils::{
in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_sugg,
span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
use semver::Version;
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics.
@ -219,8 +216,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
match &*attr.name().as_str() {
"allow" | "warn" | "deny" | "forbid" => {
check_clippy_lint_names(cx, items);
}
_ => {}
},
_ => {},
}
if items.is_empty() || attr.name() != "deprecated" {
return;
@ -254,19 +251,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
// and `unused_imports` for `extern crate` items with `macro_use`
for lint in lint_list {
match item.node {
ItemKind::Use(..) => if is_word(lint, "unused_imports")
|| is_word(lint, "deprecated") {
return
ItemKind::Use(..) => {
if is_word(lint, "unused_imports") || is_word(lint, "deprecated") {
return;
}
},
ItemKind::ExternCrate(..) => {
if is_word(lint, "unused_imports")
&& skip_unused_imports {
return
if is_word(lint, "unused_imports") && skip_unused_imports {
return;
}
if is_word(lint, "unused_extern_crates") {
return
return;
}
}
},
_ => {},
}
}
@ -396,14 +393,16 @@ fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr
ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block),
ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e),
ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
ExprKind::Call(ref path_expr, _) => if let ExprKind::Path(ref qpath) = path_expr.node {
if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
ExprKind::Call(ref path_expr, _) => {
if let ExprKind::Path(ref qpath) = path_expr.node {
if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
} else {
true
}
} else {
true
}
} else {
true
},
_ => true,
}
@ -435,7 +434,8 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
cx,
EMPTY_LINE_AFTER_OUTER_ATTR,
begin_of_attr_to_item,
"Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?"
"Found an empty line after an outer attribute. \
Perhaps you forgot to add a '!' to make it an inner attribute?",
);
}
}
@ -501,9 +501,7 @@ pub struct CfgAttrPass;
impl LintPass for CfgAttrPass {
fn get_lints(&self) -> LintArray {
lint_array!(
DEPRECATED_CFG_ATTR,
)
lint_array!(DEPRECATED_CFG_ATTR,)
}
}

View File

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::consts::{constant, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind;
use crate::syntax::source_map::Span;
use crate::utils::{span_lint, span_lint_and_then};
use crate::utils::sugg::Sugg;
use crate::consts::{constant, Constant};
use crate::rustc_errors::Applicability;
use crate::utils::{span_lint, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for incompatible bit masks in comparisons.
///
@ -173,7 +172,6 @@ fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
}
}
fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node {
if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
@ -185,99 +183,112 @@ fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp
}
}
fn check_bit_mask(cx: &LateContext<'_, '_>, bit_op: BinOpKind, cmp_op: BinOpKind, mask_value: u128, cmp_value: u128, span: Span) {
fn check_bit_mask(
cx: &LateContext<'_, '_>,
bit_op: BinOpKind,
cmp_op: BinOpKind,
mask_value: u128,
cmp_value: u128,
span: Span,
) {
match cmp_op {
BinOpKind::Eq | BinOpKind::Ne => match bit_op {
BinOpKind::BitAnd => if mask_value & cmp_value != cmp_value {
if cmp_value != 0 {
BinOpKind::BitAnd => {
if mask_value & cmp_value != cmp_value {
if cmp_value != 0 {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ & {}` can never be equal to `{}`",
mask_value, cmp_value
),
);
}
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
}
},
BinOpKind::BitOr => {
if mask_value | cmp_value != cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ & {}` can never be equal to `{}`",
mask_value,
cmp_value
"incompatible bit mask: `_ | {}` can never be equal to `{}`",
mask_value, cmp_value
),
);
}
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
},
BinOpKind::BitOr => if mask_value | cmp_value != cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ | {}` can never be equal to `{}`",
mask_value,
cmp_value
),
);
},
_ => (),
},
BinOpKind::Lt | BinOpKind::Ge => match bit_op {
BinOpKind::BitAnd => if mask_value < cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ & {}` will always be lower than `{}`",
mask_value,
cmp_value
),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
BinOpKind::BitAnd => {
if mask_value < cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ & {}` will always be lower than `{}`",
mask_value, cmp_value
),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
}
},
BinOpKind::BitOr => if mask_value >= cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ | {}` will never be lower than `{}`",
mask_value,
cmp_value
),
);
} else {
check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
BinOpKind::BitOr => {
if mask_value >= cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ | {}` will never be lower than `{}`",
mask_value, cmp_value
),
);
} else {
check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
}
},
BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
_ => (),
},
BinOpKind::Le | BinOpKind::Gt => match bit_op {
BinOpKind::BitAnd => if mask_value <= cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ & {}` will never be higher than `{}`",
mask_value,
cmp_value
),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
BinOpKind::BitAnd => {
if mask_value <= cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ & {}` will never be higher than `{}`",
mask_value, cmp_value
),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
}
},
BinOpKind::BitOr => if mask_value > cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ | {}` will always be higher than `{}`",
mask_value,
cmp_value
),
);
} else {
check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
BinOpKind::BitOr => {
if mask_value > cmp_value {
span_lint(
cx,
BAD_BIT_MASK,
span,
&format!(
"incompatible bit mask: `_ | {}` will always be higher than `{}`",
mask_value, cmp_value
),
);
} else {
check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
}
},
BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
_ => (),
@ -294,9 +305,7 @@ fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
span,
&format!(
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
op,
m,
c
op, m, c
),
);
}
@ -310,9 +319,7 @@ fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
span,
&format!(
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
op,
m,
c
op, m, c
),
);
}

View File

@ -7,10 +7,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::utils::span_lint;
/// **What it does:** Checks for usage of blacklisted names for variables, such
@ -38,9 +37,7 @@ pub struct BlackListedName {
impl BlackListedName {
pub fn new(blacklist: Vec<String>) -> Self {
Self {
blacklist,
}
Self { blacklist }
}
}

View File

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use matches::matches;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::utils::*;
use matches::matches;
/// **What it does:** Checks for `if` conditions that use blocks to contain an
/// expression.
@ -112,10 +111,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
);
}
} else {
let span = block
.expr
.as_ref()
.map_or_else(|| block.stmts[0].span, |e| e.span);
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if in_macro(span) || differing_macro_contexts(expr.span, span) {
return;
}
@ -134,10 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
}
}
} else {
let mut visitor = ExVisitor {
found_block: None,
cx,
};
let mut visitor = ExVisitor { found_block: None, cx };
walk_expr(&mut visitor, check);
if let Some(block) = visitor.found_block {
span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);

View File

@ -7,16 +7,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::intravisit::*;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::*;
use crate::rustc_data_structures::thin_vec::ThinVec;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID};
use crate::syntax::source_map::{dummy_spanned, Span, DUMMY_SP};
use crate::rustc_data_structures::thin_vec::ThinVec;
use crate::utils::{in_macro, paths, match_type, snippet_opt, span_lint_and_then, SpanlessEq, get_trait_def_id, implements_trait};
use crate::rustc_errors::Applicability;
use crate::utils::{
get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_then, SpanlessEq,
};
/// **What it does:** Checks for boolean expressions that can be written more
/// concisely.
@ -57,10 +58,7 @@ declare_clippy_lint! {
}
// For each pairs, both orders are considered.
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [
("is_some", "is_none"),
("is_err", "is_ok"),
];
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
#[derive(Copy, Clone)]
pub struct NonminimalBool;
@ -134,19 +132,16 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
}
let negated = match e.node {
ExprKind::Binary(binop, ref lhs, ref rhs) => {
if !implements_ord(self.cx, lhs) {
continue;
}
let mk_expr = |op| {
Expr {
id: DUMMY_NODE_ID,
hir_id: DUMMY_HIR_ID,
span: DUMMY_SP,
attrs: ThinVec::new(),
node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
}
let mk_expr = |op| Expr {
id: DUMMY_NODE_ID,
hir_id: DUMMY_HIR_ID,
span: DUMMY_SP,
attrs: ThinVec::new(),
node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
};
match binop.node {
BinOpKind::Eq => mk_expr(BinOpKind::Ne),
@ -191,7 +186,6 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
fn simplify_not(&self, expr: &Expr) -> Option<String> {
match expr.node {
ExprKind::Binary(binop, ref lhs, ref rhs) => {
if !implements_ord(self.cx, lhs) {
return None;
}
@ -204,16 +198,19 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
BinOpKind::Le => Some(" > "),
BinOpKind::Ge => Some(" < "),
_ => None,
}.and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?)))
}
.and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?)))
},
ExprKind::MethodCall(ref path, _, ref args) if args.len() == 1 => {
let type_of_receiver = self.cx.tables.expr_ty(&args[0]);
if !match_type(self.cx, type_of_receiver, &paths::OPTION) &&
!match_type(self.cx, type_of_receiver, &paths::RESULT) {
return None;
if !match_type(self.cx, type_of_receiver, &paths::OPTION)
&& !match_type(self.cx, type_of_receiver, &paths::RESULT)
{
return None;
}
METHODS_WITH_NEGATION
.iter().cloned()
.iter()
.cloned()
.flat_map(|(a, b)| vec![(a, b), (b, a)])
.find(|&(a, _)| a == path.ident.as_str())
.and_then(|(_, neg_method)| Some(format!("{}.{}()", self.snip(&args[0])?, neg_method)))
@ -452,7 +449,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
improvements
.into_iter()
.map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals).0)
.collect()
.collect(),
);
}
}
@ -465,11 +462,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
return;
}
match e.node {
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => self.bool_expr(e),
ExprKind::Unary(UnNot, ref inner) => if self.cx.tables.node_types()[inner.hir_id].is_bool() {
self.bool_expr(e);
} else {
walk_expr(self, e);
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
self.bool_expr(e)
},
ExprKind::Unary(UnNot, ref inner) => {
if self.cx.tables.node_types()[inner.hir_id].is_bool() {
self.bool_expr(e);
} else {
walk_expr(self, e);
}
},
_ => walk_expr(self, e),
}
@ -479,9 +480,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
}
}
fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr) -> bool {
let ty = cx.tables.expr_ty(expr);
get_trait_def_id(cx, &paths::ORD)
.map_or(false, |id| implements_trait(cx, ty, id, &[]))
get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
@ -118,10 +117,12 @@ fn check_arg(name: Name, arg: Name, needle: &Expr) -> bool {
fn get_path_name(expr: &Expr) -> Option<Name> {
match expr.node {
ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) | ExprKind::Unary(UnOp::UnDeref, ref e) => get_path_name(e),
ExprKind::Block(ref b, _) => if b.stmts.is_empty() {
b.expr.as_ref().and_then(|p| get_path_name(p))
} else {
None
ExprKind::Block(ref b, _) => {
if b.stmts.is_empty() {
b.expr.as_ref().and_then(|p| get_path_name(p))
} else {
None
}
},
ExprKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
_ => None,

View File

@ -56,7 +56,7 @@ fn is_empty_str(value: &Option<String>) -> bool {
match value {
None => true,
Some(value) if value.is_empty() => true,
_ => false
_ => false,
}
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for if expressions that contain only an if expression.
//!
//! For example, the lint would catch:
@ -24,12 +23,12 @@
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast;
use if_chain::if_chain;
use crate::utils::{in_macro, snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then};
use crate::utils::sugg::Sugg;
use crate::rustc_errors::Applicability;
use crate::utils::sugg::Sugg;
use crate::utils::{in_macro, snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then};
/// **What it does:** Checks for nested `if` statements which can be collapsed
/// by `&&`-combining their conditions and for `else { if ... }` expressions
@ -100,10 +99,12 @@ impl EarlyLintPass for CollapsibleIf {
fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
match expr.node {
ast::ExprKind::If(ref check, ref then, ref else_) => if let Some(ref else_) = *else_ {
check_collapsible_maybe_if_let(cx, else_);
} else {
check_collapsible_no_if_let(cx, expr, check, then);
ast::ExprKind::If(ref check, ref then, ref else_) => {
if let Some(ref else_) = *else_ {
check_collapsible_maybe_if_let(cx, else_);
} else {
check_collapsible_no_if_let(cx, expr, check, then);
}
},
ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => {
check_collapsible_maybe_if_let(cx, else_);
@ -114,8 +115,9 @@ fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
// We trim all opening braces and whitespaces and then check if the next string is a comment.
let trimmed_block_text =
snippet_block(cx, expr.span, "..").trim_left_matches(|c: char| c.is_whitespace() || c == '{').to_owned();
let trimmed_block_text = snippet_block(cx, expr.span, "..")
.trim_left_matches(|c: char| c.is_whitespace() || c == '{')
.to_owned();
trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
}

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::syntax::ast::*;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{in_macro, snippet, span_lint_and_then};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*;
use crate::utils::{in_macro, snippet, span_lint_and_then};
/// **What it does:** Checks for constants with an explicit `'static` lifetime.
///
@ -52,16 +51,17 @@ impl StaticConst {
TyKind::Array(ref ty, _) => {
self.visit_type(&*ty, cx);
},
TyKind::Tup(ref tup) => for tup_ty in tup {
self.visit_type(&*tup_ty, cx);
TyKind::Tup(ref tup) => {
for tup_ty in tup {
self.visit_type(&*tup_ty, cx);
}
},
// This is what we are looking for !
TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
// Match the 'static lifetime
if let Some(lifetime) = *optional_lifetime {
match borrow_type.ty.node {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) |
TyKind::Tup(..) => {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
if lifetime.ident.name == "'static" {
let snip = snippet(cx, borrow_type.ty.span, "<type>");
let sugg = format!("&{}", snip);
@ -72,7 +72,7 @@ impl StaticConst {
"Constants have by default a `'static` lifetime",
|db| {
db.span_suggestion_with_applicability(
ty.span,
ty.span,
"consider removing `'static`",
sugg,
Applicability::MachineApplicable, //snippet
@ -80,8 +80,8 @@ impl StaticConst {
},
);
}
}
_ => {}
},
_ => {},
}
}
self.visit_type(&*borrow_type.ty, cx);

View File

@ -10,21 +10,21 @@
#![allow(clippy::float_cmp)]
use crate::rustc::lint::LateContext;
use crate::rustc::{span_bug, bug};
use crate::rustc::hir::def::Def;
use crate::rustc::hir::*;
use crate::rustc::ty::{self, Ty, TyCtxt, Instance};
use crate::rustc::lint::LateContext;
use crate::rustc::ty::subst::{Subst, Substs};
use crate::rustc::ty::{self, Instance, Ty, TyCtxt};
use crate::rustc::{bug, span_bug};
use crate::syntax::ast::{FloatTy, LitKind};
use crate::syntax::ptr::P;
use crate::utils::{clip, sext, unsext};
use std::cmp::Ordering::{self, Equal};
use std::cmp::PartialOrd;
use std::convert::TryInto;
use std::hash::{Hash, Hasher};
use std::mem;
use std::rc::Rc;
use crate::syntax::ast::{FloatTy, LitKind};
use crate::syntax::ptr::P;
use crate::utils::{sext, unsext, clip};
/// A `LitKind`-like enum to fold constant `Expr`s into.
#[derive(Debug, Clone)]
@ -71,7 +71,9 @@ impl PartialEq for Constant {
unsafe { mem::transmute::<f64, u64>(f64::from(l)) == mem::transmute::<f64, u64>(f64::from(r)) }
},
(&Constant::Bool(l), &Constant::Bool(r)) => l == r,
(&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r,
(&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => {
l == r
},
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
_ => false, // TODO: Are there inter-type equalities?
}
@ -117,7 +119,12 @@ impl Hash for Constant {
}
impl Constant {
pub fn partial_cmp(tcx: TyCtxt<'_, '_, '_>, cmp_type: &ty::TyKind<'_>, left: &Self, right: &Self) -> Option<Ordering> {
pub fn partial_cmp(
tcx: TyCtxt<'_, '_, '_>,
cmp_type: &ty::TyKind<'_>,
left: &Self,
right: &Self,
) -> Option<Ordering> {
match (left, right) {
(&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)),
(&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)),
@ -158,8 +165,7 @@ pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant {
LitKind::ByteStr(ref s) => Constant::Binary(Rc::clone(s)),
LitKind::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n),
LitKind::Float(ref is, _) |
LitKind::FloatUnsuffixed(ref is) => match ty.sty {
LitKind::Float(ref is, _) | LitKind::FloatUnsuffixed(ref is) => match ty.sty {
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
_ => bug!(),
@ -168,7 +174,11 @@ pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant {
}
}
pub fn constant<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>, e: &Expr) -> Option<(Constant, bool)> {
pub fn constant<'c, 'cc>(
lcx: &LateContext<'c, 'cc>,
tables: &'c ty::TypeckTables<'cc>,
e: &Expr,
) -> Option<(Constant, bool)> {
let mut cx = ConstEvalLateContext {
tcx: lcx.tcx,
tables,
@ -179,12 +189,19 @@ pub fn constant<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTable
cx.expr(e).map(|cst| (cst, cx.needed_resolution))
}
pub fn constant_simple<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>, e: &Expr) -> Option<Constant> {
pub fn constant_simple<'c, 'cc>(
lcx: &LateContext<'c, 'cc>,
tables: &'c ty::TypeckTables<'cc>,
e: &Expr,
) -> Option<Constant> {
constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
}
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`
pub fn constant_context<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>) -> ConstEvalLateContext<'c, 'cc> {
pub fn constant_context<'c, 'cc>(
lcx: &LateContext<'c, 'cc>,
tables: &'c ty::TypeckTables<'cc>,
) -> ConstEvalLateContext<'c, 'cc> {
ConstEvalLateContext {
tcx: lcx.tcx,
tables,
@ -270,9 +287,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
/// create `Some(Vec![..])` of all constants, unless there is any
/// non-constant part
fn multi(&mut self, vec: &[Expr]) -> Option<Vec<Constant>> {
vec.iter()
.map(|elem| self.expr(elem))
.collect::<Option<_>>()
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
}
/// lookup a possibly constant expression from a ExprKind::Path
@ -331,63 +346,51 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
let l = self.expr(left)?;
let r = self.expr(right);
match (l, r) {
(Constant::Int(l), Some(Constant::Int(r))) => {
match self.tables.expr_ty(left).sty {
ty::Int(ity) => {
let l = sext(self.tcx, l, ity);
let r = sext(self.tcx, r, ity);
let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
match op.node {
BinOpKind::Add => l.checked_add(r).map(zext),
BinOpKind::Sub => l.checked_sub(r).map(zext),
BinOpKind::Mul => l.checked_mul(r).map(zext),
BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
BinOpKind::Shr => l.checked_shr(
r.try_into().expect("invalid shift")
).map(zext),
BinOpKind::Shl => l.checked_shl(
r.try_into().expect("invalid shift")
).map(zext),
BinOpKind::BitXor => Some(zext(l ^ r)),
BinOpKind::BitOr => Some(zext(l | r)),
BinOpKind::BitAnd => Some(zext(l & r)),
BinOpKind::Eq => Some(Constant::Bool(l == r)),
BinOpKind::Ne => Some(Constant::Bool(l != r)),
BinOpKind::Lt => Some(Constant::Bool(l < r)),
BinOpKind::Le => Some(Constant::Bool(l <= r)),
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None,
}
(Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).sty {
ty::Int(ity) => {
let l = sext(self.tcx, l, ity);
let r = sext(self.tcx, r, ity);
let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
match op.node {
BinOpKind::Add => l.checked_add(r).map(zext),
BinOpKind::Sub => l.checked_sub(r).map(zext),
BinOpKind::Mul => l.checked_mul(r).map(zext),
BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
BinOpKind::BitXor => Some(zext(l ^ r)),
BinOpKind::BitOr => Some(zext(l | r)),
BinOpKind::BitAnd => Some(zext(l & r)),
BinOpKind::Eq => Some(Constant::Bool(l == r)),
BinOpKind::Ne => Some(Constant::Bool(l != r)),
BinOpKind::Lt => Some(Constant::Bool(l < r)),
BinOpKind::Le => Some(Constant::Bool(l <= r)),
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None,
}
ty::Uint(_) => {
match op.node {
BinOpKind::Add => l.checked_add(r).map(Constant::Int),
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
BinOpKind::Shr => l.checked_shr(
r.try_into().expect("shift too large")
).map(Constant::Int),
BinOpKind::Shl => l.checked_shl(
r.try_into().expect("shift too large")
).map(Constant::Int),
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
BinOpKind::BitOr => Some(Constant::Int(l | r)),
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
BinOpKind::Eq => Some(Constant::Bool(l == r)),
BinOpKind::Ne => Some(Constant::Bool(l != r)),
BinOpKind::Lt => Some(Constant::Bool(l < r)),
BinOpKind::Le => Some(Constant::Bool(l <= r)),
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None,
}
},
},
ty::Uint(_) => match op.node {
BinOpKind::Add => l.checked_add(r).map(Constant::Int),
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
BinOpKind::BitOr => Some(Constant::Int(l | r)),
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
BinOpKind::Eq => Some(Constant::Bool(l == r)),
BinOpKind::Ne => Some(Constant::Bool(l != r)),
BinOpKind::Lt => Some(Constant::Bool(l < r)),
BinOpKind::Le => Some(Constant::Bool(l <= r)),
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None,
}
},
_ => None,
},
(Constant::F32(l), Some(Constant::F32(r))) => match op.node {
BinOpKind::Add => Some(Constant::F32(l + r)),
@ -420,7 +423,9 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
(l, r) => match (op.node, l, r) {
(BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
(BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
(BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => Some(r),
(BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
Some(r)
},
(BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
(BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
(BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
@ -431,36 +436,34 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}
pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<'tcx>) -> Option<Constant> {
use crate::rustc::mir::interpret::{Scalar, ConstValue};
use crate::rustc::mir::interpret::{ConstValue, Scalar};
match result.val {
ConstValue::Scalar(Scalar::Bits{ bits: b, ..}) => match result.ty.sty {
ConstValue::Scalar(Scalar::Bits { bits: b, .. }) => match result.ty.sty {
ty::Bool => Some(Constant::Bool(b == 1)),
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(b)),
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
b.try_into().expect("invalid f32 bit representation")
b.try_into().expect("invalid f32 bit representation"),
))),
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
b.try_into().expect("invalid f64 bit representation")
b.try_into().expect("invalid f64 bit representation"),
))),
// FIXME: implement other conversion
_ => None,
},
ConstValue::ScalarPair(Scalar::Ptr(ptr),
Scalar::Bits { bits: n, .. }) => match result.ty.sty {
ConstValue::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: n, .. }) => match result.ty.sty {
ty::Ref(_, tam, _) => match tam.sty {
ty::Str => {
let alloc = tcx
.alloc_map
.lock()
.unwrap_memory(ptr.alloc_id);
let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
let offset = ptr.offset.bytes().try_into().expect("too-large pointer offset");
let n = n as usize;
String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned()).ok().map(Constant::Str)
String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned())
.ok()
.map(Constant::Str)
},
_ => None,
},
_ => None,
}
},
// FIXME: implement other conversions
_ => None,
}

View File

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty::Ty;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::Ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashMap;
use crate::syntax::symbol::LocalInternedString;
use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint};
use crate::utils::{SpanlessEq, SpanlessHash};
use smallvec::SmallVec;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;
use crate::syntax::symbol::LocalInternedString;
use smallvec::SmallVec;
use crate::utils::{SpanlessEq, SpanlessHash};
use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint};
/// **What it does:** Checks for consecutive `if`s with the same condition.
///
@ -168,7 +167,8 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
h.finish()
};
let eq: &dyn Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
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) {
span_note_and_lint(
@ -229,7 +229,10 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
// hiding all the subsequent arms, and rust won't compile
db.span_note(
i.body.span,
&format!("`{}` has the same arm body as the `_` wildcard, consider removing it`", lhs),
&format!(
"`{}` has the same arm body as the `_` wildcard, consider removing it`",
lhs
),
);
} else {
db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
@ -276,11 +279,17 @@ fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>)
/// Return the list of bindings in a pattern.
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalInternedString, Ty<'tcx>> {
fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut FxHashMap<LocalInternedString, Ty<'tcx>>) {
fn bindings_impl<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &Pat,
map: &mut FxHashMap<LocalInternedString, Ty<'tcx>>,
) {
match pat.node {
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
PatKind::TupleStruct(_, ref pats, _) => for pat in pats {
bindings_impl(cx, pat, map);
PatKind::TupleStruct(_, ref pats, _) => {
for pat in pats {
bindings_impl(cx, pat, map);
}
},
PatKind::Binding(_, _, ident, ref as_pat) => {
if let Entry::Vacant(v) = map.entry(ident.as_str()) {
@ -290,11 +299,15 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalI
bindings_impl(cx, as_pat, map);
}
},
PatKind::Struct(_, ref fields, _) => for pat in fields {
bindings_impl(cx, &pat.node.pat, map);
PatKind::Struct(_, ref fields, _) => {
for pat in fields {
bindings_impl(cx, &pat.node.pat, map);
}
},
PatKind::Tuple(ref fields, _) => for pat in fields {
bindings_impl(cx, pat, map);
PatKind::Tuple(ref fields, _) => {
for pat in fields {
bindings_impl(cx, pat, map);
}
},
PatKind::Slice(ref lhs, ref mid, ref rhs) => {
for pat in lhs {
@ -316,7 +329,6 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalI
result
}
fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
where
Eq: Fn(&T, &T) -> bool,
@ -345,10 +357,8 @@ where
};
}
let mut map: FxHashMap<_, Vec<&_>> = FxHashMap::with_capacity_and_hasher(
exprs.len(),
BuildHasherDefault::default()
);
let mut map: FxHashMap<_, Vec<&_>> =
FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
for expr in exprs {
match map.entry(hash(expr)) {

View File

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::utils::{is_copy, match_path, paths, span_note_and_lint};
use crate::rustc::hir::{Item, ItemKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{is_copy, match_path, paths, span_note_and_lint};
/// **What it does:** Checks for types that implement `Copy` as well as
/// `Iterator`.

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! calculate cyclomatic complexity and warn about overly complex functions
use crate::rustc::cfg::CFG;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::ty;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::{Attribute, NodeId};
use crate::syntax::source_map::Span;
@ -138,12 +137,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity {
}
fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
self.limit
.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
}
fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
self.limit
.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
}
}
@ -197,7 +194,16 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
#[cfg(feature = "debugging")]
#[allow(clippy::too_many_arguments)]
fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, _: NodeId) {
fn report_cc_bug(
_: &LateContext<'_, '_>,
cc: u64,
narms: u64,
div: u64,
shorts: u64,
returns: u64,
span: Span,
_: NodeId,
) {
span_bug!(
span,
"Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
@ -211,7 +217,16 @@ fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts:
}
#[cfg(not(feature = "debugging"))]
#[allow(clippy::too_many_arguments)]
fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, id: NodeId) {
fn report_cc_bug(
cx: &LateContext<'_, '_>,
cc: u64,
narms: u64,
div: u64,
shorts: u64,
returns: u64,
span: Span,
id: NodeId,
) {
if !is_allowed(cx, CYCLOMATIC_COMPLEXITY, id) {
cx.sess().span_note_without_error(
span,
@ -220,11 +235,7 @@ fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts
(hide this message with `#[allow(cyclomatic_complexity)]`): \
cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \
Please file a bug report.",
cc,
narms,
div,
shorts,
returns
cc, narms, div, shorts, returns
),
);
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::TyKind;
@ -17,7 +16,6 @@ use if_chain::if_chain;
use crate::utils::{any_parent_is_automatically_derived, match_def_path, opt_def_id, paths, span_lint_and_sugg};
/// **What it does:** Checks for literal calls to `Default::default()`.
///
/// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
@ -51,44 +49,44 @@ impl LintPass for DefaultTraitAccess {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DefaultTraitAccess {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_chain! {
if let ExprKind::Call(ref path, ..) = expr.node;
if !any_parent_is_automatically_derived(cx.tcx, expr.id);
if let ExprKind::Path(ref qpath) = path.node;
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
if match_def_path(cx.tcx, def_id, &paths::DEFAULT_TRAIT_METHOD);
then {
match qpath {
QPath::Resolved(..) => {
if_chain! {
// Detect and ignore <Foo as Default>::default() because these calls do
// explicitly name the type.
if let ExprKind::Call(ref method, ref _args) = expr.node;
if let ExprKind::Path(ref p) = method.node;
if let QPath::Resolved(Some(_ty), _path) = p;
then {
return;
}
}
if let ExprKind::Call(ref path, ..) = expr.node;
if !any_parent_is_automatically_derived(cx.tcx, expr.id);
if let ExprKind::Path(ref qpath) = path.node;
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
if match_def_path(cx.tcx, def_id, &paths::DEFAULT_TRAIT_METHOD);
then {
match qpath {
QPath::Resolved(..) => {
if_chain! {
// Detect and ignore <Foo as Default>::default() because these calls do
// explicitly name the type.
if let ExprKind::Call(ref method, ref _args) = expr.node;
if let ExprKind::Path(ref p) = method.node;
if let QPath::Resolved(Some(_ty), _path) = p;
then {
return;
}
}
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
let expr_ty = cx.tables.expr_ty(expr);
if let TyKind::Adt(..) = expr_ty.sty {
let replacement = format!("{}::default()", expr_ty);
span_lint_and_sugg(
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
&format!("Calling {} is more clear than this expression", replacement),
"try",
replacement,
Applicability::Unspecified, // First resolve the TODO above
);
}
},
QPath::TypeRelative(..) => {},
}
}
}
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
let expr_ty = cx.tables.expr_ty(expr);
if let TyKind::Adt(..) = expr_ty.sty {
let replacement = format!("{}::default()", expr_ty);
span_lint_and_sugg(
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
&format!("Calling {} is more clear than this expression", replacement),
"try",
replacement,
Applicability::Unspecified, // First resolve the TODO above
);
}
},
QPath::TypeRelative(..) => {},
}
}
}
}
}

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty::{self, Ty};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::utils::paths;
use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
/// explicitly or vice versa.
@ -154,18 +153,20 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
ty::Adt(def, _) if def.is_union() => return,
// Some types are not Clone by default but could be cloned “by hand” if necessary
ty::Adt(def, substs) => for variant in &def.variants {
for field in &variant.fields {
if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty {
return;
}
}
for subst in substs {
if let ty::subst::UnpackedKind::Type(subst) = subst.unpack() {
if let ty::Param(_) = subst.sty {
ty::Adt(def, substs) => {
for variant in &def.variants {
for field in &variant.fields {
if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty {
return;
}
}
for subst in substs {
if let ty::subst::UnpackedKind::Type(subst) = subst.unpack() {
if let ty::Param(_) = subst.sty {
return;
}
}
}
}
},
_ => (),

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use itertools::Itertools;
use pulldown_cmark;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::syntax::source_map::{BytePos, Span};
use crate::syntax_pos::Pos;
use crate::utils::span_lint;
use itertools::Itertools;
use pulldown_cmark;
use url::Url;
/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
@ -49,9 +48,7 @@ pub struct Doc {
impl Doc {
pub fn new(valid_idents: Vec<String>) -> Self {
Self {
valid_idents,
}
Self { valid_idents }
}
}
@ -107,9 +104,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
doc.push('\n');
return (
doc.to_owned(),
vec![
(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32))),
],
vec![(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32)))],
);
}
}
@ -275,13 +270,10 @@ fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) {
return false;
}
let s = if s.ends_with('s') {
&s[..s.len() - 1]
} else {
s
};
let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s };
s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
s.chars().all(char::is_alphanumeric)
&& s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
&& s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Lint on unnecessary double comparisons. Some examples:
use crate::rustc::hir::*;
@ -51,18 +50,11 @@ impl LintPass for Pass {
impl<'a, 'tcx> Pass {
#[allow(clippy::similar_names)]
fn check_binop(
&self,
cx: &LateContext<'a, 'tcx>,
op: BinOpKind,
lhs: &'tcx Expr,
rhs: &'tcx Expr,
span: Span,
) {
fn check_binop(&self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) {
let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) {
(ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
(lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
}
},
_ => return,
};
let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
@ -84,13 +76,21 @@ impl<'a, 'tcx> Pass {
sugg,
applicability,
);
}}
}};
}
match (op, lkind, rkind) {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => lint_double_comparison!(<=),
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => lint_double_comparison!(>=),
(BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => lint_double_comparison!(!=),
(BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => lint_double_comparison!(==),
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
lint_double_comparison!(<=)
},
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
lint_double_comparison!(>=)
},
(BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
lint_double_comparison!(!=)
},
(BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
lint_double_comparison!(==)
},
_ => (),
};
}

View File

@ -7,13 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::syntax::ast::*;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*;
use crate::utils::{in_macro, span_lint};
/// **What it does:** Checks for unnecessary double parentheses.
///
/// **Why is this bad?** This makes code harder to read and might indicate a
@ -51,20 +49,39 @@ impl EarlyLintPass for DoubleParens {
match expr.node {
ExprKind::Paren(ref in_paren) => match in_paren.node {
ExprKind::Paren(_) | ExprKind::Tup(_) => {
span_lint(cx, DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses");
span_lint(
cx,
DOUBLE_PARENS,
expr.span,
"Consider removing unnecessary double parentheses",
);
},
_ => {},
},
ExprKind::Call(_, ref params) => if params.len() == 1 {
let param = &params[0];
if let ExprKind::Paren(_) = param.node {
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
ExprKind::Call(_, ref params) => {
if params.len() == 1 {
let param = &params[0];
if let ExprKind::Paren(_) = param.node {
span_lint(
cx,
DOUBLE_PARENS,
param.span,
"Consider removing unnecessary double parentheses",
);
}
}
},
ExprKind::MethodCall(_, ref params) => if params.len() == 2 {
let param = &params[1];
if let ExprKind::Paren(_) = param.node {
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
ExprKind::MethodCall(_, ref params) => {
if params.len() == 2 {
let param = &params[1];
if let ExprKind::Paren(_) = param.node {
span_lint(
cx,
DOUBLE_PARENS,
param.span,
"Consider removing unnecessary double parentheses",
);
}
}
},
_ => {},

View File

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint};
use if_chain::if_chain;
/// **What it does:** Checks for calls to `std::mem::drop` with a reference
/// instead of an owned value.
@ -70,9 +69,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// let x:i32 = 42; // i32 implements Copy
/// let x: i32 = 42; // i32 implements Copy
/// std::mem::drop(x) // A copy of x is passed to the function, leaving the
/// // original unaffected
/// // original unaffected
/// ```
declare_clippy_lint! {
pub DROP_COPY,
@ -97,9 +96,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// let x:i32 = 42; // i32 implements Copy
/// let x: i32 = 42; // i32 implements Copy
/// std::mem::forget(x) // A copy of x is passed to the function, leaving the
/// // original unaffected
/// // original unaffected
/// ```
declare_clippy_lint! {
pub FORGET_COPY,

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
@ -68,7 +67,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec {
expr.span,
&format!("Calling `{}()` is more concise than this calculation", suggested_fn),
"try",
format!("{}.{}()", snippet_with_applicability(cx, args[0].span, "_", &mut applicability), suggested_fn),
format!(
"{}.{}()",
snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
suggested_fn
),
applicability,
);
}

View File

@ -7,10 +7,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on if expressions with an else if, but without a final else branch
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*;

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint when there is an enum with no variants
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::utils::span_lint_and_then;
/// **What it does:** Checks for `enum`s with no variants.
@ -47,11 +46,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum {
let did = cx.tcx.hir.local_def_id(item.id);
if let ItemKind::Enum(..) = item.node {
let ty = cx.tcx.type_of(did);
let adt = ty.ty_adt_def()
.expect("already checked whether this is an enum");
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
if adt.variants.is_empty() {
span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| {
db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it");
db.span_help(
item.span,
"consider using the uninhabited type `!` or a wrapper around it",
);
});
}
}

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span;
use crate::utils::SpanlessEq;
use crate::utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty};
use crate::rustc_errors::Applicability;
use if_chain::if_chain;
/// **What it does:** Checks for uses of `contains_key` + `insert` on `HashMap`
/// or `BTreeMap`.
@ -26,12 +25,16 @@ use crate::rustc_errors::Applicability;
/// **Known problems:** Some false negatives, eg.:
/// ```rust
/// let k = &key;
/// if !m.contains_key(k) { m.insert(k.clone(), v); }
/// if !m.contains_key(k) {
/// m.insert(k.clone(), v);
/// }
/// ```
///
/// **Example:**
/// ```rust
/// if !m.contains_key(&k) { m.insert(k, v) }
/// if !m.contains_key(&k) {
/// m.insert(k, v)
/// }
/// ```
/// can be rewritten as:
/// ```rust
@ -60,11 +63,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint {
// in case of `if !m.contains_key(&k) { m.insert(k, v); }`
// we can give a better error message
let sole_expr = {
else_block.is_none() && if let ExprKind::Block(ref then_block, _) = then_block.node {
(then_block.expr.is_some() as usize) + then_block.stmts.len() == 1
} else {
true
}
else_block.is_none()
&& if let ExprKind::Block(ref then_block, _) = then_block.node {
(then_block.expr.is_some() as usize) + then_block.stmts.len() == 1
} else {
true
}
};
let mut visitor = InsertVisitor {

View File

@ -7,20 +7,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::consts::{miri_to_const, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::mir::interpret::GlobalId;
use crate::rustc::ty;
use crate::rustc::ty::subst::Substs;
use crate::rustc::ty::util::IntTypeExt;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::{IntTy, UintTy};
use crate::utils::span_lint;
use crate::consts::{Constant, miri_to_const};
use crate::rustc::ty::util::IntTypeExt;
use crate::rustc::mir::interpret::GlobalId;
/// **What it does:** Checks for C-like enumerations that are
/// `repr(isize/usize)` and have values that don't fit into an `i32`.
@ -35,7 +34,7 @@ use crate::rustc::mir::interpret::GlobalId;
/// #[repr(usize)]
/// enum NonPortable {
/// X = 0x1_0000_0000,
/// Y = 0
/// Y = 0,
/// }
/// ```
declare_clippy_lint! {
@ -68,7 +67,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
let instance = ty::Instance::new(def_id, substs);
let c_id = GlobalId {
instance,
promoted: None
promoted: None,
};
let constant = cx.tcx.const_eval(param_env.and(c_id)).ok();
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) {
@ -84,7 +83,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
if val <= i128::from(i32::max_value()) && val >= i128::from(i32::min_value()) {
continue;
}
}
},
ty::Uint(UintTy::Usize) if val > u128::from(u32::max_value()) => {},
_ => continue,
}

View File

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on `use`ing all variants of an enum
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::NodeId;
@ -60,12 +59,7 @@ impl EnumGlobUse {
}
if let ItemKind::Use(ref path, UseKind::Glob) = item.node {
if let Def::Enum(_) = path.def {
span_lint(
cx,
ENUM_GLOB_USE,
item.span,
"don't use glob imports for enum variants",
);
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
}

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on enum variants that are prefixed or suffixed by the same characters
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, Lint};
use crate::rustc::lint::{EarlyContext, EarlyLintPass, Lint, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*;
use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString;
use crate::utils::{span_help_and_lint, span_lint};
use crate::utils::{camel_case, in_macro};
use crate::utils::{span_help_and_lint, span_lint};
/// **What it does:** Detects enumeration variants that are prefixed or suffixed
/// by the same characters.
@ -139,10 +138,7 @@ fn var2str(var: &Variant) -> LocalInternedString {
fn partial_match(pre: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next_back(); // make sure the name is never fully matched
pre.chars()
.zip(name_iter)
.take_while(|&(l, r)| l == r)
.count()
pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
}
/// Returns the number of chars that match from the end
@ -171,9 +167,7 @@ fn check_variant(
for var in &def.variants {
let name = var2str(var);
if partial_match(item_name, &name) == item_name_chars
&& name.chars()
.nth(item_name_chars)
.map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
{
span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
}
@ -277,19 +271,26 @@ impl EarlyLintPass for EnumVariantNames {
let rmatching = partial_rmatch(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
let is_word_beginning = |c: char| {
c == '_' || c.is_uppercase() || c.is_numeric()
};
let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
if matching == nchars {
match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) =>
span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"),
_ => ()
Some(c) if is_word_beginning(c) => span_lint(
cx,
STUTTER,
item.span,
"item name starts with its containing module's name",
),
_ => (),
}
}
if rmatching == nchars {
span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name");
span_lint(
cx,
STUTTER,
item.span,
"item name ends with its containing module's name",
);
}
}
}

View File

@ -7,12 +7,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{in_macro, implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq};
use crate::rustc_errors::Applicability;
use crate::utils::{
implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq,
};
/// **What it does:** Checks for equal operands to comparison, logical and
/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
@ -92,7 +93,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false),
BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false),
BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true),
BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => (cx.tcx.lang_items().ord_trait(), true),
BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => {
(cx.tcx.lang_items().ord_trait(), true)
},
};
if let Some(trait_id) = trait_id {
#[allow(clippy::match_same_arms)]
@ -122,7 +125,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
);
},
)
} else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()]) {
} else if lcpy
&& !rcpy
&& implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
{
span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
let lsnip = snippet(cx, l.span, "...").to_string();
db.span_suggestion_with_applicability(
@ -132,7 +138,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
Applicability::MachineApplicable, // snippet
);
})
} else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()]) {
} else if !lcpy
&& rcpy
&& implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
{
span_lint_and_then(
cx,
OP_REF,
@ -154,7 +163,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
(&ExprKind::AddrOf(_, ref l), _) => {
let lty = cx.tables.expr_ty(l);
let lcpy = is_copy(cx, lty);
if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()]) {
if (requires_ref || lcpy)
&& implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
{
span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
let lsnip = snippet(cx, l.span, "...").to_string();
db.span_suggestion_with_applicability(
@ -170,7 +181,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
(_, &ExprKind::AddrOf(_, ref r)) => {
let rty = cx.tables.expr_ty(r);
let rcpy = is_copy(cx, rty);
if (requires_ref || rcpy) && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()]) {
if (requires_ref || rcpy)
&& implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
{
span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| {
let rsnip = snippet(cx, r.span, "...").to_string();
db.span_suggestion_with_applicability(
@ -189,10 +202,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
}
}
fn is_valid_operator(op: BinOp) -> bool {
match op.node {
BinOpKind::Sub | BinOpKind::Div | BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge | BinOpKind::Ne | BinOpKind::And | BinOpKind::Or | BinOpKind::BitXor | BinOpKind::BitAnd | BinOpKind::BitOr => true,
BinOpKind::Sub
| BinOpKind::Div
| BinOpKind::Eq
| BinOpKind::Lt
| BinOpKind::Le
| BinOpKind::Gt
| BinOpKind::Ge
| BinOpKind::Ne
| BinOpKind::And
| BinOpKind::Or
| BinOpKind::BitXor
| BinOpKind::BitAnd
| BinOpKind::BitOr => true,
_ => false,
}
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::consts::{constant_simple, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@ -25,7 +24,9 @@ use crate::utils::{in_macro, span_lint};
///
/// **Example:**
/// ```rust
/// 0 / x; 0 * x; x & 0
/// 0 / x;
/// 0 * x;
/// x & 0
/// ```
declare_clippy_lint! {
pub ERASING_OP,

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit as visit;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::middle::expr_use_visitor::*;
use crate::rustc::middle::mem_categorization::{cmt_, Categorization};
use crate::rustc::ty::{self, Ty};
use crate::rustc::ty::layout::LayoutOf;
use crate::rustc::ty::{self, Ty};
use crate::rustc::util::nodemap::NodeSet;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::NodeId;
use crate::syntax::source_map::Span;
use crate::utils::span_lint;
@ -65,7 +64,6 @@ impl LintPass for Pass {
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
@ -157,7 +155,15 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
}
}
}
fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, loan_cause: LoanCause) {
fn borrow(
&mut self,
_: NodeId,
_: Span,
cmt: &cmt_<'tcx>,
_: ty::Region<'_>,
_: ty::BorrowKind,
loan_cause: LoanCause,
) {
if let Categorization::Local(lid) = cmt.cat {
match loan_cause {
// x.foo()

View File

@ -7,17 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc::hir::*;
use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then};
pub struct EtaPass;
/// **What it does:** Checks for closures which just call another function where
/// the function can be called directly. `unsafe` functions or calls where types
/// get adjusted are ignored.
@ -52,8 +50,10 @@ impl LintPass for EtaPass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
match expr.node {
ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => for arg in args {
check_closure(cx, arg)
ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
for arg in args {
check_closure(cx, arg)
}
},
_ => (),
}

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::ty;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast;
use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
use if_chain::if_chain;
/// **What it does:** Checks for a read and a write to the same variable where
/// whether the read occurs before or after the write depends on the evaluation
@ -30,7 +29,10 @@ use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
/// **Example:**
/// ```rust
/// let mut x = 0;
/// let a = {x = 1; 1} + x;
/// let a = {
/// x = 1;
/// 1
/// } + x;
/// // Unclear whether a is 1 or 2.
/// ```
declare_clippy_lint! {
@ -74,17 +76,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// Find a write to a local variable.
match expr.node {
ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => if let ExprKind::Path(ref qpath) = lhs.node {
if let QPath::Resolved(_, ref path) = *qpath {
if path.segments.len() == 1 {
if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
let mut visitor = ReadVisitor {
cx,
var,
write_expr: expr,
last_expr: expr,
};
check_for_unsequenced_reads(&mut visitor);
ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => {
if let ExprKind::Path(ref qpath) = lhs.node {
if let QPath::Resolved(_, ref path) = *qpath {
if path.segments.len() == 1 {
if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
let mut visitor = ReadVisitor {
cx,
var,
write_expr: expr,
last_expr: expr,
};
check_for_unsequenced_reads(&mut visitor);
}
}
}
}
@ -95,12 +99,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
match stmt.node {
StmtKind::Expr(ref e, _) | StmtKind::Semi(ref e, _) => DivergenceVisitor { cx }.maybe_walk_expr(e),
StmtKind::Decl(ref d, _) => if let DeclKind::Local(ref local) = d.node {
if let Local {
init: Some(ref e), ..
} = **local
{
DivergenceVisitor { cx }.visit_expr(e);
StmtKind::Decl(ref d, _) => {
if let DeclKind::Local(ref local) = d.node {
if let Local { init: Some(ref e), .. } = **local {
DivergenceVisitor { cx }.visit_expr(e);
}
}
},
}
@ -179,12 +182,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
/// This means reads for which there is a common ancestor between the read and
/// the write such that
///
/// * evaluating the ancestor necessarily evaluates both the read and the write
/// (for example, `&x` and `|| x = 1` don't necessarily evaluate `x`), and
/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
/// and `|| x = 1` don't necessarily evaluate `x`), and
///
/// * which one is evaluated first depends on the order of sub-expression
/// evaluation. Blocks, `if`s, loops, `match`es, and the short-circuiting
/// logical operators are considered to have a defined evaluation order.
/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
/// loops, `match`es, and the short-circuiting logical operators are considered to have a defined
/// evaluation order.
///
/// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
@ -232,14 +235,14 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St
}
match expr.node {
ExprKind::Array(_) |
ExprKind::Tup(_) |
ExprKind::MethodCall(..) |
ExprKind::Call(_, _) |
ExprKind::Assign(_, _) |
ExprKind::Index(_, _) |
ExprKind::Repeat(_, _) |
ExprKind::Struct(_, _, _) => {
ExprKind::Array(_)
| ExprKind::Tup(_)
| ExprKind::MethodCall(..)
| ExprKind::Call(_, _)
| ExprKind::Assign(_, _)
| ExprKind::Index(_, _)
| ExprKind::Repeat(_, _)
| ExprKind::Struct(_, _, _) => {
walk_expr(vis, expr);
},
ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
@ -253,13 +256,12 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St
ExprKind::Closure(_, _, _, _, _) => {
// Either
//
// * `var` is defined in the closure body, in which case we've
// reached the top of the enclosing function and can stop, or
// * `var` is defined in the closure body, in which case we've reached the top of the enclosing
// function and can stop, or
//
// * `var` is captured by the closure, in which case, because
// evaluating a closure does not evaluate its body, we don't
// necessarily have a write, so we need to stop to avoid
// generating false positives.
// * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
// its body, we don't necessarily have a write, so we need to stop to avoid generating false
// positives.
//
// This is also the only place we need to stop early (grrr).
return StopEarly::Stop;

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::TyKind;
@ -32,12 +31,12 @@ use std::fmt;
///
/// ```rust
/// // Bad
/// let v: f32 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789
/// let v: f32 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789
///
/// // Good
/// let v: f64 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789_9
/// let v: f64 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789_9
/// ```
declare_clippy_lint! {
pub EXCESSIVE_PRECISION,
@ -82,7 +81,7 @@ impl ExcessivePrecision {
let max = max_digits(fty);
let sym_str = sym.as_str();
if dot_zero_exclusion(&sym_str) {
return None
return None;
}
// Try to bail out if the float is for sure fine.
// If its within the 2 decimal digits of being out of precision we
@ -116,9 +115,7 @@ impl ExcessivePrecision {
/// Ex 1_000_000_000.
fn dot_zero_exclusion(s: &str) -> bool {
if let Some(after_dec) = s.split('.').nth(1) {
let mut decpart = after_dec
.chars()
.take_while(|c| *c != 'e' || *c != 'E');
let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');
match decpart.next() {
Some('0') => decpart.count() == 0,
@ -169,7 +166,9 @@ impl FloatFormat {
.unwrap_or(FloatFormat::Normal)
}
fn format<T>(&self, f: T) -> String
where T: fmt::UpperExp + fmt::LowerExp + fmt::Display {
where
T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
{
match self {
FloatFormat::LowerExp => format!("{:e}", f),
FloatFormat::UpperExp => format!("{:E}", f),

View File

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint};
use crate::utils::opt_def_id;
use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint};
use if_chain::if_chain;
/// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
/// replaced with `(e)print!()` / `(e)println!()`
@ -28,10 +27,10 @@ use crate::utils::opt_def_id;
/// writeln!(&mut io::stderr(), "foo: {:?}", bar).unwrap();
/// ```
declare_clippy_lint! {
pub EXPLICIT_WRITE,
complexity,
"using the `write!()` family of functions instead of the `print!()` family \
of functions, when using the latter would work"
pub EXPLICIT_WRITE,
complexity,
"using the `write!()` family of functions instead of the `print!()` family \
of functions, when using the latter would work"
}
#[derive(Copy, Clone, Debug)]

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax_pos::Span;
use crate::utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, is_expn_of, opt_def_id};
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
use crate::utils::{is_expn_of, match_def_path, method_chain_args, opt_def_id, span_lint_and_then, walk_ptrs_ty};
use if_chain::if_chain;
/// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
///
@ -62,8 +61,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom {
}
fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_items: &hir::HirVec<hir::ImplItemRef>) {
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
struct FindPanicUnwrap<'a, 'tcx: 'a> {
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,

View File

@ -7,16 +7,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind;
use crate::utils::paths;
use crate::utils::{in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty};
use crate::rustc_errors::Applicability;
use crate::utils::{
in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet,
span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
@ -92,17 +94,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
},
// `format!("foo")` expansion contains `match () { () => [], }`
ExprKind::Match(ref matchee, _, _) => if let ExprKind::Tup(ref tup) = matchee.node {
if tup.is_empty() {
let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
db.span_suggestion_with_applicability(
span,
"consider using .to_string()",
sugg,
Applicability::MachineApplicable, // snippet
);
});
ExprKind::Match(ref matchee, _, _) => {
if let ExprKind::Tup(ref tup) = matchee.node {
if tup.is_empty() {
let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
db.span_suggestion_with_applicability(
span,
"consider using .to_string()",
sugg,
Applicability::MachineApplicable, // snippet
);
});
}
}
},
_ => (),

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use crate::syntax::ptr::P;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
/// operators.
@ -78,7 +77,6 @@ declare_clippy_lint! {
"possible missing comma in array"
}
#[derive(Copy, Clone)]
pub struct Formatting;
@ -96,8 +94,8 @@ impl EarlyLintPass for Formatting {
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
for w in block.stmts.windows(2) {
match (&w[0].node, &w[1].node) {
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
| (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
check_consecutive_ifs(cx, first, second);
},
_ => (),
@ -153,9 +151,7 @@ fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
// the snippet should look like " else \n " with maybe comments anywhere
// its bad when there is a \n after the “else”
if let Some(else_snippet) = snippet_opt(cx, else_span) {
let else_pos = else_snippet
.find("else")
.expect("there must be a `else` here");
let else_pos = else_snippet.find("else").expect("there must be a `else` here");
if else_snippet[else_pos..].contains('\n') {
span_note_and_lint(
@ -175,9 +171,7 @@ fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
// &, *, -
bin_op == ast::BinOpKind::And
|| bin_op == ast::BinOpKind::Mul
|| bin_op == ast::BinOpKind::Sub
bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}
/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
@ -208,7 +202,9 @@ fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
if !differing_macro_contexts(first.span, second.span)
&& !in_macro(first.span)
&& unsugar_if(first).is_some()
&& unsugar_if(second).is_some()
{
// where the else would be

View File

@ -7,19 +7,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use matches::matches;
use crate::rustc::hir::intravisit;
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc::hir::def::Def;
use crate::rustc::hir::intravisit;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashSet;
use crate::syntax::ast;
use crate::rustc_target::spec::abi::Abi;
use crate::syntax::ast;
use crate::syntax::source_map::Span;
use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function};
use matches::matches;
/// **What it does:** Checks for functions with too many parameters.
///
@ -31,8 +30,9 @@ use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function};
///
/// **Example:**
/// ```rust
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b:
/// f32) { .. }
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub TOO_MANY_ARGUMENTS,
@ -58,7 +58,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// pub fn foo(x: *const u8) { println!("{}", unsafe { *x }); }
/// pub fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
/// ```
declare_clippy_lint! {
pub NOT_UNSAFE_PTR_ARG_DEREF,
@ -73,9 +75,7 @@ pub struct Functions {
impl Functions {
pub fn new(threshold: u64) -> Self {
Self {
threshold,
}
Self { threshold }
}
}
@ -111,8 +111,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
if !is_impl {
// don't lint extern functions decls, it's not their fault either
match kind {
hir::intravisit::FnKind::Method(_, &hir::MethodSig { header: hir::FnHeader { abi: Abi::Rust, .. }, .. }, _, _) |
hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => self.check_arg_number(cx, decl, span),
hir::intravisit::FnKind::Method(
_,
&hir::MethodSig {
header: hir::FnHeader { abi: Abi::Rust, .. },
..
},
_,
_,
)
| hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
self.check_arg_number(cx, decl, span)
},
_ => {},
}
}

View File

@ -7,14 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::syntax::ast::NodeId;
use crate::utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then};
use crate::utils::{opt_def_id, paths, resolve_node};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::NodeId;
use crate::utils::{
in_macro, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then,
};
use crate::utils::{opt_def_id, paths, resolve_node};
/// **What it does:** Checks for always-identical `Into`/`From`/`IntoIter` conversions.
///
@ -101,22 +102,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
}
},
ExprKind::Call(ref path, ref args) => if let ExprKind::Path(ref qpath) = path.node {
if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) {
if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
let a = cx.tables.expr_ty(e);
let b = cx.tables.expr_ty(&args[0]);
if same_tys(cx, a, b) {
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
db.span_suggestion_with_applicability(
e.span,
&sugg_msg,
sugg,
Applicability::MachineApplicable, // snippet
);
});
ExprKind::Call(ref path, ref args) => {
if let ExprKind::Path(ref qpath) = path.node {
if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) {
if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
let a = cx.tables.expr_ty(e);
let b = cx.tables.expr_ty(&args[0]);
if same_tys(cx, a, b) {
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
let sugg_msg =
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
db.span_suggestion_with_applicability(
e.span,
&sugg_msg,
sugg,
Applicability::MachineApplicable, // snippet
);
});
}
}
}
}

View File

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::consts::{constant_simple, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::utils::{in_macro, snippet, span_lint, unsext, clip};
use crate::rustc::ty;
use crate::utils::{clip, in_macro, snippet, span_lint, unsext};
/// **What it does:** Checks for identity operations, e.g. `x + 0`.
///

View File

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on if branches that could be swapped so no `!` operation is necessary
//! on the condition
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*;

View File

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on indexing and slicing operations
use crate::consts::{constant, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::RangeLimits;
use crate::utils;
use crate::utils::higher;
use crate::utils::higher::Range;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::syntax::ast::RangeLimits;
/// **What it does:** Checks for out of bounds array indexing with a constant
/// index.
@ -29,7 +28,7 @@ use crate::syntax::ast::RangeLimits;
///
/// **Example:**
/// ```rust
/// let x = [1,2,3,4];
/// let x = [1, 2, 3, 4];
///
/// // Bad
/// x[9];
@ -108,7 +107,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
if let ExprKind::Index(ref array, ref index) = &expr.node {
let ty = cx.tables.expr_ty(array);
if let Some(range) = higher::range(cx, index) {
// Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.sty {
let size: u128 = s.assert_usize(cx.tcx).unwrap().into();
@ -153,13 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
(None, None) => return, // [..] is ok.
};
utils::span_help_and_lint(
cx,
INDEXING_SLICING,
expr.span,
"slicing may panic.",
help_msg,
);
utils::span_help_and_lint(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg);
} else {
// Catchall non-range index, i.e. [n] or [n << m]
if let ty::Array(..) = ty.sty {
@ -189,23 +181,21 @@ fn to_const_range<'a, 'tcx>(
range: Range<'_>,
array_size: u128,
) -> (Option<u128>, Option<u128>) {
let s = range
.start
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let start = match s {
Some(Some(Constant::Int(x))) => Some(x),
Some(_) => None,
None => Some(0),
};
let e = range
.end
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let end = match e {
Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed {
Some(x + 1)
} else {
Some(x)
Some(Some(Constant::Int(x))) => {
if range.limits == RangeLimits::Closed {
Some(x + 1)
} else {
Some(x)
}
},
Some(_) => None,
None => Some(array_size),

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
@ -160,7 +159,8 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
First => is_infinite(cx, &args[0]),
Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
}).and(cap);
})
.and(cap);
}
}
if method.ident.name == "flat_map" && args.len() == 2 {
@ -173,14 +173,14 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
},
ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) => is_infinite(cx, e),
ExprKind::Call(ref path, _) => if let ExprKind::Path(ref qpath) = path.node {
match_qpath(qpath, &paths::REPEAT).into()
} else {
Finite
ExprKind::Call(ref path, _) => {
if let ExprKind::Path(ref qpath) = path.node {
match_qpath(qpath, &paths::REPEAT).into()
} else {
Finite
}
},
ExprKind::Struct(..) => higher::range(cx, expr)
.map_or(false, |r| r.end.is_none())
.into(),
ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
_ => Finite,
}
}
@ -235,10 +235,10 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
}
}
},
ExprKind::Binary(op, ref l, ref r) => if op.node.is_comparison() {
return is_infinite(cx, l)
.and(is_infinite(cx, r))
.and(MaybeInfinite);
ExprKind::Binary(op, ref l, ref r) => {
if op.node.is_comparison() {
return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite);
}
}, // TODO: ExprKind::Loop + Match
_ => (),
}

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on inherent implementations
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashMap;
use std::default::Default;
use crate::syntax_pos::Span;
use crate::utils::span_lint_and_then;
use std::default::Default;
/// **What it does:** Checks for multiple inherent implementations of a struct
///
@ -56,7 +55,9 @@ pub struct Pass {
impl Default for Pass {
fn default() -> Self {
Self { impls: FxHashMap::default() }
Self {
impls: FxHashMap::default(),
}
}
}
@ -88,11 +89,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let mut impl_spans = impls
.iter()
.filter_map(|impl_def| self.impls.get(impl_def))
.filter_map(|(span, generics)| if generics.params.len() == 0 {
Some(span)
} else {
None
});
.filter_map(|(span, generics)| if generics.params.len() == 0 { Some(span) } else { None });
if let Some(initial_span) = impl_spans.nth(0) {
impl_spans.for_each(|additional_span| {
span_lint_and_then(
@ -101,10 +98,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
*additional_span,
"Multiple implementations of this structure",
|db| {
db.span_note(
*initial_span,
"First implementation here",
);
db.span_note(*initial_span, "First implementation here");
},
)
})

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! checks for `#[inline]` on trait methods without bodies
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::{Attribute, Name};
use crate::utils::span_lint_and_then;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::rustc_errors::Applicability;
/// **What it does:** Checks for `#[inline]` on trait methods without bodies
///

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint on blocks unnecessarily using >= with a + 1 or - 1
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
@ -162,14 +161,20 @@ impl IntPlusOne {
}
fn emit_warning(&self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| {
db.span_suggestion_with_applicability(
block.span,
"change `>= y + 1` to `> y` as shown",
recommendation,
Applicability::MachineApplicable, // snippet
);
});
span_lint_and_then(
cx,
INT_PLUS_ONE,
block.span,
"Unnecessary `>= y + 1` or `x - 1 >=`",
|db| {
db.span_suggestion_with_applicability(
block.span,
"change `>= y + 1` to `> y` as shown",
recommendation,
Applicability::MachineApplicable, // snippet
);
},
);
}
}

View File

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{match_def_path, opt_def_id, paths, span_help_and_lint};
use if_chain::if_chain;
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
///

View File

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint when items are used after statements
use matches::matches;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*;
use crate::utils::{in_macro, span_lint};
use matches::matches;
/// **What it does:** Checks for items declared after some statement in a block.
///
@ -59,7 +58,8 @@ impl EarlyLintPass for ItemsAfterStatements {
}
// skip initial items
let stmts = item.stmts
let stmts = item
.stmts
.iter()
.map(|stmt| &stmt.node)
.skip_while(|s| matches!(**s, StmtKind::Item(..)));

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! lint when there is a large size difference between variants on an enum
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::utils::{snippet_opt, span_lint_and_then};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::layout::LayoutOf;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::utils::{snippet_opt, span_lint_and_then};
/// **What it does:** Checks for large size differences between variants on
/// `enum`s.
@ -29,8 +28,8 @@ use crate::rustc_errors::Applicability;
/// **Example:**
/// ```rust
/// enum Test {
/// A(i32),
/// B([i32; 8000]),
/// A(i32),
/// B([i32; 8000]),
/// }
/// ```
declare_clippy_lint! {
@ -63,8 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
let did = cx.tcx.hir.local_def_id(item.id);
if let ItemKind::Enum(ref def, _) = item.node {
let ty = cx.tcx.type_of(did);
let adt = ty.ty_adt_def()
.expect("already checked whether this is an enum");
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
let mut smallest_variant: Option<(_, _)> = None;
let mut largest_variant: Option<(_, _)> = None;

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@ -32,19 +31,27 @@ use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lin
///
/// **Example:**
/// ```rust
/// if x.len() == 0 { .. }
/// if y.len() != 0 { .. }
/// if x.len() == 0 {
/// ..
/// }
/// if y.len() != 0 {
/// ..
/// }
/// ```
/// instead use
/// ```rust
/// if x.len().is_empty() { .. }
/// if !y.len().is_empty() { .. }
/// if x.len().is_empty() {
/// ..
/// }
/// if !y.len().is_empty() {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
could be used instead"
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
could be used instead"
}
/// **What it does:** Checks for items that implement `.len()` but not
@ -61,7 +68,9 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// impl X {
/// pub fn len(&self) -> usize { .. }
/// pub fn len(&self) -> usize {
/// ..
/// }
/// }
/// ```
declare_clippy_lint! {
@ -125,14 +134,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && {
let did = cx.tcx.hir.local_def_id(item.id.node_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
item.ident.name == name
&& if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && {
let did = cx.tcx.hir.local_def_id(item.id.node_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
}
} else {
false
}
} else {
false
}
}
// fill the set with current and super traits
@ -153,7 +163,9 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
.iter()
.flat_map(|&i| cx.tcx.associated_items(i))
.any(|i| {
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.ident.name == "is_empty"
i.kind == ty::AssociatedKind::Method
&& i.method_has_self_argument
&& i.ident.name == "is_empty"
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
});
@ -173,14 +185,15 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && {
let did = cx.tcx.hir.local_def_id(item.id.node_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
item.ident.name == name
&& if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && {
let did = cx.tcx.hir.local_def_id(item.id.node_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
}
} else {
false
}
} else {
false
}
}
let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
@ -251,7 +264,11 @@ fn check_len(
span,
&format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
"using `is_empty` is clearer and more explicit",
format!("{}{}.is_empty()", op, snippet_with_applicability(cx, args[0].span, "_", &mut applicability)),
format!(
"{}{}.is_empty()",
op,
snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
),
applicability,
);
}
@ -277,16 +294,16 @@ fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
/// Check the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
cx.tcx.inherent_impls(id).iter().any(|imp| {
cx.tcx
.associated_items(*imp)
.any(|item| is_is_empty(cx, &item))
})
cx.tcx
.inherent_impls(id)
.iter()
.any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
}
let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
match ty.sty {
ty::Dynamic(ref tt, ..) => cx.tcx
ty::Dynamic(ref tt, ..) => cx
.tcx
.associated_items(tt.principal().def_id())
.any(|item| is_is_empty(cx, &item)),
ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::hir::def::Def;
use crate::rustc::hir::BindingAnnotation;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir;
use crate::rustc::hir::BindingAnnotation;
use crate::rustc::hir::def::Def;
use crate::rustc_errors::Applicability;
use crate::syntax::ast;
use crate::utils::{snippet, span_lint_and_then};
use crate::rustc_errors::Applicability;
use if_chain::if_chain;
/// **What it does:** Checks for variable declarations immediately followed by a
/// conditional affectation.
@ -207,11 +206,7 @@ fn check_assign<'a, 'tcx>(
}
fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: ast::NodeId, expr: &'tcx hir::Expr) -> bool {
let mut v = UsedVisitor {
cx,
id,
used: false,
};
let mut v = UsedVisitor { cx, id, used: false };
hir::intravisit::walk_expr(&mut v, expr);
v.used
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:cargo-clippy
#![feature(box_syntax)]
@ -18,7 +17,6 @@
#![allow(clippy::missing_docs_in_private_items)]
#![recursion_limit = "256"]
#![feature(macro_at_most_once_rep)]
#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
#![feature(crate_visibility_modifier)]
#![feature(try_from)]
@ -216,12 +214,19 @@ mod reexport {
crate use crate::syntax::ast::{Name, NodeId};
}
pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore, conf: &Conf) {
pub fn register_pre_expansion_lints(
session: &rustc::session::Session,
store: &mut rustc::lint::LintStore,
conf: &Conf,
) {
store.register_pre_expansion_pass(Some(session), box write::Pass);
store.register_pre_expansion_pass(Some(session), box redundant_field_names::RedundantFieldNames);
store.register_pre_expansion_pass(Some(session), box non_expressive_names::NonExpressiveNames {
single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
});
store.register_pre_expansion_pass(
Some(session),
box non_expressive_names::NonExpressiveNames {
single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
},
);
store.register_pre_expansion_pass(Some(session), box attrs::CfgAttrPass);
}
@ -236,38 +241,49 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf {
match utils::conf::lookup_conf_file() {
Ok(path) => path,
Err(error) => {
reg.sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)).emit();
reg.sess
.struct_err(&format!("error finding Clippy's configuration file: {}", error))
.emit();
None
}
},
}
};
let file_name = file_name.map(|file_name| if file_name.is_relative() {
reg.sess
.local_crate_source_file
.as_ref()
.and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf))
.unwrap_or_default()
.join(file_name)
} else {
file_name
let file_name = file_name.map(|file_name| {
if file_name.is_relative() {
reg.sess
.local_crate_source_file
.as_ref()
.and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf))
.unwrap_or_default()
.join(file_name)
} else {
file_name
}
});
let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref()));
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
reg.sess.struct_err(&format!("error reading Clippy's configuration file `{}`: {}", file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""), error)).emit();
reg.sess
.struct_err(&format!(
"error reading Clippy's configuration file `{}`: {}",
file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""),
error
))
.emit();
}
conf
}
},
Err((err, span)) => {
reg.sess.struct_span_err(span, err)
.span_note(span, "Clippy will use default configuration")
.emit();
reg.sess
.struct_span_err(span, err)
.span_note(span, "Clippy will use default configuration")
.emit();
toml::from_str("").expect("we never error on empty config files")
}
},
}
}

View File

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::reexport::*;
use matches::matches;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::def::Def;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::*;
use crate::rustc::hir::*;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::syntax::source_map::Span;
use crate::utils::{last_path_segment, span_lint};
use crate::syntax::symbol::keywords;
use crate::utils::{last_path_segment, span_lint};
use matches::matches;
/// **What it does:** Checks for lifetime annotations which can be removed by
/// relying on lifetime elision.
@ -32,13 +31,15 @@ use crate::syntax::symbol::keywords;
///
/// **Example:**
/// ```rust
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
/// x
/// }
/// ```
declare_clippy_lint! {
pub NEEDLESS_LIFETIMES,
complexity,
"using explicit lifetimes for references in function arguments when elision rules \
would allow omitting them"
pub NEEDLESS_LIFETIMES,
complexity,
"using explicit lifetimes for references in function arguments when elision rules \
would allow omitting them"
}
/// **What it does:** Checks for lifetimes in generics that are never used
@ -52,7 +53,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// fn unused_lifetime<'a>(x: u8) { .. }
/// fn unused_lifetime<'a>(x: u8) {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub EXTRA_UNUSED_LIFETIMES,
@ -152,7 +155,8 @@ fn check_fn_inner<'a, 'tcx>(
cx,
NEEDLESS_LIFETIMES,
span,
"explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)",
"explicit lifetimes given in parameter types where they could be elided \
(or replaced with `'_` if needed by type declaration)",
);
}
report_extra_lifetimes(cx, decl, generics);
@ -220,9 +224,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
// no output lifetimes, check distinctness of input lifetimes
// only unnamed and static, ok
let unnamed_and_static = input_lts
.iter()
.all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
if unnamed_and_static {
return false;
}
@ -320,7 +322,8 @@ impl<'v, 't> RefVisitor<'v, 't> {
&& !last_path_segment.args.iter().any(|arg| match arg {
GenericArg::Lifetime(_) => true,
GenericArg::Type(_) => false,
}) {
})
{
let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
match self.cx.tables.qpath_def(qpath, hir_id) {
Def::TyAlias(def_id) | Def::Struct(def_id) => {
@ -354,9 +357,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
self.record(&None);
},
TyKind::Path(ref path) => {
self.collect_anonymous_lifetimes(path, ty);
}
},
TyKind::Def(item, _) => {
if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir.expect_item(item.id).node {
for bound in &exist_ty.bounds {
@ -368,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
unreachable!()
}
walk_ty(self, ty);
}
},
TyKind::TraitObject(ref bounds, ref lt) => {
if !lt.is_elided() {
self.abort = true;
@ -410,9 +412,11 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
// and check that all lifetimes are allowed
match visitor.into_vec() {
None => return false,
Some(lts) => for lt in lts {
if !allowed_lts.contains(&lt) {
return true;
Some(lts) => {
for lt in lts {
if !allowed_lts.contains(&lt) {
return true;
}
}
},
}
@ -456,7 +460,9 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
}
fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
let hs = generics.params.iter()
let hs = generics
.params
.iter()
.filter_map(|par| match par.kind {
GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
_ => None,
@ -468,7 +474,12 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx
walk_fn_decl(&mut checker, func);
for &v in checker.map.values() {
span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition");
span_lint(
cx,
EXTRA_UNUSED_LIFETIMES,
v,
"this lifetime isn't used in the function definition",
);
}
}

View File

@ -414,9 +414,11 @@ impl LiteralDigitGrouping {
parts[0].len(),
parts[1].len());
if !consistent {
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
cx,
lit.span);
WarningType::InconsistentDigitGrouping.display(
&digit_info.grouping_hint(),
cx,
lit.span,
);
}
})
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),

View File

@ -7,33 +7,32 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use itertools::Itertools;
use crate::reexport::*;
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def;
use crate::rustc::hir::def_id;
use crate::rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::hir::*;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::middle::region;
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::middle::region;
use itertools::Itertools;
// use crate::rustc::middle::region::CodeExtent;
use crate::consts::{constant, Constant};
use crate::rustc::middle::expr_use_visitor::*;
use crate::rustc::middle::mem_categorization::Categorization;
use crate::rustc::middle::mem_categorization::cmt_;
use crate::rustc::ty::{self, Ty};
use crate::rustc::middle::mem_categorization::Categorization;
use crate::rustc::ty::subst::Subst;
use crate::rustc_errors::Applicability;
use crate::rustc::ty::{self, Ty};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::iter::{once, Iterator};
use std::mem;
use crate::rustc_errors::Applicability;
use crate::syntax::ast;
use crate::syntax::source_map::Span;
use crate::syntax_pos::BytePos;
use crate::utils::{in_macro, sugg, sext};
use crate::utils::usage::mutated_variables;
use crate::consts::{constant, Constant};
use crate::utils::{in_macro, sext, sugg};
use std::iter::{once, Iterator};
use std::mem;
use crate::utils::paths;
use crate::utils::{
@ -92,11 +91,15 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// // with `y` a `Vec` or slice:
/// for x in y.iter() { .. }
/// for x in y.iter() {
/// ..
/// }
/// ```
/// can be rewritten to
/// ```rust
/// for x in &y { .. }
/// for x in &y {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub EXPLICIT_ITER_LOOP,
@ -114,11 +117,15 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// // with `y` a `Vec` or slice:
/// for x in y.into_iter() { .. }
/// for x in y.into_iter() {
/// ..
/// }
/// ```
/// can be rewritten to
/// ```rust
/// for x in y { .. }
/// for x in y {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub EXPLICIT_INTO_ITER_LOOP,
@ -139,7 +146,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// for x in y.next() { .. }
/// for x in y.next() {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub ITER_NEXT_LOOP,
@ -156,12 +165,16 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// for x in option { .. }
/// for x in option {
/// ..
/// }
/// ```
///
/// This should be
/// ```rust
/// if let Some(x) = option { .. }
/// if let Some(x) = option {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub FOR_LOOP_OVER_OPTION,
@ -178,12 +191,16 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// for x in result { .. }
/// for x in result {
/// ..
/// }
/// ```
///
/// This should be
/// ```rust
/// if let Ok(x) = result { .. }
/// if let Ok(x) = result {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub FOR_LOOP_OVER_RESULT,
@ -232,10 +249,10 @@ declare_clippy_lint! {
/// vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();
/// ```
declare_clippy_lint! {
pub UNUSED_COLLECT,
perf,
"`collect()`ing an iterator without using the result; this is usually better \
written as a for loop"
pub UNUSED_COLLECT,
perf,
"`collect()`ing an iterator without using the result; this is usually better \
written as a for loop"
}
/// **What it does:** Checks for functions collecting an iterator when collect
@ -273,7 +290,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// for x in 5..10-5 { .. } // oops, stray `-`
/// for x in 5..10 - 5 {
/// ..
/// } // oops, stray `-`
/// ```
declare_clippy_lint! {
pub REVERSE_RANGE_LOOP,
@ -328,7 +347,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// while let Some(val) = iter() { .. }
/// while let Some(val) = iter() {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub WHILE_LET_ON_ITERATOR,
@ -346,13 +367,17 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// for (k, _) in &map { .. }
/// for (k, _) in &map {
/// ..
/// }
/// ```
///
/// could be replaced by
///
/// ```rust
/// for k in map.keys() { .. }
/// for k in map.keys() {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub FOR_KV_MAP,
@ -370,7 +395,10 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// loop { ..; break; }
/// loop {
/// ..;
/// break;
/// }
/// ```
declare_clippy_lint! {
pub NEVER_LOOP,
@ -412,7 +440,7 @@ declare_clippy_lint! {
/// ```rust
/// let i = 0;
/// while i > 10 {
/// println!("let me loop forever!");
/// println!("let me loop forever!");
/// }
/// ```
declare_clippy_lint! {
@ -459,8 +487,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
match expr.node {
ExprKind::While(_, ref block, _) | ExprKind::Loop(ref block, _, _) => {
match never_loop_block(block, expr.id) {
NeverLoopResult::AlwaysBreak =>
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
NeverLoopResult::AlwaysBreak => {
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops")
},
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
}
},
@ -490,8 +519,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// ensure "if let" compatible match structure
match *source {
MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none()
&& arms[1].pats.len() == 1 && arms[1].guard.is_none()
if arms.len() == 2
&& arms[0].pats.len() == 1
&& arms[0].guard.is_none()
&& arms[1].pats.len() == 1
&& arms[1].guard.is_none()
&& is_simple_break_expr(&arms[1].body)
{
if in_external_macro(cx.sess(), expr.span) {
@ -533,12 +565,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
{
let iter_expr = &method_args[0];
let lhs_constructor = last_path_segment(qpath);
if method_path.ident.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR)
&& lhs_constructor.ident.name == "Some" && (
pat_args.is_empty()
if method_path.ident.name == "next"
&& match_trait_method(cx, match_expr, &paths::ITERATOR)
&& lhs_constructor.ident.name == "Some"
&& (pat_args.is_empty()
|| !is_refutable(cx, &pat_args[0])
&& !is_iterator_used_after_while_let(cx, iter_expr)
&& !is_nested(cx, expr, &method_args[0]))
&& !is_iterator_used_after_while_let(cx, iter_expr)
&& !is_nested(cx, expr, &method_args[0]))
{
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = if pat_args.is_empty() {
@ -594,8 +627,7 @@ enum NeverLoopResult {
fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
match *arg {
NeverLoopResult::AlwaysBreak |
NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
}
}
@ -611,24 +643,22 @@ fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResu
// Combine two results where both parts are called but not necessarily in order.
fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
match (left, right) {
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) =>
NeverLoopResult::MayContinueMainLoop,
(NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) =>
NeverLoopResult::AlwaysBreak,
(NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) =>
NeverLoopResult::Otherwise,
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
NeverLoopResult::MayContinueMainLoop
},
(NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
(NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
}
}
// Combine two results where only one of the part may have been executed.
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
match (b1, b2) {
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) =>
NeverLoopResult::AlwaysBreak,
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) =>
NeverLoopResult::MayContinueMainLoop,
(NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) =>
NeverLoopResult::Otherwise,
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
NeverLoopResult::MayContinueMainLoop
},
(NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
}
}
@ -655,26 +685,28 @@ fn decl_to_expr(decl: &Decl) -> Option<&Expr> {
fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
match expr.node {
ExprKind::Box(ref e) |
ExprKind::Unary(_, ref e) |
ExprKind::Cast(ref e, _) |
ExprKind::Type(ref e, _) |
ExprKind::Field(ref e, _) |
ExprKind::AddrOf(_, ref e) |
ExprKind::Struct(_, _, Some(ref e)) |
ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id),
ExprKind::Box(ref e)
| ExprKind::Unary(_, ref e)
| ExprKind::Cast(ref e, _)
| ExprKind::Type(ref e, _)
| ExprKind::Field(ref e, _)
| ExprKind::AddrOf(_, ref e)
| ExprKind::Struct(_, _, Some(ref e))
| ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id),
ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es) | ExprKind::Tup(ref es) => {
never_loop_expr_all(&mut es.iter(), main_loop_id)
},
ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
ExprKind::Binary(_, ref e1, ref e2) |
ExprKind::Assign(ref e1, ref e2) |
ExprKind::AssignOp(_, ref e1, ref e2) |
ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
ExprKind::Binary(_, ref e1, ref e2)
| ExprKind::Assign(ref e1, ref e2)
| ExprKind::AssignOp(_, ref e1, ref e2)
| ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
ExprKind::If(ref e, ref e2, ref e3) => {
let e1 = never_loop_expr(e, main_loop_id);
let e2 = never_loop_expr(e2, main_loop_id);
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
let e3 = e3
.as_ref()
.map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
combine_seq(e1, combine_branches(e2, e3))
},
ExprKind::Loop(ref b, _, _) => {
@ -698,7 +730,8 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
},
ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id),
ExprKind::Continue(d) => {
let id = d.target_id
let id = d
.target_id
.expect("target id can only be missing in the presence of compilation errors");
if id == main_loop_id {
NeverLoopResult::MayContinueMainLoop
@ -706,9 +739,7 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
NeverLoopResult::AlwaysBreak
}
},
ExprKind::Break(_, _) => {
NeverLoopResult::AlwaysBreak
},
ExprKind::Break(_, _) => NeverLoopResult::AlwaysBreak,
ExprKind::Ret(ref e) => {
if let Some(ref e) = *e {
combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
@ -716,26 +747,26 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
NeverLoopResult::AlwaysBreak
}
},
ExprKind::Struct(_, _, None) |
ExprKind::Yield(_) |
ExprKind::Closure(_, _, _, _, _) |
ExprKind::InlineAsm(_, _, _) |
ExprKind::Path(_) |
ExprKind::Lit(_) => NeverLoopResult::Otherwise,
ExprKind::Struct(_, _, None)
| ExprKind::Yield(_)
| ExprKind::Closure(_, _, _, _, _)
| ExprKind::InlineAsm(_, _, _)
| ExprKind::Path(_)
| ExprKind::Lit(_) => NeverLoopResult::Otherwise,
}
}
fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_seq)
}
fn never_loop_expr_all<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_both)
}
fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr>>(e: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
e.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
}
@ -779,10 +810,7 @@ struct Offset {
impl Offset {
fn negative(s: String) -> Self {
Self {
value: s,
negate: true,
}
Self { value: s, negate: true }
}
fn positive(s: String) -> Self {
@ -842,19 +870,19 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var:
BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
_ => None,
},
ExprKind::Path(..) => if same_var(cx, idx, var) {
Some(Offset::positive("0".into()))
} else {
None
ExprKind::Path(..) => {
if same_var(cx, idx, var) {
Some(Offset::positive("0".into()))
} else {
None
}
},
_ => None,
};
offset.map(|o| {
FixedOffsetVar {
var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
offset: o,
}
offset.map(|o| FixedOffsetVar {
var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
offset: o,
})
} else {
None
@ -890,7 +918,10 @@ fn get_indexed_assignments<'a, 'tcx>(
var: ast::NodeId,
) -> Option<(FixedOffsetVar, FixedOffsetVar)> {
if let ExprKind::Assign(ref lhs, ref rhs) = e.node {
match (get_fixed_offset_var(cx, lhs, var), fetch_cloned_fixed_offset_var(cx, rhs, var)) {
match (
get_fixed_offset_var(cx, lhs, var),
fetch_cloned_fixed_offset_var(cx, rhs, var),
) {
(Some(offset_left), Some(offset_right)) => {
// Source and destination must be different
if offset_left.var_name == offset_right.var_name {
@ -908,9 +939,7 @@ fn get_indexed_assignments<'a, 'tcx>(
if let ExprKind::Block(ref b, _) = body.node {
let Block {
ref stmts,
ref expr,
..
ref stmts, ref expr, ..
} = **b;
stmts
@ -919,11 +948,7 @@ fn get_indexed_assignments<'a, 'tcx>(
StmtKind::Decl(..) => None,
StmtKind::Expr(ref e, _node_id) | StmtKind::Semi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
})
.chain(
expr.as_ref()
.into_iter()
.map(|e| Some(get_assignment(cx, &*e, var))),
)
.chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var))))
.filter_map(|op| op)
.collect::<Option<Vec<_>>>()
.unwrap_or_else(|| vec![])
@ -973,33 +998,35 @@ fn detect_manual_memcpy<'a, 'tcx>(
}
};
let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| if let Some(end) = *end {
if_chain! {
if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
if method.ident.name == "len";
if len_args.len() == 1;
if let Some(arg) = len_args.get(0);
if snippet(cx, arg.span, "??") == var_name;
then {
return if offset.negate {
format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
} else {
String::new()
};
let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| {
if let Some(end) = *end {
if_chain! {
if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
if method.ident.name == "len";
if len_args.len() == 1;
if let Some(arg) = len_args.get(0);
if snippet(cx, arg.span, "??") == var_name;
then {
return if offset.negate {
format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
} else {
String::new()
};
}
}
let end_str = match limits {
ast::RangeLimits::Closed => {
let end = sugg::Sugg::hir(cx, end, "<count>");
format!("{}", end + sugg::ONE)
},
ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
};
print_sum(&Offset::positive(end_str), &offset)
} else {
"..".into()
}
let end_str = match limits {
ast::RangeLimits::Closed => {
let end = sugg::Sugg::hir(cx, end, "<count>");
format!("{}", end + sugg::ONE)
},
ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
};
print_sum(&Offset::positive(end_str), &offset)
} else {
"..".into()
};
// The only statements in the for loops can be indexed assignments from
@ -1020,7 +1047,10 @@ fn detect_manual_memcpy<'a, 'tcx>(
format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit)
};
format!("{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit)
format!(
"{}.clone_from_slice(&{}[{}..{}])",
dst, src_var.var_name, src_offset, src_limit
)
})
.join("\n ");
@ -1166,7 +1196,10 @@ fn check_for_loop_range<'a, 'tcx>(
"consider using an iterator".to_string(),
vec![
(pat.span, format!("({}, <item>)", ident.name)),
(arg.span, format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2)),
(
arg.span,
format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
),
],
);
},
@ -1182,7 +1215,10 @@ fn check_for_loop_range<'a, 'tcx>(
cx,
NEEDLESS_RANGE_LOOP,
expr.span,
&format!("the loop variable `{}` is only used to index `{}`.", ident.name, indexed),
&format!(
"the loop variable `{}` is only used to index `{}`.",
ident.name, indexed
),
|db| {
multispan_sugg(
db,
@ -1213,12 +1249,7 @@ fn is_len_call(expr: &Expr, var: Name) -> bool {
false
}
fn is_end_eq_array_len(
cx: &LateContext<'_, '_>,
end: &Expr,
limits: ast::RangeLimits,
indexed_ty: Ty<'_>,
) -> bool {
fn is_end_eq_array_len(cx: &LateContext<'_, '_>, end: &Expr, limits: ast::RangeLimits, indexed_ty: Ty<'_>) -> bool {
if_chain! {
if let ExprKind::Lit(ref lit) = end.node;
if let ast::LitKind::Int(end_int, _) = lit.node;
@ -1252,14 +1283,14 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
// smaller value.
let ty = cx.tables.expr_ty(start);
let (sup, eq) = match (start_idx, end_idx) {
(
Constant::Int(start_idx),
Constant::Int(end_idx),
) => (match ty.sty {
ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
ty::Uint(_) => start_idx > end_idx,
_ => false,
}, start_idx == end_idx),
(Constant::Int(start_idx), Constant::Int(end_idx)) => (
match ty.sty {
ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
ty::Uint(_) => start_idx > end_idx,
_ => false,
},
start_idx == end_idx,
),
_ => (false, false),
};
@ -1310,11 +1341,7 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_name: &str) {
let mut applicability = Applicability::MachineApplicable;
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
let muta = if method_name == "iter_mut" {
"mut "
} else {
""
};
let muta = if method_name == "iter_mut" { "mut " } else { "" };
span_lint_and_sugg(
cx,
EXPLICIT_ITER_LOOP,
@ -1439,15 +1466,12 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
// For each candidate, check the parent block to see if
// it's initialized to zero at the start of the loop.
let map = &cx.tcx.hir;
let parent_scope = map.get_enclosing_scope(expr.id)
let parent_scope = map
.get_enclosing_scope(expr.id)
.and_then(|id| map.get_enclosing_scope(id));
if let Some(parent_id) = parent_scope {
if let Node::Block(block) = map.get(parent_id) {
for (id, _) in visitor
.states
.iter()
.filter(|&(_, v)| *v == VarState::IncrOnce)
{
for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) {
let mut visitor2 = InitializeVisitor {
cx,
end_expr: expr,
@ -1586,10 +1610,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_, '_>, arg: &Expr, body: &Expr)
..
}) = higher::range(cx, arg)
{
let mut_ids = vec![
check_for_mutability(cx, start),
check_for_mutability(cx, end),
];
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
if mut_ids[0].is_some() || mut_ids[1].is_some() {
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
mut_warn_with_span(cx, span_low);
@ -1631,7 +1652,11 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<NodeId
None
}
fn check_for_mutation(cx: &LateContext<'_, '_>, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) {
fn check_for_mutation(
cx: &LateContext<'_, '_>,
body: &Expr,
bound_ids: &[Option<NodeId>],
) -> (Option<Span>, Option<Span>) {
let mut delegate = MutatePairDelegate {
node_id_low: bound_ids[0],
node_id_high: bound_ids[1],
@ -1821,8 +1846,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
}
let old = self.prefer_mutable;
match expr.node {
ExprKind::AssignOp(_, ref lhs, ref rhs) |
ExprKind::Assign(ref lhs, ref rhs) => {
ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs) => {
self.prefer_mutable = true;
self.visit_expr(lhs);
self.prefer_mutable = false;
@ -1910,7 +1934,6 @@ impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> {
}
}
/// Return true if the type of expr is one that provides `IntoIterator` impls
/// for `&T` and `&mut T`, such as `Vec`.
#[rustfmt::skip]
@ -1998,9 +2021,9 @@ enum VarState {
/// Scan a for loop for variables that are incremented exactly once.
struct IncrementVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference
cx: &'a LateContext<'a, 'tcx>, // context reference
states: FxHashMap<NodeId, VarState>, // incremented variables
depth: u32, // depth of conditional expressions
depth: u32, // depth of conditional expressions
done: bool,
}
@ -2244,8 +2267,10 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
return;
}
match expr.node {
ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => if match_var(path, self.iterator) {
self.nesting = RuledOut;
ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => {
if match_var(path, self.iterator) {
self.nesting = RuledOut;
}
},
_ => walk_expr(self, expr),
}
@ -2299,7 +2324,7 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
let no_cond_variable_mutated = if let Some(used_mutably) = mutated_variables(expr, cx) {
used_in_condition.is_disjoint(&used_mutably)
} else {
return
return;
};
let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
if no_cond_variable_mutated && !mutable_static_in_cond {
@ -2307,7 +2332,8 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
cx,
WHILE_IMMUTABLE_CONDITION,
cond.span,
"Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.",
"Variable in the condition are not mutated in the loop body. \
This either leads to an infinite or to a never running loop.",
);
}
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
@ -15,7 +14,9 @@ use crate::rustc_errors::Applicability;
use crate::syntax::ast::Ident;
use crate::syntax::source_map::Span;
use crate::utils::paths;
use crate::utils::{in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
use crate::utils::{
in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
};
use if_chain::if_chain;
#[derive(Clone)]
@ -72,15 +73,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let closure_expr = remove_blocks(&closure_body.value);
then {
match closure_body.arguments[0].pat.node {
hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) = inner.node {
hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated, _, name, None
) = inner.node {
lint(cx, e.span, args[0].span, name, closure_expr);
},
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => match closure_expr.node {
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) if !cx.tables.expr_ty(inner).is_box() => lint(cx, e.span, args[0].span, name, inner),
hir::ExprKind::MethodCall(ref method, _, ref obj) => if method.ident.as_str() == "clone" && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
lint(cx, e.span, args[0].span, name, &obj[0]);
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => {
match closure_expr.node {
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
if !cx.tables.expr_ty(inner).is_box() => {
lint(cx, e.span, args[0].span, name, inner);
}
},
hir::ExprKind::MethodCall(ref method, _, ref obj) => {
if method.ident.as_str() == "clone"
&& match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
lint(cx, e.span, args[0].span, name, &obj[0]);
}
},
_ => {},
}
_ => {},
},
_ => {},
}
@ -99,7 +111,10 @@ fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, name: Ident, path:
replace,
"You are using an explicit closure for cloning elements",
"Consider calling the dedicated `cloned` method",
format!("{}.cloned()", snippet_with_applicability(cx, root, "..", &mut applicability)),
format!(
"{}.cloned()",
snippet_with_applicability(cx, root, "..", &mut applicability)
),
applicability,
)
}

View File

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span;
use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use crate::utils::paths;
use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use if_chain::if_chain;
#[derive(Clone)]
pub struct Pass;
@ -87,7 +86,6 @@ declare_clippy_lint! {
"using `result.map(f)`, where f is a function or closure that returns ()"
}
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN)
@ -127,8 +125,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
}
match expr.node {
hir::ExprKind::Call(_, _) |
hir::ExprKind::MethodCall(_, _, _) => {
hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _) => {
// Calls can't be reduced any more
Some(expr.span)
},
@ -155,7 +152,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
//
// We do not attempt to build a suggestion for those right now.
None
}
},
}
},
_ => None,
@ -189,15 +186,14 @@ fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String {
match &var_arg.node {
hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
_ => "_".to_string()
_ => "_".to_string(),
}
}
fn suggestion_msg(function_type: &str, map_type: &str) -> String {
format!(
"called `map(f)` on an {0} value where `f` is a unit {1}",
map_type,
function_type
map_type, function_type
)
}
@ -205,39 +201,39 @@ fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr
let var_arg = &map_args[0];
let fn_arg = &map_args[1];
let (map_type, variant, lint) =
if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
("Option", "Some", OPTION_MAP_UNIT_FN)
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
("Result", "Ok", RESULT_MAP_UNIT_FN)
} else {
return
};
let (map_type, variant, lint) = if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
("Option", "Some", OPTION_MAP_UNIT_FN)
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
("Result", "Ok", RESULT_MAP_UNIT_FN)
} else {
return;
};
if is_unit_function(cx, fn_arg) {
let msg = suggestion_msg("function", map_type);
let suggestion = format!("if let {0}({1}) = {2} {{ {3}(...) }}",
variant,
let_binding_name(cx, var_arg),
snippet(cx, var_arg.span, "_"),
snippet(cx, fn_arg.span, "_"));
let suggestion = format!(
"if let {0}({1}) = {2} {{ {3}(...) }}",
variant,
let_binding_name(cx, var_arg),
snippet(cx, var_arg.span, "_"),
snippet(cx, fn_arg.span, "_")
);
span_lint_and_then(cx, lint, expr.span, &msg, |db| {
db.span_suggestion_with_applicability(stmt.span,
"try this",
suggestion,
Applicability::Unspecified);
db.span_suggestion_with_applicability(stmt.span, "try this", suggestion, Applicability::Unspecified);
});
} else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
let msg = suggestion_msg("closure", map_type);
span_lint_and_then(cx, lint, expr.span, &msg, |db| {
if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
let suggestion = format!("if let {0}({1}) = {2} {{ {3} }}",
variant,
snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_"),
snippet(cx, reduced_expr_span, "_"));
let suggestion = format!(
"if let {0}({1}) = {2} {{ {3} }}",
variant,
snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_"),
snippet(cx, reduced_expr_span, "_")
);
db.span_suggestion_with_applicability(
stmt.span,
"try this",
@ -245,16 +241,13 @@ fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr
Applicability::MachineApplicable, // snippet
);
} else {
let suggestion = format!("if let {0}({1}) = {2} {{ ... }}",
variant,
snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_"));
db.span_suggestion_with_applicability(
stmt.span,
"try this",
suggestion,
Applicability::Unspecified,
let suggestion = format!(
"if let {0}({1}) = {2} {{ ... }}",
variant,
snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_")
);
db.span_suggestion_with_applicability(stmt.span, "try this", suggestion, Applicability::Unspecified);
}
});
}

View File

@ -7,23 +7,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::consts::{constant, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty::{self, Ty};
use std::cmp::Ordering;
use std::collections::Bound;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind;
use crate::syntax::source_map::Span;
use crate::utils::paths;
use crate::utils::{expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type,
multispan_sugg, remove_blocks, snippet, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
span_note_and_lint, walk_ptrs_ty};
use crate::utils::sugg::Sugg;
use crate::consts::{constant, Constant};
use crate::rustc_errors::Applicability;
use crate::utils::{
expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty,
};
use if_chain::if_chain;
use std::cmp::Ordering;
use std::collections::Bound;
/// **What it does:** Checks for matches with a single arm where an `if let`
/// will usually suffice.
@ -36,14 +36,14 @@ use crate::rustc_errors::Applicability;
/// ```rust
/// match x {
/// Some(ref foo) => bar(foo),
/// _ => ()
/// _ => (),
/// }
/// ```
declare_clippy_lint! {
pub SINGLE_MATCH,
style,
"a match statement with a single nontrivial arm (i.e. where the other arm \
is `_ => {}`) instead of `if let`"
pub SINGLE_MATCH,
style,
"a match statement with a single nontrivial arm (i.e. where the other arm \
is `_ => {}`) instead of `if let`"
}
/// **What it does:** Checks for matches with a two arms where an `if let` will
@ -61,10 +61,10 @@ declare_clippy_lint! {
/// }
/// ```
declare_clippy_lint! {
pub SINGLE_MATCH_ELSE,
pedantic,
"a match statement with a two arms where the second arm's pattern is a wildcard \
instead of `if let`"
pub SINGLE_MATCH_ELSE,
pedantic,
"a match statement with a two arms where the second arm's pattern is a wildcard \
instead of `if let`"
}
/// **What it does:** Checks for matches where all arms match a reference,
@ -131,8 +131,8 @@ declare_clippy_lint! {
/// ```rust
/// let x = 5;
/// match x {
/// 1 ... 10 => println!("1 ... 10"),
/// 5 ... 15 => println!("5 ... 15"),
/// 1...10 => println!("1 ... 10"),
/// 5...15 => println!("5 ... 15"),
/// _ => (),
/// }
/// ```
@ -152,7 +152,7 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// let x : Result(i32, &str) = Ok(3);
/// let x: Result(i32, &str) = Ok(3);
/// match x {
/// Ok(_) => println!("ok"),
/// Err(_) => panic!("err"),
@ -175,8 +175,8 @@ declare_clippy_lint! {
/// ```rust
/// let x: Option<()> = None;
/// let r: Option<&()> = match x {
/// None => None,
/// Some(ref v) => Some(v),
/// None => None,
/// Some(ref v) => Some(v),
/// };
/// ```
declare_clippy_lint! {
@ -243,19 +243,29 @@ fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
}
}
fn check_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
fn check_single_match_single_pattern(
cx: &LateContext<'_, '_>,
ex: &Expr,
arms: &[Arm],
expr: &Expr,
els: Option<&Expr>,
) {
if is_wild(&arms[1].pats[0]) {
report_single_match_single_pattern(cx, ex, arms, expr, els);
}
}
fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
let lint = if els.is_some() {
SINGLE_MATCH_ELSE
} else {
SINGLE_MATCH
};
let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
fn report_single_match_single_pattern(
cx: &LateContext<'_, '_>,
ex: &Expr,
arms: &[Arm],
expr: &Expr,
els: Option<&Expr>,
) {
let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
let els_str = els.map_or(String::new(), |els| {
format!(" else {}", expr_block(cx, els, None, ".."))
});
span_lint_and_sugg(
cx,
lint,
@ -274,7 +284,14 @@ fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms:
);
}
fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty<'_>, els: Option<&Expr>) {
fn check_single_match_opt_like(
cx: &LateContext<'_, '_>,
ex: &Expr,
arms: &[Arm],
expr: &Expr,
ty: Ty<'_>,
els: Option<&Expr>,
) {
// list of candidate Enums we know will never get any more members
let candidates = &[
(&paths::COW, "Borrowed"),
@ -466,9 +483,12 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
}
fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
if arms.len() == 2 &&
arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
arms[1].pats.len() == 1 && arms[1].guard.is_none() {
if arms.len() == 2
&& arms[0].pats.len() == 1
&& arms[0].guard.is_none()
&& arms[1].pats.len() == 1
&& arms[1].guard.is_none()
{
let arm_ref: Option<BindingAnnotation> = if is_none_arm(&arms[0]) {
is_ref_some_arm(&arms[1])
} else if is_none_arm(&arms[1]) {
@ -477,7 +497,11 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
None
};
if let Some(rb) = arm_ref {
let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" };
let suggestion = if rb == BindingAnnotation::Ref {
"as_ref"
} else {
"as_mut"
};
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
@ -485,7 +509,11 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
expr.span,
&format!("use {}() instead", suggestion),
"try this",
format!("{}.{}()", snippet_with_applicability(cx, ex.span, "_", &mut applicability), suggestion),
format!(
"{}.{}()",
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
suggestion
),
applicability,
)
}
@ -493,22 +521,18 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
}
/// Get all arms that are unbounded `PatRange`s.
fn all_ranges<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
arms: &'tcx [Arm],
) -> Vec<SpannedRange<Constant>> {
fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> {
arms.iter()
.flat_map(|arm| {
if let Arm {
ref pats,
guard: None,
..
ref pats, guard: None, ..
} = *arm
{
pats.iter()
} else {
[].iter()
}.filter_map(|pat| {
}
.filter_map(|pat| {
if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node {
let lhs = constant(cx, cx.tables, lhs)?.0;
let rhs = constant(cx, cx.tables, rhs)?.0;
@ -516,12 +540,18 @@ fn all_ranges<'a, 'tcx>(
RangeEnd::Included => Bound::Included(rhs),
RangeEnd::Excluded => Bound::Excluded(rhs),
};
return Some(SpannedRange { span: pat.span, node: (lhs, rhs) });
return Some(SpannedRange {
span: pat.span,
node: (lhs, rhs),
});
}
if let PatKind::Lit(ref value) = pat.node {
let value = constant(cx, cx.tables, value)?.0;
return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) });
return Some(SpannedRange {
span: pat.span,
node: (value.clone(), Bound::Included(value)),
});
}
None
@ -545,24 +575,15 @@ fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
ranges
.iter()
.filter_map(|range| match range.node {
(
Constant::Int(start),
Bound::Included(Constant::Int(end)),
) => Some(SpannedRange {
(Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Included(end)),
}),
(
Constant::Int(start),
Bound::Excluded(Constant::Int(end)),
) => Some(SpannedRange {
(Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Excluded(end)),
}),
(
Constant::Int(start),
Bound::Unbounded,
) => Some(SpannedRange {
(Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Unbounded),
}),
@ -608,7 +629,8 @@ fn is_ref_some_arm(arm: &Arm) -> Option<BindingAnnotation> {
}
fn has_only_ref_pats(arms: &[Arm]) -> bool {
let mapped = arms.iter()
let mapped = arms
.iter()
.flat_map(|a| &a.pats)
.map(|p| {
match p.node {
@ -682,8 +704,10 @@ where
for (a, b) in values.iter().zip(values.iter().skip(1)) {
match (a, b) {
(&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node {
return Some((ra, rb));
(&Kind::Start(_, ra), &Kind::End(_, rb)) => {
if ra.node != rb.node {
return Some((ra, rb));
}
},
(&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
_ => return Some((a.range(), b.range())),

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};

View File

@ -7,10 +7,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::{Expr, ExprKind};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};

View File

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::hir::def::Def;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
use crate::rustc::ty::{self, Ty, TyKind, Predicate};
use crate::rustc::ty::{self, Predicate, Ty, TyKind};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast;
@ -23,7 +22,7 @@ use crate::utils::{
get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty,
iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type,
match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet,
snippet_with_macro_callsite, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg, span_lint_and_then,
span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
};
use if_chain::if_chain;
@ -95,7 +94,9 @@ declare_clippy_lint! {
/// ```rust
/// struct X;
/// impl X {
/// fn add(&self, other: &X) -> X { .. }
/// fn add(&self, other: &X) -> X {
/// ..
/// }
/// }
/// ```
declare_clippy_lint! {
@ -124,14 +125,16 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// impl X {
/// fn as_str(self) -> &str { .. }
/// fn as_str(self) -> &str {
/// ..
/// }
/// }
/// ```
declare_clippy_lint! {
pub WRONG_SELF_CONVENTION,
style,
"defining a method named with an established prefix (like \"into_\") that takes \
`self` with the wrong convention"
pub WRONG_SELF_CONVENTION,
style,
"defining a method named with an established prefix (like \"into_\") that takes \
`self` with the wrong convention"
}
/// **What it does:** This is the same as
@ -146,14 +149,16 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// impl X {
/// pub fn as_str(self) -> &str { .. }
/// pub fn as_str(self) -> &str {
/// ..
/// }
/// }
/// ```
declare_clippy_lint! {
pub WRONG_PUB_SELF_CONVENTION,
restriction,
"defining a public method named with an established prefix (like \"into_\") that takes \
`self` with the wrong convention"
pub WRONG_PUB_SELF_CONVENTION,
restriction,
"defining a public method named with an established prefix (like \"into_\") that takes \
`self` with the wrong convention"
}
/// **What it does:** Checks for usage of `ok().expect(..)`.
@ -168,10 +173,10 @@ declare_clippy_lint! {
/// x.ok().expect("why did I do this again?")
/// ```
declare_clippy_lint! {
pub OK_EXPECT,
style,
"using `ok().expect()`, which gives worse error messages than \
calling `expect` directly on the Result"
pub OK_EXPECT,
style,
"using `ok().expect()`, which gives worse error messages than \
calling `expect` directly on the Result"
}
/// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`.
@ -186,10 +191,10 @@ declare_clippy_lint! {
/// x.map(|a| a + 1).unwrap_or(0)
/// ```
declare_clippy_lint! {
pub OPTION_MAP_UNWRAP_OR,
pedantic,
"using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
`map_or(a, f)`"
pub OPTION_MAP_UNWRAP_OR,
pedantic,
"using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
`map_or(a, f)`"
}
/// **What it does:** Checks for usage of `_.map(_).unwrap_or_else(_)`.
@ -204,10 +209,10 @@ declare_clippy_lint! {
/// x.map(|a| a + 1).unwrap_or_else(some_function)
/// ```
declare_clippy_lint! {
pub OPTION_MAP_UNWRAP_OR_ELSE,
pedantic,
"using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
`map_or_else(g, f)`"
pub OPTION_MAP_UNWRAP_OR_ELSE,
pedantic,
"using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
`map_or_else(g, f)`"
}
/// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
@ -222,10 +227,10 @@ declare_clippy_lint! {
/// x.map(|a| a + 1).unwrap_or_else(some_function)
/// ```
declare_clippy_lint! {
pub RESULT_MAP_UNWRAP_OR_ELSE,
pedantic,
"using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
`.ok().map_or_else(g, f)`"
pub RESULT_MAP_UNWRAP_OR_ELSE,
pedantic,
"using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
`.ok().map_or_else(g, f)`"
}
/// **What it does:** Checks for usage of `_.map_or(None, _)`.
@ -240,10 +245,10 @@ declare_clippy_lint! {
/// opt.map_or(None, |a| a + 1)
/// ```
declare_clippy_lint! {
pub OPTION_MAP_OR_NONE,
style,
"using `Option.map_or(None, f)`, which is more succinctly expressed as \
`and_then(f)`"
pub OPTION_MAP_OR_NONE,
style,
"using `Option.map_or(None, f)`, which is more succinctly expressed as \
`and_then(f)`"
}
/// **What it does:** Checks for usage of `_.filter(_).next()`.
@ -275,10 +280,10 @@ declare_clippy_lint! {
/// iter.map(|x| x.iter()).flatten()
/// ```
declare_clippy_lint! {
pub MAP_FLATTEN,
pedantic,
"using combinations of `flatten` and `map` which can usually be written as a \
single method call"
pub MAP_FLATTEN,
pedantic,
"using combinations of `flatten` and `map` which can usually be written as a \
single method call"
}
/// **What it does:** Checks for usage of `_.filter(_).map(_)`,
@ -295,10 +300,10 @@ declare_clippy_lint! {
/// iter.filter(|x| x == 0).map(|x| x * 2)
/// ```
declare_clippy_lint! {
pub FILTER_MAP,
pedantic,
"using combinations of `filter`, `map`, `filter_map` and `flat_map` which can \
usually be written as a single method call"
pub FILTER_MAP,
pedantic,
"using combinations of `filter`, `map`, `filter_map` and `flat_map` which can \
usually be written as a single method call"
}
/// **What it does:** Checks for an iterator search (such as `find()`,
@ -314,10 +319,10 @@ declare_clippy_lint! {
/// iter.find(|x| x == 0).is_some()
/// ```
declare_clippy_lint! {
pub SEARCH_IS_SOME,
complexity,
"using an iterator search followed by `is_some()`, which is more succinctly \
expressed as a call to `any()`"
pub SEARCH_IS_SOME,
complexity,
"using an iterator search followed by `is_some()`, which is more succinctly \
expressed as a call to `any()`"
}
/// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
@ -437,10 +442,10 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// fn main() {
/// let x = vec![1];
/// let y = &&x;
/// let z = y.clone();
/// println!("{:p} {:p}",*y, z); // prints out the same pointer
/// let x = vec![1];
/// let y = &&x;
/// let z = y.clone();
/// println!("{:p} {:p}", *y, z); // prints out the same pointer
/// }
/// ```
declare_clippy_lint! {
@ -480,10 +485,10 @@ declare_clippy_lint! {
/// **Example:**
/// `_.split("x")` could be `_.split('x')`
declare_clippy_lint! {
pub SINGLE_CHAR_PATTERN,
perf,
"using a single-character str where a char could be used, e.g. \
`_.split(\"x\")`"
pub SINGLE_CHAR_PATTERN,
perf,
"using a single-character str where a char could be used, e.g. \
`_.split(\"x\")`"
}
/// **What it does:** Checks for getting the inner pointer of a temporary
@ -635,13 +640,13 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// let s = [1,2,3,4,5];
/// let s2 : Vec<isize> = s[..].iter().cloned().collect();
/// let s = [1, 2, 3, 4, 5];
/// let s2: Vec<isize> = s[..].iter().cloned().collect();
/// ```
/// The better use would be:
/// ```rust
/// let s = [1,2,3,4,5];
/// let s2 : Vec<isize> = s.to_vec();
/// let s = [1, 2, 3, 4, 5];
/// let s2: Vec<isize> = s.to_vec();
/// ```
declare_clippy_lint! {
pub ITER_CLONED_COLLECT,
@ -676,12 +681,12 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// let x: &[i32] = &[1,2,3,4,5];
/// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x.as_ref());
/// ```
/// The correct use would be:
/// ```rust
/// let x: &[i32] = &[1,2,3,4,5];
/// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x);
/// ```
declare_clippy_lint! {
@ -690,7 +695,6 @@ declare_clippy_lint! {
"using `as_ref` where the types before and after the call are the same"
}
/// **What it does:** Checks for using `fold` when a more succinct alternative exists.
/// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
/// `sum` or `product`.
@ -714,7 +718,6 @@ declare_clippy_lint! {
"using `fold` when a more succinct alternative exists"
}
/// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
/// More specifically it checks if the closure provided is only performing one of the
/// filter or map operations and suggests the appropriate option.
@ -870,12 +873,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
["as_mut", ..] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]),
["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
_ => {}
_ => {},
}
match expr.node {
hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => {
lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
@ -886,9 +888,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
match self_ty.sty {
ty::Ref(_, ty, _) if ty.sty == ty::Str => for &(method, pos) in &PATTERN_METHODS {
if method_call.ident.name == method && args.len() > pos {
lint_single_char_pattern(cx, expr, &args[pos]);
ty::Ref(_, ty, _) if ty.sty == ty::Str => {
for &(method, pos) in &PATTERN_METHODS {
if method_call.ident.name == method && args.len() > pos {
lint_single_char_pattern(cx, expr, &args[pos]);
}
}
},
ty::Ref(..) if method_call.ident.name == "into_iter" => {
@ -897,7 +901,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
_ => (),
}
},
hir::ExprKind::Binary(op, ref lhs, ref rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
hir::ExprKind::Binary(op, ref lhs, ref rhs)
if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
{
let mut info = BinaryExprInfo {
expr,
chain: lhs,
@ -905,7 +911,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
eq: op.node == hir::BinOpKind::Eq,
};
lint_binary_expr_with_method_call(cx, &mut info);
},
}
_ => (),
}
}
@ -963,7 +969,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
.join(" or ")));
}
// Only check the first convention to match (CONVENTIONS should be listed from most to least specific)
// Only check the first convention to match (CONVENTIONS should be listed from most to least
// specific)
break;
}
}
@ -975,12 +982,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// walk the return type and check for Self (this does not check associated types)
for inner_type in ret_ty.walk() {
if same_tys(cx, ty, inner_type) { return; }
if same_tys(cx, ty, inner_type) {
return;
}
}
// if return type is impl trait, check the associated types
if let TyKind::Opaque(def_id, _) = ret_ty.sty {
// one of the associated types must be Self
for predicate in &cx.tcx.predicates_of(def_id).predicates {
match predicate {
@ -990,7 +998,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let associated_type_is_self_type = same_tys(cx, ty, associated_type);
// if the associated type is self, early return and do not trigger lint
if associated_type_is_self_type { return; }
if associated_type_is_self_type {
return;
}
},
(_, _) => {},
}
@ -998,10 +1008,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
if name == "new" && !same_tys(cx, ret_ty, ty) {
span_lint(cx,
NEW_RET_NO_SELF,
implitem.span,
"methods called `new` usually return `Self`");
span_lint(
cx,
NEW_RET_NO_SELF,
implitem.span,
"methods called `new` usually return `Self`",
);
}
}
}
@ -1043,7 +1055,10 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
span,
&format!("use of `{}` followed by a call to `{}`", name, path),
"try this",
format!("{}.unwrap_or_default()", snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)),
format!(
"{}.unwrap_or_default()",
snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
),
applicability,
);
return true;
@ -1123,12 +1138,28 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
hir::ExprKind::Call(ref fun, ref or_args) => {
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
check_general_case(cx, name, method_span, fun.span, &args[0], &args[1], or_has_args, expr.span);
check_general_case(
cx,
name,
method_span,
fun.span,
&args[0],
&args[1],
or_has_args,
expr.span,
);
}
},
hir::ExprKind::MethodCall(_, span, ref or_args) => {
check_general_case(cx, name, method_span, span, &args[0], &args[1], !or_args.is_empty(), expr.span)
},
hir::ExprKind::MethodCall(_, span, ref or_args) => check_general_case(
cx,
name,
method_span,
span,
&args[0],
&args[1],
!or_args.is_empty(),
expr.span,
),
_ => {},
}
}
@ -1137,12 +1168,13 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
/// Checks for the `EXPECT_FUN_CALL` lint.
fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
fn extract_format_args(arg: &hir::Expr) -> Option<&hir::HirVec<hir::Expr>> {
let arg = match &arg.node {
hir::ExprKind::AddrOf(_, expr)=> expr,
let arg = match &arg.node {
hir::ExprKind::AddrOf(_, expr) => expr,
hir::ExprKind::MethodCall(method_name, _, args)
if method_name.ident.name == "as_str" ||
method_name.ident.name == "as_ref"
=> &args[0],
if method_name.ident.name == "as_str" || method_name.ident.name == "as_ref" =>
{
&args[0]
},
_ => arg,
};
@ -1165,7 +1197,8 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node {
if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node {
if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node {
return snippet_with_applicability(cx, format_arg_expr_tup[0].span, "..", applicability).into_owned();
return snippet_with_applicability(cx, format_arg_expr_tup[0].span, "..", applicability)
.into_owned();
}
}
};
@ -1212,7 +1245,11 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
return;
}
let closure = if match_type(cx, self_type, &paths::OPTION) { "||" } else { "|_|" };
let closure = if match_type(cx, self_type, &paths::OPTION) {
"||"
} else {
"|_|"
};
let span_replace_word = method_span.with_hi(span.hi());
if let Some(format_args) = extract_format_args(arg) {
@ -1272,28 +1309,30 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
expr.span,
"using `clone` on a double-reference; \
this will copy the reference instead of cloning the inner type",
|db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
let mut ty = innermost;
let mut n = 0;
while let ty::Ref(_, inner, _) = ty.sty {
ty = inner;
n += 1;
|db| {
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
let mut ty = innermost;
let mut n = 0;
while let ty::Ref(_, inner, _) = ty.sty {
ty = inner;
n += 1;
}
let refs: String = iter::repeat('&').take(n + 1).collect();
let derefs: String = iter::repeat('*').take(n).collect();
let explicit = format!("{}{}::clone({})", refs, ty, snip);
db.span_suggestion_with_applicability(
expr.span,
"try dereferencing it",
format!("{}({}{}).clone()", refs, derefs, snip.deref()),
Applicability::MaybeIncorrect,
);
db.span_suggestion_with_applicability(
expr.span,
"or try being explicit about what type to clone",
explicit,
Applicability::MaybeIncorrect,
);
}
let refs: String = iter::repeat('&').take(n + 1).collect();
let derefs: String = iter::repeat('*').take(n).collect();
let explicit = format!("{}{}::clone({})", refs, ty, snip);
db.span_suggestion_with_applicability(
expr.span,
"try dereferencing it",
format!("{}({}{}).clone()", refs, derefs, snip.deref()),
Applicability::MaybeIncorrect,
);
db.span_suggestion_with_applicability(
expr.span,
"or try being explicit about what type to clone",
explicit,
Applicability::MaybeIncorrect,
);
},
);
return; // don't report clone_on_copy
@ -1312,7 +1351,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
// (*x).func() is useless, x.clone().func() can work in case func borrows mutably
hir::ExprKind::MethodCall(..) => return,
_ => {},
}
},
hir::Node::Stmt(stmt) => {
if let hir::StmtKind::Decl(ref decl, _) = stmt.node {
if let hir::DeclKind::Local(ref loc) = decl.node {
@ -1334,12 +1373,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
}
span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| {
if let Some((text, snip)) = snip {
db.span_suggestion_with_applicability(
expr.span,
text,
snip,
Applicability::Unspecified,
);
db.span_suggestion_with_applicability(expr.span, text, snip, Applicability::Unspecified);
}
});
}
@ -1365,13 +1399,17 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::
expr.span,
"using '.clone()' on a ref-counted pointer",
"try this",
format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet(cx, arg.span, "_")),
format!(
"{}::<{}>::clone(&{})",
caller_type,
subst.type_at(0),
snippet(cx, arg.span, "_")
),
Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
);
}
}
fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
let arg = &args[1];
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
@ -1451,8 +1489,8 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
fold_args: &[hir::Expr],
op: hir::BinOpKind,
replacement_method_name: &str,
replacement_has_args: bool) {
replacement_has_args: bool,
) {
if_chain! {
// Extract the body of the closure passed to fold
if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].node;
@ -1509,29 +1547,21 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
return;
}
assert!(fold_args.len() == 3,
"Expected fold_args to have three entries - the receiver, the initial value and the closure");
assert!(
fold_args.len() == 3,
"Expected fold_args to have three entries - the receiver, the initial value and the closure"
);
// Check if the first argument to .fold is a suitable literal
match fold_args[1].node {
hir::ExprKind::Lit(ref lit) => {
match lit.node {
ast::LitKind::Bool(false) => check_fold_with_op(
cx, fold_args, hir::BinOpKind::Or, "any", true
),
ast::LitKind::Bool(true) => check_fold_with_op(
cx, fold_args, hir::BinOpKind::And, "all", true
),
ast::LitKind::Int(0, _) => check_fold_with_op(
cx, fold_args, hir::BinOpKind::Add, "sum", false
),
ast::LitKind::Int(1, _) => check_fold_with_op(
cx, fold_args, hir::BinOpKind::Mul, "product", false
),
_ => return
}
}
_ => return
hir::ExprKind::Lit(ref lit) => match lit.node {
ast::LitKind::Bool(false) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Or, "any", true),
ast::LitKind::Bool(true) => check_fold_with_op(cx, fold_args, hir::BinOpKind::And, "all", true),
ast::LitKind::Int(0, _) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Add, "sum", false),
ast::LitKind::Int(1, _) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Mul, "product", false),
_ => return,
},
_ => return,
};
}
@ -1553,8 +1583,7 @@ fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::E
expr.span,
&format!(
"called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
mut_str,
caller_type
mut_str, caller_type
),
);
}
@ -1590,15 +1619,20 @@ fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::
};
let mut_str = if is_mut { "_mut" } else { "" };
let borrow_str = if !needs_ref { "" } else if is_mut { "&mut " } else { "&" };
let borrow_str = if !needs_ref {
""
} else if is_mut {
"&mut "
} else {
"&"
};
span_lint_and_sugg(
cx,
GET_UNWRAP,
expr.span,
&format!(
"called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
mut_str,
caller_type
mut_str, caller_type
),
"try this",
format!(
@ -1645,10 +1679,12 @@ fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Op
match ty.sty {
ty::Slice(_) => sugg::Sugg::hir_opt(cx, expr),
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
ty::Ref(_, inner, _) => if may_slice(cx, inner) {
sugg::Sugg::hir_opt(cx, expr)
} else {
None
ty::Ref(_, inner, _) => {
if may_slice(cx, inner) {
sugg::Sugg::hir_opt(cx, expr)
} else {
None
}
},
_ => None,
}
@ -1676,8 +1712,7 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::E
"used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \
using expect() to provide a better panic \
message",
kind,
none_value
kind, none_value
),
);
}
@ -1711,11 +1746,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
// lint message
// comparing the snippet from source to raw text ("None") below is safe
// because we already have checked the type.
let arg = if unwrap_snippet == "None" {
"None"
} else {
"a"
};
let arg = if unwrap_snippet == "None" { "None" } else { "a" };
let suggest = if unwrap_snippet == "None" {
"and_then(f)"
} else {
@ -1724,8 +1755,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
let msg = &format!(
"called `map(f).unwrap_or({})` on an Option value. \
This can be done more directly by calling `{}` instead",
arg,
suggest
arg, suggest
);
// lint, with note if neither arg is > 1 line and both map() and
// unwrap_or() have the same span
@ -1739,9 +1769,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
};
let note = format!(
"replace `map({}).unwrap_or({})` with `{}`",
map_snippet,
unwrap_snippet,
suggest
map_snippet, unwrap_snippet, suggest
);
span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, &note);
} else if same_span && multiline {
@ -1751,11 +1779,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
}
/// lint use of `map().flatten()` for `Iterators`
fn lint_map_flatten<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
map_args: &'tcx [hir::Expr],
) {
fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr]) {
// lint if caller of `.map().flatten()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `map(..).flatten()` on an `Iterator`. \
@ -1971,7 +1995,10 @@ fn lint_search_is_some<'a, 'tcx>(
expr.span,
&msg,
expr.span,
&format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet),
&format!(
"replace `{0}({1}).is_some()` with `any({1})`",
search_method, search_snippet
),
);
} else {
span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
@ -1998,7 +2025,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut Binary
return;
}
}
}
};
}
lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
@ -2163,7 +2190,10 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_re
}
}
fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: ty::Ty<'_>) -> Option<(&'static Lint, &'static str, &'static str)> {
fn ty_has_iter_method(
cx: &LateContext<'_, '_>,
self_ref_ty: ty::Ty<'_>,
) -> Option<(&'static Lint, &'static str, &'static str)> {
// FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
// exists and has the desired signature. Unfortunately FnCtxt is not exported
// so we can't use its `lookup_method` method.
@ -2201,7 +2231,7 @@ fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: ty::Ty<'_>) -> Opti
for (lint, path) in &INTO_ITER_COLLECTIONS {
if match_def_path(cx.tcx, def_id, path) {
return Some((lint, path.last().unwrap(), method_name))
return Some((lint, path.last().unwrap(), method_name));
}
}
None
@ -2218,8 +2248,7 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: ty::T
method_span,
&format!(
"this .into_iter() call is equivalent to .{}() and will not move the {}",
method_name,
kind,
method_name, kind,
),
"call directly",
method_name.to_string(),
@ -2228,7 +2257,6 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: ty::T
}
}
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
if let ty::Adt(_, substs) = ty.sty {
@ -2321,7 +2349,6 @@ const PATTERN_METHODS: [(&str, usize); 17] = [
("trim_right_matches", 1),
];
#[derive(Clone, Copy, PartialEq, Debug)]
enum SelfKind {
Value,
@ -2397,31 +2424,36 @@ fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Gener
single_segment_ty(ty).map_or(false, |seg| {
generics.params.iter().any(|param| match param.kind {
hir::GenericParamKind::Type { .. } => {
param.name.ident().name == seg.ident.name && param.bounds.iter().any(|bound| {
if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
let path = &ptr.trait_ref.path;
match_path(path, name) && path.segments.last().map_or(false, |s| {
if let Some(ref params) = s.args {
if params.parenthesized {
false
} else {
// FIXME(flip1995): messy, improve if there is a better option
// in the compiler
let types: Vec<_> = params.args.iter().filter_map(|arg| match arg {
hir::GenericArg::Type(ty) => Some(ty),
_ => None,
}).collect();
types.len() == 1
&& (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
}
} else {
false
}
})
} else {
false
}
})
param.name.ident().name == seg.ident.name
&& param.bounds.iter().any(|bound| {
if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
let path = &ptr.trait_ref.path;
match_path(path, name)
&& path.segments.last().map_or(false, |s| {
if let Some(ref params) = s.args {
if params.parenthesized {
false
} else {
// FIXME(flip1995): messy, improve if there is a better option
// in the compiler
let types: Vec<_> = params
.args
.iter()
.filter_map(|arg| match arg {
hir::GenericArg::Type(ty) => Some(ty),
_ => None,
})
.collect();
types.len() == 1 && (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
}
} else {
false
}
})
} else {
false
}
})
},
_ => false,
})

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::hir::def::Def;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::consts::{constant_simple, Constant};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
use std::cmp::Ordering;
/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are

View File

@ -7,23 +7,24 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::reexport::*;
use matches::matches;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::syntax::source_map::{ExpnFormat, Span};
use crate::utils::{get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal,
iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint,
span_lint_and_then, walk_ptrs_ty, SpanlessEq};
use crate::utils::sugg::Sugg;
use crate::syntax::ast::LitKind;
use crate::consts::{constant, Constant};
use crate::reexport::*;
use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind;
use crate::syntax::source_map::{ExpnFormat, Span};
use crate::utils::sugg::Sugg;
use crate::utils::{
get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, iter_input_pats,
last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty,
SpanlessEq,
};
use if_chain::if_chain;
use matches::matches;
/// **What it does:** Checks for function arguments and let bindings denoted as
/// `ref`.
@ -43,7 +44,9 @@ use crate::rustc_errors::Applicability;
///
/// **Example:**
/// ```rust
/// fn foo(ref x: u8) -> bool { .. }
/// fn foo(ref x: u8) -> bool {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub TOPLEVEL_REF_ARG,
@ -139,7 +142,7 @@ declare_clippy_lint! {
/// ```rust
/// match v {
/// Some(x) => (),
/// y @ _ => (), // easier written as `y`,
/// y @ _ => (), // easier written as `y`,
/// }
/// ```
declare_clippy_lint! {
@ -182,7 +185,7 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// f() && g(); // We should write `if f() { g(); }`.
/// f() && g(); // We should write `if f() { g(); }`.
/// ```
declare_clippy_lint! {
pub SHORT_CIRCUIT_STATEMENT,
@ -266,8 +269,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
for arg in iter_input_pats(decl, body) {
match arg.pat.node {
PatKind::Binding(BindingAnnotation::Ref, _, _, _) |
PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => {
PatKind::Binding(BindingAnnotation::Ref, _, _, _)
| PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => {
span_lint(
cx,
TOPLEVEL_REF_ARG,
@ -372,7 +375,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
if let Some(name) = get_item_name(cx, expr) {
let name = name.as_str();
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_")
if name == "eq"
|| name == "ne"
|| name == "is_nan"
|| name.starts_with("eq_")
|| name.ends_with("_eq")
{
return;
@ -451,7 +457,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
cx,
REDUNDANT_PATTERN,
pat.span,
&format!("the `{} @ _` pattern can be written as just `{}`", ident.name, ident.name),
&format!(
"the `{} @ _` pattern can be written as just `{}`",
ident.name, ident.name
),
);
}
}
@ -467,7 +476,7 @@ fn check_nan(cx: &LateContext<'_, '_>, path: &Path, expr: &Expr) {
CMP_NAN,
expr.span,
"doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead",
);
);
}
}
}
@ -477,7 +486,7 @@ fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) ->
if let Some((_, res)) = constant(cx, cx.tables, expr) {
res
} else {
false
false
}
}
@ -502,14 +511,16 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
return;
}
},
ExprKind::Call(ref path, ref v) if v.len() == 1 => if let ExprKind::Path(ref path) = path.node {
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
(cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
ExprKind::Call(ref path, ref v) if v.len() == 1 => {
if let ExprKind::Path(ref path) = path.node {
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
(cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
} else {
return;
}
} else {
return;
}
} else {
return;
},
_ => return,
};
@ -520,18 +531,15 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
None => return,
};
let deref_arg_impl_partial_eq_other = arg_ty
.builtin_deref(true)
.map_or(false, |tam| implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()]));
let arg_impl_partial_eq_deref_other = other_ty
.builtin_deref(true)
.map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()]));
let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
});
let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
});
let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
if !deref_arg_impl_partial_eq_other
&& !arg_impl_partial_eq_deref_other
&& !arg_impl_partial_eq_other
{
if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
return;
}

View File

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext, in_external_macro};
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashMap;
use if_chain::if_chain;
use std::char;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*;
use crate::syntax::source_map::Span;
use crate::syntax::visit::{FnKind, Visitor, walk_expr};
use crate::syntax::visit::{walk_expr, FnKind, Visitor};
use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then};
use crate::rustc_errors::Applicability;
use if_chain::if_chain;
use std::char;
/// **What it does:** Checks for structure field patterns bound to wildcards.
///
@ -206,9 +205,7 @@ struct ReturnVisitor {
impl ReturnVisitor {
fn new() -> Self {
Self {
found_return: false,
}
Self { found_return: false }
}
}
@ -244,7 +241,8 @@ impl EarlyLintPass for MiscEarly {
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat, _: &mut bool) {
if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
let mut wilds = 0;
let type_name = npat.segments
let type_name = npat
.segments
.last()
.expect("A path must have at least one segment")
.ident
@ -271,8 +269,10 @@ impl EarlyLintPass for MiscEarly {
for field in pfields {
match field.node.pat.node {
PatKind::Wild => {},
_ => if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
normal.push(n);
_ => {
if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
normal.push(n);
}
},
}
}
@ -334,36 +334,42 @@ impl EarlyLintPass for MiscEarly {
return;
}
match expr.node {
ExprKind::Call(ref paren, _) => if let ExprKind::Paren(ref closure) = paren.node {
if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
let mut visitor = ReturnVisitor::new();
visitor.visit_expr(block);
if !visitor.found_return {
span_lint_and_then(
cx,
REDUNDANT_CLOSURE_CALL,
expr.span,
"Try not to call a closure in the expression where it is declared.",
|db| if decl.inputs.is_empty() {
let hint = snippet(cx, block.span, "..").into_owned();
db.span_suggestion_with_applicability(
expr.span,
"Try doing something like: ",
hint,
Applicability::MachineApplicable, // snippet
);
},
);
ExprKind::Call(ref paren, _) => {
if let ExprKind::Paren(ref closure) = paren.node {
if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
let mut visitor = ReturnVisitor::new();
visitor.visit_expr(block);
if !visitor.found_return {
span_lint_and_then(
cx,
REDUNDANT_CLOSURE_CALL,
expr.span,
"Try not to call a closure in the expression where it is declared.",
|db| {
if decl.inputs.is_empty() {
let hint = snippet(cx, block.span, "..").into_owned();
db.span_suggestion_with_applicability(
expr.span,
"Try doing something like: ",
hint,
Applicability::MachineApplicable, // snippet
);
}
},
);
}
}
}
},
ExprKind::Unary(UnOp::Neg, ref inner) => if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
ExprKind::Unary(UnOp::Neg, ref inner) => {
if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
}
},
ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
_ => (),

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This file incorporates work covered by the following copyright and
// permission notice:
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
@ -29,13 +28,13 @@
//
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::syntax::attr;
use crate::syntax::source_map::Span;
use crate::utils::{span_lint, in_macro};
use crate::utils::{in_macro, span_lint};
/// **What it does:** Warns if there is missing doc for any documentable item
/// (public or private).
@ -72,12 +71,16 @@ impl MissingDoc {
}
fn doc_hidden(&self) -> bool {
*self.doc_hidden_stack
.last()
.expect("empty doc_hidden_stack")
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
fn check_missing_docs_attrs(&self, cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_, '_>,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str,
) {
// If we're building a test harness, then warning about
// documentation is probably not really relevant right now.
if cx.sess().opts.test {
@ -93,9 +96,7 @@ impl MissingDoc {
return;
}
let has_doc = attrs
.iter()
.any(|a| a.is_value_str() && a.name() == "doc");
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc {
span_lint(
cx,
@ -115,12 +116,14 @@ impl LintPass for MissingDoc {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"),
}
});
let doc_hidden = self.doc_hidden()
|| attrs.iter().any(|attr| {
attr.check_name("doc")
&& match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"),
}
});
self.doc_hidden_stack.push(doc_hidden);
}
@ -156,10 +159,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
hir::ItemKind::Ty(..) => "a type alias",
hir::ItemKind::Union(..) => "a union",
hir::ItemKind::Existential(..) => "an existential type",
hir::ItemKind::ExternCrate(..) |
hir::ItemKind::ForeignMod(..) |
hir::ItemKind::Impl(..) |
hir::ItemKind::Use(..) => return,
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::ForeignMod(..)
| hir::ItemKind::Impl(..)
| hir::ItemKind::Use(..) => return,
};
self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc);
@ -180,8 +183,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
let def_id = cx.tcx.hir.local_def_id(impl_item.id);
match cx.tcx.associated_item(def_id).container {
ty::TraitContainer(_) => return,
ty::ImplContainer(cid) => if cx.tcx.impl_trait_ref(cid).is_some() {
return;
ty::ImplContainer(cid) => {
if cx.tcx.impl_trait_ref(cid).is_some() {
return;
}
},
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
@ -33,9 +32,9 @@ use crate::utils::span_lint;
/// crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
/// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
/// might intend for most of the methods in their public API to be able to be inlined across
/// crates even when LTO is disabled. For these types of crates, enabling this lint might make sense.
/// It allows the crate to require all exported methods to be `#[inline]` by default, and then opt
/// out for specific methods where this might not make sense.
/// crates even when LTO is disabled. For these types of crates, enabling this lint might make
/// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
/// then opt out for specific methods where this might not make sense.
///
/// **Known problems:** None.
///
@ -79,11 +78,8 @@ declare_clippy_lint! {
pub struct MissingInline;
fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
let has_inline = attrs
.iter()
.any(|a| a.name() == "inline" );
fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
let has_inline = attrs.iter().any(|a| a.name() == "inline");
if !has_inline {
span_lint(
cx,
@ -97,11 +93,9 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
fn is_executable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>) -> bool {
use crate::rustc::session::config::CrateType;
cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| {
match t {
CrateType::Executable => true,
_ => false,
}
cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t {
CrateType::Executable => true,
_ => false,
})
}
@ -125,47 +119,44 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
let desc = "a function";
check_missing_inline_attrs(cx, &it.attrs, it.span, desc);
},
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics,
ref _bounds, ref trait_items) => {
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, ref trait_items) => {
// note: we need to check if the trait is exported so we can't use
// `LateLintPass::check_trait_item` here.
for tit in trait_items {
let tit_ = cx.tcx.hir.trait_item(tit.id);
match tit_.node {
hir::TraitItemKind::Const(..) |
hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Method(..) => {
if tit.defaultness.has_value() {
// trait method with default body needs inline in case
// an impl is not provided
let desc = "a default trait method";
let item = cx.tcx.hir.expect_trait_item(tit.id.node_id);
check_missing_inline_attrs(cx, &item.attrs,
item.span, desc);
check_missing_inline_attrs(cx, &item.attrs, item.span, desc);
}
},
}
}
}
hir::ItemKind::Const(..) |
hir::ItemKind::Enum(..) |
hir::ItemKind::Mod(..) |
hir::ItemKind::Static(..) |
hir::ItemKind::Struct(..) |
hir::ItemKind::TraitAlias(..) |
hir::ItemKind::GlobalAsm(..) |
hir::ItemKind::Ty(..) |
hir::ItemKind::Union(..) |
hir::ItemKind::Existential(..) |
hir::ItemKind::ExternCrate(..) |
hir::ItemKind::ForeignMod(..) |
hir::ItemKind::Impl(..) |
hir::ItemKind::Use(..) => {},
},
hir::ItemKind::Const(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::TraitAlias(..)
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::Ty(..)
| hir::ItemKind::Union(..)
| hir::ItemKind::Existential(..)
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::ForeignMod(..)
| hir::ItemKind::Impl(..)
| hir::ItemKind::Use(..) => {},
};
}
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) {
use crate::rustc::ty::{TraitContainer, ImplContainer};
use crate::rustc::ty::{ImplContainer, TraitContainer};
if is_executable(cx) {
return;
}
@ -177,9 +168,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
let desc = match impl_item.node {
hir::ImplItemKind::Method(..) => "a method",
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Type(_) |
hir::ImplItemKind::Existential(_) => return,
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) | hir::ImplItemKind::Existential(_) => return,
};
let def_id = cx.tcx.hir.local_def_id(impl_item.id);

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir;
use crate::rustc::hir::intravisit;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{higher, span_lint};
/// **What it does:** Checks for instances of `mut mut` references.
@ -81,12 +80,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
expr.span,
"generally you want to avoid `&mut &mut _` if possible",
);
} else if let ty::Ref(
_,
_,
hir::MutMutable,
) = self.cx.tables.expr_ty(e).sty
{
} else if let ty::Ref(_, _, hir::MutMutable) = self.cx.tables.expr_ty(e).sty {
span_lint(
self.cx,
MUT_MUT,
@ -109,8 +103,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
if let hir::TyKind::Rptr(
_,
hir::MutTy {
mutbl: hir::MutMutable,
..
mutbl: hir::MutMutable, ..
},
) = pty.node
{

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty::{self, Ty};
use crate::rustc::ty::subst::Subst;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::subst::Subst;
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::span_lint;
/// **What it does:** Detects giving a mutable reference to a function that only
@ -28,13 +27,12 @@ use crate::utils::span_lint;
/// my_vec.push(&mut value)
/// ```
declare_clippy_lint! {
pub UNNECESSARY_MUT_PASSED,
style,
"an argument passed as a mutable reference although the callee only demands an \
immutable reference"
pub UNNECESSARY_MUT_PASSED,
style,
"an argument passed as a mutable reference although the callee only demands an \
immutable reference"
}
#[derive(Copy, Clone)]
pub struct UnnecessaryMutPassed;
@ -47,13 +45,15 @@ impl LintPass for UnnecessaryMutPassed {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
match e.node {
ExprKind::Call(ref fn_expr, ref arguments) => if let ExprKind::Path(ref path) = fn_expr.node {
check_arguments(
cx,
arguments,
cx.tables.expr_ty(fn_expr),
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
);
ExprKind::Call(ref fn_expr, ref arguments) => {
if let ExprKind::Path(ref path) = fn_expr.node {
check_arguments(
cx,
arguments,
cx.tables.expr_ty(fn_expr),
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
);
}
},
ExprKind::MethodCall(ref path, _, ref arguments) => {
let def_id = cx.tables.type_dependent_defs()[e.hir_id].def_id();
@ -72,21 +72,18 @@ fn check_arguments<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arguments: &[Expr], typ
let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
match parameter.sty {
ty::Ref(
_,
_,
MutImmutable,
) |
ty::RawPtr(ty::TypeAndMut {
mutbl: MutImmutable,
..
}) => if let ExprKind::AddrOf(MutMutable, _) = argument.node {
span_lint(
cx,
UNNECESSARY_MUT_PASSED,
argument.span,
&format!("The function/method `{}` doesn't need a mutable reference", name),
);
ty::Ref(_, _, MutImmutable)
| ty::RawPtr(ty::TypeAndMut {
mutbl: MutImmutable, ..
}) => {
if let ExprKind::AddrOf(MutMutable, _) = argument.node {
span_lint(
cx,
UNNECESSARY_MUT_PASSED,
argument.span,
&format!("The function/method `{}` doesn't need a mutable reference", name),
);
}
},
_ => (),
}

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for uses of mutex where an atomic value could be used
//!
//! This lint is **warn** by default
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty::{self, Ty};
use crate::rustc::hir::Expr;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{match_type, paths, span_lint};

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for needless boolean results of if-else expressions
//!
//! This lint is **warn** by default
@ -34,13 +33,17 @@ use crate::utils::{in_macro, snippet_with_applicability, span_lint, span_lint_an
///
/// **Example:**
/// ```rust
/// if x { false } else { true }
/// if x {
/// false
/// } else {
/// true
/// }
/// ```
declare_clippy_lint! {
pub NEEDLESS_BOOL,
complexity,
"if-statements with plain booleans in the then- and else-clause, e.g. \
`if p { true } else { false }`"
pub NEEDLESS_BOOL,
complexity,
"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` (or vice
@ -52,7 +55,7 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// if x == true { } // could be `if x { }`
/// if x == true {} // could be `if x { }`
/// ```
declare_clippy_lint! {
pub BOOL_COMPARISON,
@ -142,7 +145,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
return;
}
if let ExprKind::Binary(Spanned { node: BinOpKind::Eq, .. }, ref left_side, ref right_side) = e.node {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Eq, ..
},
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) => {
@ -208,14 +218,16 @@ enum Expression {
fn fetch_bool_block(block: &Block) -> Expression {
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 ExprKind::Ret(_) = e.node {
fetch_bool_expr(&**e)
(&[ref e], None) => {
if let StmtKind::Semi(ref e, _) = e.node {
if let ExprKind::Ret(_) = e.node {
fetch_bool_expr(&**e)
} else {
Expression::Other
}
} else {
Expression::Other
}
} else {
Expression::Other
},
_ => Expression::Other,
}
@ -224,10 +236,12 @@ fn fetch_bool_block(block: &Block) -> Expression {
fn fetch_bool_expr(expr: &Expr) -> Expression {
match expr.node {
ExprKind::Block(ref block, _) => fetch_bool_block(block),
ExprKind::Lit(ref lit_ptr) => if let LitKind::Bool(value) = lit_ptr.node {
Expression::Bool(value)
} else {
Expression::Other
ExprKind::Lit(ref lit_ptr) => {
if let LitKind::Bool(value) = lit_ptr.node {
Expression::Bool(value)
} else {
Expression::Other
}
},
ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) {
Expression::Bool(value) => Expression::RetBool(value),

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for needless address of operations (`&`)
//!
//! This lint is **warn** by default
@ -18,8 +17,8 @@ use crate::rustc::ty;
use crate::rustc::ty::adjustment::{Adjust, Adjustment};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
use crate::syntax::ast::NodeId;
use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for address of operations (`&`) that are going to
@ -60,11 +59,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
if let ty::Ref(..) = cx.tables.expr_ty(inner).sty {
for adj3 in cx.tables.expr_adjustments(e).windows(3) {
if let [Adjustment {
kind: Adjust::Deref(_),
..
kind: Adjust::Deref(_), ..
}, Adjustment {
kind: Adjust::Deref(_),
..
kind: Adjust::Deref(_), ..
}, Adjustment {
kind: Adjust::Borrow(_),
..

View File

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for useless borrowed references.
//!
//! This lint is **warn** by default
use crate::rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind};
use crate::utils::{in_macro, snippet, span_lint_and_then};
use crate::rustc_errors::Applicability;
use crate::utils::{in_macro, snippet, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for useless borrowed references.
///
@ -48,8 +47,8 @@ use crate::rustc_errors::Applicability;
///
/// **Example:**
/// ```rust
/// let mut v = Vec::<String>::new();
/// let _ = v.iter_mut().filter(|&ref a| a.is_empty());
/// let mut v = Vec::<String>::new();
/// let _ = v.iter_mut().filter(|&ref a| a.is_empty());
/// ```
/// This closure takes a reference on something that has been matched as a
/// reference and
@ -89,7 +88,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
|db| {
let hint = snippet(cx, spanned_name.span, "..").into_owned();
db.span_suggestion_with_applicability(
pat.span,
pat.span,
"try removing the `&ref` part and just keep",
hint,
Applicability::MachineApplicable, // snippet

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for continue statements in loops that are redundant.
//!
//! For example, the lint would catch
@ -181,7 +180,6 @@ impl EarlyLintPass for NeedlessContinue {
/// - The expression is a `continue` node.
/// - The expression node is a block with the first statement being a
/// `continue`.
///
fn needless_continue_in_else(else_expr: &ast::Expr) -> bool {
match else_expr.node {
ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block),
@ -192,10 +190,12 @@ fn needless_continue_in_else(else_expr: &ast::Expr) -> bool {
fn is_first_block_stmt_continue(block: &ast::Block) -> bool {
block.stmts.get(0).map_or(false, |stmt| match stmt.node {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => if let ast::ExprKind::Continue(_) = e.node {
true
} else {
false
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
if let ast::ExprKind::Continue(_) = e.node {
true
} else {
false
}
},
_ => false,
})
@ -208,10 +208,10 @@ where
F: FnMut(&ast::Block),
{
match expr.node {
ast::ExprKind::While(_, ref loop_block, _) |
ast::ExprKind::WhileLet(_, _, ref loop_block, _) |
ast::ExprKind::ForLoop(_, _, ref loop_block, _) |
ast::ExprKind::Loop(ref loop_block, _) => func(loop_block),
ast::ExprKind::While(_, ref loop_block, _)
| ast::ExprKind::WhileLet(_, _, ref loop_block, _)
| ast::ExprKind::ForLoop(_, _, ref loop_block, _)
| ast::ExprKind::Loop(ref loop_block, _) => func(loop_block),
_ => {},
}
}
@ -224,7 +224,6 @@ where
/// - The `if` condition expression,
/// - The `then` block, and
/// - The `else` expression.
///
fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
where
F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
@ -274,7 +273,6 @@ const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "Consider dropping the else clause a
const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \
block, like so:\n";
fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
// snip is the whole *help* message that appears after the warning.
// message is the warning message.
@ -294,7 +292,11 @@ fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str
span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip);
}
fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String {
fn suggestion_snippet_for_continue_inside_if<'a>(
ctx: &EarlyContext<'_>,
data: &'a LintData<'_>,
header: &str,
) -> String {
let cond_code = snippet(ctx, data.if_cond.span, "..");
let if_code = format!("if {} {{\n continue;\n}}\n", cond_code);
@ -311,7 +313,11 @@ fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &
ret
}
fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String {
fn suggestion_snippet_for_continue_inside_else<'a>(
ctx: &EarlyContext<'_>,
data: &'a LintData<'_>,
header: &str,
) -> String {
let cond_code = snippet(ctx, data.if_cond.span, "..");
let mut if_code = format!("if {} {{\n", cond_code);
@ -355,7 +361,12 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
block_stmts: &loop_block.stmts,
};
if needless_continue_in_else(else_expr) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
emit_warning(
ctx,
data,
DROP_ELSE_BLOCK_AND_MERGE_MSG,
LintType::ContinueInsideElseBlock,
);
} else if is_first_block_stmt_continue(then_block) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
}
@ -369,9 +380,9 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
/// e.g., the string
///
/// ```
/// {
/// let x = 5;
/// }
/// {
/// let x = 5;
/// }
/// ```
///
/// is transformed to
@ -413,7 +424,6 @@ pub fn erode_from_back(s: &str) -> String {
/// inside_a_block();
/// }
/// ```
///
pub fn erode_from_front(s: &str) -> String {
s.chars()
.skip_while(|c| c.is_whitespace())

View File

@ -7,27 +7,28 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use matches::matches;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty::{self, RegionKind, TypeFoldable};
use crate::rustc::traits;
use crate::rustc::middle::expr_use_visitor as euv;
use crate::rustc::middle::mem_categorization as mc;
use crate::rustc_target::spec::abi::Abi;
use crate::rustc::traits;
use crate::rustc::ty::{self, RegionKind, TypeFoldable};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::syntax::ast::NodeId;
use crate::syntax_pos::Span;
use crate::syntax::errors::DiagnosticBuilder;
use crate::utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
snippet, snippet_opt, span_lint_and_then};
use crate::utils::ptr::get_spans;
use std::borrow::Cow;
use crate::rustc_errors::Applicability;
use crate::rustc_target::spec::abi::Abi;
use crate::syntax::ast::NodeId;
use crate::syntax::errors::DiagnosticBuilder;
use crate::syntax_pos::Span;
use crate::utils::ptr::get_spans;
use crate::utils::{
get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths, snippet,
snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use matches::matches;
use std::borrow::Cow;
/// **What it does:** Checks for functions taking arguments by value, but not
/// consuming them in its
@ -67,7 +68,13 @@ impl LintPass for NeedlessPassByValue {
}
macro_rules! need {
($e: expr) => { if let Some(x) = $e { x } else { return; } };
($e: expr) => {
if let Some(x) = $e {
x
} else {
return;
}
};
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
@ -114,7 +121,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
need!(cx.tcx.lang_items().fn_trait()),
need!(cx.tcx.lang_items().fn_once_trait()),
need!(cx.tcx.lang_items().fn_mut_trait()),
need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT))
need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)),
];
let sized_trait = need!(cx.tcx.lang_items().sized_trait());
@ -125,7 +132,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
.filter(|p| !p.is_global())
.filter_map(|pred| {
if let ty::Predicate::Trait(poly_trait_ref) = pred {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars() {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
{
return None;
}
Some(poly_trait_ref)
@ -152,12 +160,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let fn_sig = cx.tcx.fn_sig(fn_def_id);
let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);
for (idx, ((input, &ty), arg)) in decl.inputs
.iter()
.zip(fn_sig.inputs())
.zip(&body.arguments)
.enumerate()
{
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments).enumerate() {
// All spans generated from a proc-macro invocation are the same...
if span == input.span {
return;
@ -172,9 +175,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
}
}
//
// * Exclude a type that is specifically bounded by `Borrow`.
// * Exclude a type whose reference also fulfills its bound.
// (e.g. `std::convert::AsRef`, `serde::Serialize`)
// * Exclude a type whose reference also fulfills its bound. (e.g. `std::convert::AsRef`,
// `serde::Serialize`)
let (implements_borrow_trait, all_borrowable_trait) = {
let preds = preds
.iter()
@ -183,17 +187,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
(
preds.iter().any(|t| t.def_id() == borrow_trait),
!preds.is_empty() && preds.iter().all(|t| {
let ty_params = &t.skip_binder().trait_ref.substs.iter().skip(1)
.cloned()
.collect::<Vec<_>>();
implements_trait(
cx,
cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
t.def_id(),
ty_params
)
}),
!preds.is_empty()
&& preds.iter().all(|t| {
let ty_params = &t
.skip_binder()
.trait_ref
.substs
.iter()
.skip(1)
.cloned()
.collect::<Vec<_>>();
implements_trait(cx, cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty), t.def_id(), ty_params)
}),
)
};
@ -415,14 +420,22 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
}
}
fn borrow(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, _: euv::LoanCause) {}
fn borrow(
&mut self,
_: NodeId,
_: Span,
_: &mc::cmt_<'tcx>,
_: ty::Region<'_>,
_: ty::BorrowKind,
_: euv::LoanCause,
) {
}
fn mutate(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {}
fn decl_without_init(&mut self, _: NodeId, _: Span) {}
}
fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt_<'tcx> {
loop {
match cmt.cat {
@ -431,5 +444,5 @@ fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt
},
_ => return (*cmt).clone(),
}
};
}
}

View File

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::span_lint;
/// **What it does:** Checks for needlessly including a base struct on update
@ -24,7 +23,11 @@ use crate::utils::span_lint;
///
/// **Example:**
/// ```rust
/// Point { x: 1, y: 0, ..zero_point }
/// Point {
/// x: 1,
/// y: 0,
/// ..zero_point
/// }
/// ```
declare_clippy_lint! {
pub NEEDLESS_UPDATE,

View File

@ -7,9 +7,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
@ -61,7 +60,6 @@ impl LintPass for NoNegCompOpForPartialOrd {
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_chain! {

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::source_map::{Span, Spanned};
use if_chain::if_chain;
use crate::consts::{self, Constant};
use crate::utils::span_lint;
@ -45,7 +44,14 @@ impl LintPass for NegMultiply {
#[allow(clippy::match_same_arms)]
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref l, ref r) = e.node {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Mul, ..
},
ref l,
ref r,
) = e.node
{
match (&l.node, &r.node) {
(&ExprKind::Unary(..), &ExprKind::Unary(..)) => (),
(&ExprKind::Unary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r),

View File

@ -7,19 +7,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::hir::def_id::DefId;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::util::nodemap::NodeSet;
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty::{self, Ty};
use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span;
use crate::utils::paths;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then};
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::rustc_errors::Applicability;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for types with a `fn new() -> Self` method and no
/// implementation of
@ -125,7 +124,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
}
if impl_item.generics.params.iter().any(|gen| match gen.kind {
hir::GenericParamKind::Type { .. } => true,
_ => false
_ => false,
}) {
// when the result of `new()` depends on a type parameter we should not require
// an
@ -134,8 +133,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
}
if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
let self_did = cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id));
let self_ty = cx.tcx
.type_of(self_did);
let self_ty = cx.tcx.type_of(self_did);
if_chain! {
if same_tys(cx, self_ty, return_ty(cx, id));
if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
@ -171,7 +169,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
cx,
NEW_WITHOUT_DEFAULT_DERIVE,
impl_item.span,
&format!("you should consider deriving a `Default` implementation for `{}`", self_ty),
&format!(
"you should consider deriving a `Default` implementation for `{}`",
self_ty
),
|db| {
db.suggest_item_with_attr(
cx,
@ -186,7 +187,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
cx,
NEW_WITHOUT_DEFAULT,
impl_item.span,
&format!("you should consider adding a `Default` implementation for `{}`", self_ty),
&format!(
"you should consider adding a `Default` implementation for `{}`",
self_ty
),
|db| {
db.suggest_prepend_item(
cx,

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::def::Def;
use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@ -63,37 +62,42 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
has_no_effect(cx, a) && has_no_effect(cx, b)
},
ExprKind::Array(ref v) | ExprKind::Tup(ref v) => v.iter().all(|val| has_no_effect(cx, val)),
ExprKind::Repeat(ref inner, _) |
ExprKind::Cast(ref inner, _) |
ExprKind::Type(ref inner, _) |
ExprKind::Unary(_, ref inner) |
ExprKind::Field(ref inner, _) |
ExprKind::AddrOf(_, ref inner) |
ExprKind::Box(ref inner) => has_no_effect(cx, inner),
ExprKind::Repeat(ref inner, _)
| ExprKind::Cast(ref inner, _)
| ExprKind::Type(ref inner, _)
| ExprKind::Unary(_, ref inner)
| ExprKind::Field(ref inner, _)
| ExprKind::AddrOf(_, ref inner)
| ExprKind::Box(ref inner) => has_no_effect(cx, inner),
ExprKind::Struct(_, ref fields, ref base) => {
!has_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base {
Some(ref base) => has_no_effect(cx, base),
None => true,
}
!has_drop(cx, expr)
&& fields.iter().all(|field| has_no_effect(cx, &field.expr))
&& match *base {
Some(ref base) => has_no_effect(cx, base),
None => true,
}
},
ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def {
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
!has_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
},
_ => false,
}
} else {
false
},
ExprKind::Block(ref block, _) => {
block.stmts.is_empty() && if let Some(ref expr) = block.expr {
has_no_effect(cx, expr)
ExprKind::Call(ref callee, ref args) => {
if let ExprKind::Path(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def {
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
!has_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
},
_ => false,
}
} else {
false
}
},
ExprKind::Block(ref block, _) => {
block.stmts.is_empty()
&& if let Some(ref expr) = block.expr {
has_no_effect(cx, expr)
} else {
false
}
},
_ => false,
}
}
@ -139,7 +143,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
}
fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec<&'a Expr>> {
if in_macro(expr.span) {
return None;
@ -150,37 +153,34 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec
Some(vec![&**a, &**b])
},
ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()),
ExprKind::Repeat(ref inner, _) |
ExprKind::Cast(ref inner, _) |
ExprKind::Type(ref inner, _) |
ExprKind::Unary(_, ref inner) |
ExprKind::Field(ref inner, _) |
ExprKind::AddrOf(_, ref inner) |
ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
ExprKind::Struct(_, ref fields, ref base) => if has_drop(cx, expr) {
None
} else {
Some(
fields
.iter()
.map(|f| &f.expr)
.chain(base)
.map(Deref::deref)
.collect(),
)
},
ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def {
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
if !has_drop(cx, expr) =>
{
Some(args.iter().collect())
},
_ => None,
ExprKind::Repeat(ref inner, _)
| ExprKind::Cast(ref inner, _)
| ExprKind::Type(ref inner, _)
| ExprKind::Unary(_, ref inner)
| ExprKind::Field(ref inner, _)
| ExprKind::AddrOf(_, ref inner)
| ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
ExprKind::Struct(_, ref fields, ref base) => {
if has_drop(cx, expr) {
None
} else {
Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
}
},
ExprKind::Call(ref callee, ref args) => {
if let ExprKind::Path(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def {
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
if !has_drop(cx, expr) =>
{
Some(args.iter().collect())
},
_ => None,
}
} else {
None
}
} else {
None
},
ExprKind::Block(ref block, _) => {
if block.stmts.is_empty() {

View File

@ -7,22 +7,21 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for uses of const which the type is not Freeze (Cell-free).
//!
//! This lint is **deny** by default.
use crate::rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def;
use crate::rustc::ty::{self, TypeFlags};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
use crate::rustc::ty::adjustment::Adjust;
use crate::rustc::ty::{self, TypeFlags};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::rustc_typeck::hir_ty_to_ty;
use crate::syntax_pos::{DUMMY_SP, Span};
use std::ptr;
use crate::syntax_pos::{Span, DUMMY_SP};
use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then};
use std::ptr;
/// **What it does:** Checks for declaration of `const` items which is interior
/// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc).
@ -42,11 +41,11 @@ use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then};
///
/// **Example:**
/// ```rust
/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// // Bad.
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
///
/// // Good.
@ -74,11 +73,11 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
///
/// // Bad.
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
///
/// // Good.
@ -94,16 +93,9 @@ declare_clippy_lint! {
#[derive(Copy, Clone)]
enum Source {
Item {
item: Span,
},
Assoc {
item: Span,
ty: Span,
},
Expr {
expr: Span,
},
Item { item: Span },
Assoc { item: Span, ty: Span },
Expr { expr: Span },
}
impl Source {
@ -123,11 +115,7 @@ impl Source {
}
}
fn verify_ty_bound<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
ty: ty::Ty<'tcx>,
source: Source,
) {
fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, source: Source) {
if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) {
// an UnsafeCell is !Copy, and an UnsafeCell is also the only type which
// is !Freeze, thus if our type is Copy we can be sure it must be Freeze
@ -149,22 +137,19 @@ fn verify_ty_bound<'a, 'tcx>(
"static".to_string(),
Applicability::MachineApplicable,
);
}
},
Source::Assoc { ty: ty_span, .. } => {
if ty.flags.contains(TypeFlags::HAS_FREE_LOCAL_NAMES) {
db.span_help(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
}
}
},
Source::Expr { .. } => {
db.help(
"assign this const to a local or static variable, and use the variable here",
);
}
db.help("assign this const to a local or static variable, and use the variable here");
},
}
});
}
pub struct NonCopyConst;
impl LintPass for NonCopyConst {
@ -184,7 +169,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx TraitItem) {
if let TraitItemKind::Const(hir_ty, ..) = &trait_item.node {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: trait_item.span });
verify_ty_bound(
cx,
ty,
Source::Assoc {
ty: hir_ty.span,
item: trait_item.span,
},
);
}
}
@ -195,7 +187,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
// ensure the impl is an inherent impl.
if let ItemKind::Impl(_, _, _, _, None, _, _) = item.node {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: impl_item.span });
verify_ty_bound(
cx,
ty,
Source::Assoc {
ty: hir_ty.span,
item: impl_item.span,
},
);
}
}
}
@ -227,25 +226,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
ExprKind::AddrOf(..) => {
// `&e` => `e` must be referenced
needs_check_adjustment = false;
}
},
ExprKind::Field(..) => {
dereferenced_expr = parent_expr;
needs_check_adjustment = true;
}
},
ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
// `e[i]` => desugared to `*Index::index(&e, i)`,
// meaning `e` must be referenced.
// no need to go further up since a method call is involved now.
needs_check_adjustment = false;
break;
}
},
ExprKind::Unary(UnDeref, _) => {
// `*e` => desugared to `*Deref::deref(&e)`,
// meaning `e` must be referenced.
// no need to go further up since a method call is involved now.
needs_check_adjustment = false;
break;
}
},
_ => break,
}
cur_expr = parent_expr;

View File

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{LintArray, LintPass, EarlyContext, EarlyLintPass};
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString;
use crate::syntax::ast::*;
use crate::syntax::attr;
use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString;
use crate::syntax::visit::{walk_block, walk_expr, walk_pat, Visitor};
use crate::utils::{span_lint, span_lint_and_then};
@ -116,9 +115,11 @@ impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
fn visit_pat(&mut self, pat: &'tcx Pat) {
match pat.node {
PatKind::Ident(_, ident, _) => self.check_name(ident.span, ident.name),
PatKind::Struct(_, ref fields, _) => for field in fields {
if !field.node.is_shorthand {
self.visit_pat(&field.node.pat);
PatKind::Struct(_, ref fields, _) => {
for field in fields {
if !field.node.is_shorthand {
self.visit_pat(&field.node.pat);
}
}
},
_ => walk_pat(self, pat),
@ -155,7 +156,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
self.0.cx,
MANY_SINGLE_CHAR_NAMES,
span,
&format!("{}th binding whose name is just one char", self.0.single_char_names.len()),
&format!(
"{}th binding whose name is just one char",
self.0.single_char_names.len()
),
);
}
}
@ -197,26 +201,19 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
} else {
let mut interned_chars = interned_name.chars();
let mut existing_chars = existing_name.interned.chars();
let first_i = interned_chars
.next()
.expect("we know we have at least one char");
let first_e = existing_chars
.next()
.expect("we know we have at least one char");
let first_i = interned_chars.next().expect("we know we have at least one char");
let first_e = existing_chars.next().expect("we know we have at least one char");
let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();
if eq_or_numeric((first_i, first_e)) {
let last_i = interned_chars
.next_back()
.expect("we know we have at least two chars");
let last_e = existing_chars
.next_back()
.expect("we know we have at least two chars");
let last_i = interned_chars.next_back().expect("we know we have at least two chars");
let last_e = existing_chars.next_back().expect("we know we have at least two chars");
if eq_or_numeric((last_i, last_e)) {
if interned_chars
.zip(existing_chars)
.filter(|&ie| !eq_or_numeric(ie))
.count() != 1
.count()
!= 1
{
continue;
}
@ -227,7 +224,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
let second_last_e = existing_chars
.next_back()
.expect("we know we have at least three chars");
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_'
if !eq_or_numeric((second_last_i, second_last_e))
|| second_last_i == '_'
|| !interned_chars.zip(existing_chars).all(eq_or_numeric)
{
// allowed similarity foo_x, foo_y
@ -237,13 +235,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
}
} else {
let second_i = interned_chars
.next()
.expect("we know we have at least two chars");
let second_e = existing_chars
.next()
.expect("we know we have at least two chars");
if !eq_or_numeric((second_i, second_e)) || second_i == '_'
let second_i = interned_chars.next().expect("we know we have at least two chars");
let second_e = existing_chars.next().expect("we know we have at least two chars");
if !eq_or_numeric((second_i, second_e))
|| second_i == '_'
|| !interned_chars.zip(existing_chars).all(eq_or_numeric)
{
// allowed similarity x_foo, y_foo

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint};
use if_chain::if_chain;
/// **What it does:*** Checks for unnecessary `ok()` in if let.
///

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
@ -200,7 +199,12 @@ fn check_open_options(cx: &LateContext<'_, '_>, options: &[(OpenOption, Argument
}
if read && truncate && read_arg && truncate_arg && !(write && write_arg) {
span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\"");
span_lint(
cx,
NONSENSICAL_OPEN_OPTIONS,
span,
"file opened with \"truncate\" and \"read\"",
);
}
if append && truncate && append_arg && truncate_arg {
span_lint(

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::utils::{span_lint, SpanlessEq};
use if_chain::if_chain;
/// **What it does:** Detects classic underflow/overflow checks.
///

View File

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast::LitKind;
use crate::syntax::ptr::P;
use crate::syntax::ext::quote::rt::Span;
use crate::syntax::ptr::P;
use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint};
use if_chain::if_chain;
/// **What it does:** Checks for missing parameters in `panic!`.
///

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::utils::{is_automatically_derived, span_lint};
use if_chain::if_chain;
/// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
///

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
@ -115,7 +114,10 @@ impl EarlyLintPass for Precedence {
expr.span,
"unary minus has lower precedence than method call",
"consider adding parentheses to clarify your intent",
format!("-({})", snippet_with_applicability(cx, rhs.span, "..", &mut applicability)),
format!(
"-({})",
snippet_with_applicability(cx, rhs.span, "..", &mut applicability)
),
applicability,
);
},

View File

@ -7,22 +7,21 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Checks for usage of `&Vec[_]` and `&String`.
use std::borrow::Cow;
use crate::rustc::hir::*;
use crate::rustc::hir::QPath;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::NodeId;
use crate::syntax::source_map::Span;
use crate::syntax_pos::MultiSpan;
use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
use crate::utils::ptr::get_spans;
use crate::rustc_errors::Applicability;
use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
use if_chain::if_chain;
use std::borrow::Cow;
/// **What it does:** This lint checks for function arguments of type `&String`
/// or `&Vec` unless the references are mutable. It will also suggest you
@ -55,10 +54,10 @@ use crate::rustc_errors::Applicability;
/// fn foo(&Vec<u32>) { .. }
/// ```
declare_clippy_lint! {
pub PTR_ARG,
style,
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
instead, respectively"
pub PTR_ARG,
style,
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
instead, respectively"
}
/// **What it does:** This lint checks for equality comparisons with `ptr::null`
@ -71,7 +70,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// if x == ptr::null { .. }
/// if x == ptr::null {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub CMP_NULL,
@ -162,12 +163,7 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
let fn_ty = sig.skip_binder();
for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
if let ty::Ref(
_,
ty,
MutImmutable
) = ty.sty
{
if let ty::Ref(_, ty, MutImmutable) = ty.sty {
if match_type(cx, ty, &paths::VEC) {
let mut ty_snippet = None;
if_chain! {
@ -193,19 +189,18 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
|db| {
if let Some(ref snippet) = ty_snippet {
db.span_suggestion_with_applicability(
arg.span,
"change this to",
format!("&[{}]", snippet),
Applicability::Unspecified,
);
arg.span,
"change this to",
format!("&[{}]", snippet),
Applicability::Unspecified,
);
}
for (clonespan, suggestion) in spans {
db.span_suggestion_with_applicability(
clonespan,
&snippet_opt(cx, clonespan).map_or(
"change the call to".into(),
|x| Cow::Owned(format!("change `{}` to", x)),
),
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
Cow::Owned(format!("change `{}` to", x))
}),
suggestion.into(),
Applicability::Unspecified,
);
@ -230,10 +225,9 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
for (clonespan, suggestion) in spans {
db.span_suggestion_short_with_applicability(
clonespan,
&snippet_opt(cx, clonespan).map_or(
"change the call to".into(),
|x| Cow::Owned(format!("change `{}` to", x)),
),
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
Cow::Owned(format!("change `{}` to", x))
}),
suggestion.into(),
Applicability::Unspecified,
);
@ -280,7 +274,8 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
if let FunctionRetTy::Return(ref ty) = decl.output {
if let Some((out, MutMutable, _)) = get_rptr_lm(ty) {
let mut immutables = vec![];
for (_, ref mutbl, ref argspan) in decl.inputs
for (_, ref mutbl, ref argspan) in decl
.inputs
.iter()
.filter_map(|ty| get_rptr_lm(ty))
.filter(|&(lt, _, _)| lt.name == out.name)
@ -293,10 +288,16 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
if immutables.is_empty() {
return;
}
span_lint_and_then(cx, MUT_FROM_REF, ty.span, "mutable borrow from immutable input(s)", |db| {
let ms = MultiSpan::from_spans(immutables);
db.span_note(ms, "immutable borrow here");
});
span_lint_and_then(
cx,
MUT_FROM_REF,
ty.span,
"mutable borrow from immutable input(s)",
|db| {
let ms = MultiSpan::from_spans(immutables);
db.span_note(ms, "immutable borrow here");
},
);
}
}
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::{declare_tool_lint, hir, lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::utils;
@ -27,7 +26,9 @@ use std::fmt;
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
///
/// unsafe { ptr.offset(offset as isize); }
/// unsafe {
/// ptr.offset(offset as isize);
/// }
/// ```
///
/// Could be written:
@ -37,7 +38,9 @@ use std::fmt;
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
///
/// unsafe { ptr.add(offset); }
/// unsafe {
/// ptr.add(offset);
/// }
/// ```
declare_clippy_lint! {
pub PTR_OFFSET_WITH_CAST,
@ -82,7 +85,6 @@ impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass {
} else {
utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg);
}
}
}
@ -119,18 +121,12 @@ fn expr_as_ptr_offset_call<'a, 'tcx>(
}
// Is the type of the expression a usize?
fn is_expr_ty_usize<'a, 'tcx>(
cx: &lint::LateContext<'a, 'tcx>,
expr: &hir::Expr,
) -> bool {
fn is_expr_ty_usize<'a, 'tcx>(cx: &lint::LateContext<'a, 'tcx>, expr: &hir::Expr) -> bool {
cx.tables.expr_ty(expr) == cx.tcx.types.usize
}
// Is the type of the expression a raw pointer?
fn is_expr_ty_raw_ptr<'a, 'tcx>(
cx: &lint::LateContext<'a, 'tcx>,
expr: &hir::Expr,
) -> bool {
fn is_expr_ty_raw_ptr<'a, 'tcx>(cx: &lint::LateContext<'a, 'tcx>, expr: &hir::Expr) -> bool {
cx.tables.expr_ty(expr).is_unsafe_ptr()
}

View File

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::def::Def;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def;
use crate::utils::sugg::Sugg;
use crate::syntax::ptr::P;
use crate::utils::sugg::Sugg;
use if_chain::if_chain;
use crate::utils::{match_def_path, match_type, span_lint_and_then};
use crate::utils::paths::*;
use crate::rustc_errors::Applicability;
use crate::utils::paths::*;
use crate::utils::{match_def_path, match_type, span_lint_and_then};
/// **What it does:** Checks for expressions that could be replaced by the question mark operator
///
@ -38,7 +37,7 @@ use crate::rustc_errors::Applicability;
/// ```rust
/// option?;
/// ```
declare_clippy_lint!{
declare_clippy_lint! {
pub QUESTION_MARK,
style,
"checks for expressions that could be replaced by the question mark operator"
@ -108,17 +107,15 @@ impl Pass {
false
},
ExprKind::Ret(Some(ref expr)) => {
Self::expression_returns_none(cx, expr)
},
ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
ExprKind::Path(ref qp) => {
if let Def::VariantCtor(def_id, _) = cx.tables.qpath_def(qp, expression.hir_id) {
return match_def_path(cx.tcx, def_id, &OPTION_NONE);
return match_def_path(cx.tcx, def_id, &OPTION_NONE);
}
false
},
_ => false
_ => false,
}
}

View File

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::RangeLimits;
use crate::syntax::source_map::Spanned;
use crate::utils::{is_integer_literal, paths, snippet, span_lint, span_lint_and_then, snippet_opt};
use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
use crate::utils::sugg::Sugg;
use crate::rustc_errors::Applicability;
use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
use crate::utils::{is_integer_literal, paths, snippet, snippet_opt, span_lint, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for calling `.step_by(0)` on iterators,
/// which never terminates.
@ -29,7 +28,9 @@ use crate::rustc_errors::Applicability;
///
/// **Example:**
/// ```rust
/// for x in (5..5).step_by(0) { .. }
/// for x in (5..5).step_by(0) {
/// ..
/// }
/// ```
declare_clippy_lint! {
pub ITERATOR_STEP_BY_ZERO,
@ -98,7 +99,12 @@ pub struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE)
lint_array!(
ITERATOR_STEP_BY_ZERO,
RANGE_ZIP_WITH_LEN,
RANGE_PLUS_ONE,
RANGE_MINUS_ONE
)
}
}
@ -148,7 +154,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// exclusive range plus one: x..(y+1)
if_chain! {
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(cx, expr);
if let Some(higher::Range {
start,
end: Some(end),
limits: RangeLimits::HalfOpen
}) = higher::range(cx, expr);
if let Some(y) = y_plus_one(end);
then {
span_lint_and_then(
@ -217,12 +227,20 @@ fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
fn y_plus_one(expr: &Expr) -> Option<&Expr> {
match expr.node {
ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) {
Some(rhs)
} else if is_integer_literal(rhs, 1) {
Some(lhs)
} else {
None
ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
ref lhs,
ref rhs,
) => {
if is_integer_literal(lhs, 1) {
Some(rhs)
} else if is_integer_literal(rhs, 1) {
Some(lhs)
} else {
None
}
},
_ => None,
}
@ -230,7 +248,13 @@ fn y_plus_one(expr: &Expr) -> Option<&Expr> {
fn y_minus_one(expr: &Expr) -> Option<&Expr> {
match expr.node {
ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) if is_integer_literal(rhs, 1) => Some(lhs),
ExprKind::Binary(
Spanned {
node: BinOpKind::Sub, ..
},
ref lhs,
ref rhs,
) if is_integer_literal(rhs, 1) => Some(lhs),
_ => None,
}
}

View File

@ -279,7 +279,9 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
fn visit_local(&mut self, local: &mir::Local, ctx: PlaceContext<'tcx>, _: mir::Location) {
match ctx {
PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(NonUseContext::StorageDead) => return,
PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(NonUseContext::StorageDead) => {
return
},
_ => {},
}

View File

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*;
use crate::utils::{span_lint_and_sugg};
use crate::utils::span_lint_and_sugg;
/// **What it does:** Checks for fields in struct literals where shorthands
/// could be used.

View File

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::syntax::ptr::P;
use crate::syntax::ast::LitKind;
use crate::utils::{match_qpath, paths, snippet, span_lint_and_then};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind;
use crate::syntax::ptr::P;
use crate::utils::{match_qpath, paths, snippet, span_lint_and_then};
/// **What it does:** Lint for redundant pattern matching over `Result` or
/// `Option`
@ -46,7 +45,6 @@ use crate::rustc_errors::Applicability;
/// if Some(42).is_some() {}
/// Ok::<i32, i32>(42).is_ok();
/// ```
///
declare_clippy_lint! {
pub REDUNDANT_PATTERN_MATCHING,
style,
@ -74,12 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
}
fn find_sugg_for_if_let<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx Expr,
op: &P<Expr>,
arms: &HirVec<Arm>
) {
fn find_sugg_for_if_let<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, op: &P<Expr>, arms: &HirVec<Arm>) {
if arms[0].pats.len() == 1 {
let good_method = match arms[0].pats[0].node {
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
@ -123,19 +116,14 @@ fn find_sugg_for_if_let<'a, 'tcx>(
}
}
fn find_sugg_for_match<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx Expr,
op: &P<Expr>,
arms: &HirVec<Arm>
) {
fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, op: &P<Expr>, arms: &HirVec<Arm>) {
if arms.len() == 2 {
let node_pair = (&arms[0].pats[0].node, &arms[1].pats[0].node);
let found_good_method = match node_pair {
(
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
PatKind::TupleStruct(ref path_right, ref patterns_right, _)
PatKind::TupleStruct(ref path_right, ref patterns_right, _),
) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].node, &patterns_right[0].node) {
find_good_method_for_match(
@ -145,19 +133,16 @@ fn find_sugg_for_match<'a, 'tcx>(
&paths::RESULT_OK,
&paths::RESULT_ERR,
"is_ok()",
"is_err()"
"is_err()",
)
} else {
None
}
},
(
PatKind::TupleStruct(ref path_left, ref patterns, _),
PatKind::Path(ref path_right)
) | (
PatKind::Path(ref path_left),
PatKind::TupleStruct(ref path_right, ref patterns, _)
) if patterns.len() == 1 => {
(PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
| (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
if patterns.len() == 1 =>
{
if let PatKind::Wild = patterns[0].node {
find_good_method_for_match(
arms,
@ -166,7 +151,7 @@ fn find_sugg_for_match<'a, 'tcx>(
&paths::OPTION_SOME,
&paths::OPTION_NONE,
"is_some()",
"is_none()"
"is_none()",
)
} else {
None
@ -204,7 +189,7 @@ fn find_good_method_for_match<'a>(
expected_left: &[&str],
expected_right: &[&str],
should_be_left: &'a str,
should_be_right: &'a str
should_be_right: &'a str,
) -> Option<&'a str> {
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
(&(*arms[0].body).node, &(*arms[1].body).node)
@ -215,12 +200,10 @@ fn find_good_method_for_match<'a>(
};
match body_node_pair {
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => {
match (&lit_left.node, &lit_right.node) {
(LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
(LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
_ => None,
}
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
(LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
(LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
_ => None,
},
_ => None,
}

View File

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;

Some files were not shown because too many files have changed in this diff Show More