Skip to content

Add lint to detect manual slice copies #2021

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clippy_lints/src/approx_const.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc::lint::*;
use rustc::hir::*;
use std::f64::consts as f64;
use syntax::ast::{Lit, LitKind, FloatTy};
use syntax::ast::{FloatTy, Lit, LitKind};
use syntax::symbol;
use utils::span_lint;

Expand Down Expand Up @@ -91,7 +91,7 @@ fn check_known_consts(cx: &LateContext, e: &Expr, s: &symbol::Symbol, module: &s
e.span,
&format!(
"approximate value of `{}::consts::{}` found. \
Consider using it directly",
Consider using it directly",
module,
&name
),
Expand Down
15 changes: 13 additions & 2 deletions clippy_lints/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
match expr.node {
hir::ExprBinary(ref op, ref l, ref r) => {
match op.node {
hir::BiAnd | hir::BiOr | hir::BiBitAnd | hir::BiBitOr | hir::BiBitXor | hir::BiShl |
hir::BiShr | hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => return,
hir::BiAnd |
hir::BiOr |
hir::BiBitAnd |
hir::BiBitOr |
hir::BiBitXor |
hir::BiShl |
hir::BiShr |
hir::BiEq |
hir::BiLt |
hir::BiLe |
hir::BiNe |
hir::BiGe |
hir::BiGt => return,
_ => (),
}
let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r));
Expand Down
46 changes: 22 additions & 24 deletions clippy_lints/src/array_indexing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::ty;
use rustc::ty::subst::Substs;
use rustc_const_eval::ConstContext;
use rustc_const_math::{ConstUsize, ConstIsize, ConstInt};
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use rustc::hir;
use syntax::ast::RangeLimits;
use utils::{self, higher};
Expand Down Expand Up @@ -124,29 +124,27 @@ fn to_const_range(
};

let end = match *end {
Some(Some(ConstVal::Integral(x))) => {
if limits == RangeLimits::Closed {
match x {
ConstInt::U8(_) => (x + ConstInt::U8(1)),
ConstInt::U16(_) => (x + ConstInt::U16(1)),
ConstInt::U32(_) => (x + ConstInt::U32(1)),
ConstInt::U64(_) => (x + ConstInt::U64(1)),
ConstInt::U128(_) => (x + ConstInt::U128(1)),
ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))),
ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))),
ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))),
ConstInt::I8(_) => (x + ConstInt::I8(1)),
ConstInt::I16(_) => (x + ConstInt::I16(1)),
ConstInt::I32(_) => (x + ConstInt::I32(1)),
ConstInt::I64(_) => (x + ConstInt::I64(1)),
ConstInt::I128(_) => (x + ConstInt::I128(1)),
ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))),
ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))),
ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))),
}.expect("such a big array is not realistic")
} else {
x
}
Some(Some(ConstVal::Integral(x))) => if limits == RangeLimits::Closed {
match x {
ConstInt::U8(_) => (x + ConstInt::U8(1)),
ConstInt::U16(_) => (x + ConstInt::U16(1)),
ConstInt::U32(_) => (x + ConstInt::U32(1)),
ConstInt::U64(_) => (x + ConstInt::U64(1)),
ConstInt::U128(_) => (x + ConstInt::U128(1)),
ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))),
ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))),
ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))),
ConstInt::I8(_) => (x + ConstInt::I8(1)),
ConstInt::I16(_) => (x + ConstInt::I16(1)),
ConstInt::I32(_) => (x + ConstInt::I32(1)),
ConstInt::I64(_) => (x + ConstInt::I64(1)),
ConstInt::I128(_) => (x + ConstInt::I128(1)),
ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))),
ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))),
ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))),
}.expect("such a big array is not realistic")
} else {
x
},
Some(_) => return None,
None => array_size,
Expand Down
40 changes: 23 additions & 17 deletions clippy_lints/src/assign_ops.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc::hir;
use rustc::lint::*;
use syntax::ast;
use utils::{span_lint_and_then, snippet_opt, SpanlessEq, get_trait_def_id, implements_trait};
use utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use utils::{higher, sugg};

/// **What it does:** Checks for compound assignment operations (`+=` and
Expand Down Expand Up @@ -88,19 +88,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
if let hir::ExprBinary(binop, ref l, ref r) = rhs.node {
if op.node == binop.node {
let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
span_lint_and_then(cx,
MISREFACTORED_ASSIGN_OP,
expr.span,
"variable appears on both sides of an assignment operation",
|db| if let (Some(snip_a), Some(snip_r)) =
(snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) {
db.span_suggestion(expr.span,
"replace it with",
format!("{} {}= {}",
snip_a,
op.node.as_str(),
snip_r));
});
span_lint_and_then(
cx,
MISREFACTORED_ASSIGN_OP,
expr.span,
"variable appears on both sides of an assignment operation",
|db| if let (Some(snip_a), Some(snip_r)) =
(snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
{
db.span_suggestion(
expr.span,
"replace it with",
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
);
},
);
};
// lhs op= l op r
if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
Expand Down Expand Up @@ -167,8 +169,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
BitXor: BiBitXor,
Shr: BiShr,
Shl: BiShl
)
{
) {
span_lint_and_then(
cx,
ASSIGN_OP_PATTERN,
Expand All @@ -193,7 +194,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
// a = b commutative_op a
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) {
match op.node {
hir::BiAdd | hir::BiMul | hir::BiAnd | hir::BiOr | hir::BiBitXor | hir::BiBitAnd |
hir::BiAdd |
hir::BiMul |
hir::BiAnd |
hir::BiOr |
hir::BiBitXor |
hir::BiBitAnd |
hir::BiBitOr => {
lint(assignee, l);
},
Expand Down
31 changes: 13 additions & 18 deletions clippy_lints/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt};
use semver::Version;
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span;
use utils::{in_macro, match_def_path, paths, span_lint, span_lint_and_then, snippet_opt};
use utils::{in_macro, match_def_path, paths, snippet_opt, span_lint, span_lint_and_then};

/// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics.
Expand Down Expand Up @@ -110,8 +110,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
check_attrs(cx, item.span, &item.name, &item.attrs)
}
match item.node {
ItemExternCrate(_) |
ItemUse(_, _) => {
ItemExternCrate(_) | ItemUse(_, _) => {
for attr in &item.attrs {
if let Some(ref lint_list) = attr.meta_item_list() {
if let Some(name) = attr.name() {
Expand Down Expand Up @@ -196,30 +195,26 @@ fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> b
if let Some(stmt) = block.stmts.first() {
match stmt.node {
StmtDecl(_, _) => true,
StmtExpr(ref expr, _) |
StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr),
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr),
}
} else {
block.expr.as_ref().map_or(
false,
|e| is_relevant_expr(tcx, tables, e),
)
block
.expr
.as_ref()
.map_or(false, |e| is_relevant_expr(tcx, tables, e))
}
}

fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool {
match expr.node {
ExprBlock(ref block) => is_relevant_block(tcx, tables, block),
ExprRet(Some(ref e)) => is_relevant_expr(tcx, tables, e),
ExprRet(None) |
ExprBreak(_, None) => false,
ExprCall(ref path_expr, _) => {
if let ExprPath(ref qpath) = path_expr.node {
let fun_id = tables.qpath_def(qpath, path_expr.hir_id).def_id();
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
} else {
true
}
ExprRet(None) | ExprBreak(_, None) => false,
ExprCall(ref path_expr, _) => if let ExprPath(ref qpath) = path_expr.node {
let fun_id = tables.qpath_def(qpath, path_expr.hir_id).def_id();
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
} else {
true
},
_ => true,
}
Expand Down
Loading