Skip to content

Needless borrow lint #884

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
May 9, 2016
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ All notable changes to this project will be documented in this file.
[`mutex_atomic`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic
[`mutex_integer`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_integer
[`needless_bool`]: https://github.com/Manishearth/rust-clippy/wiki#needless_bool
[`needless_borrow`]: https://github.com/Manishearth/rust-clippy/wiki#needless_borrow
[`needless_lifetimes`]: https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes
[`needless_range_loop`]: https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop
[`needless_return`]: https://github.com/Manishearth/rust-clippy/wiki#needless_return
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Table of contents:

## Lints

There are 146 lints included in this crate:
There are 147 lints included in this crate:

name | default | meaning
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -97,6 +97,7 @@ name
[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead
[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type
[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
[needless_borrow](https://github.com/Manishearth/rust-clippy/wiki#needless_borrow) | warn | taking a reference that is going to be automatically dereferenced
[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them
[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do
[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice
Expand Down
2 changes: 1 addition & 1 deletion src/array_indexing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl LateLintPass for ArrayIndexing {
let size = ConstInt::Infer(size as u64);

// Index is a constant uint
let const_index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None);
let const_index = eval_const_expr_partial(cx.tcx, index, ExprTypeChecked, None);
if let Ok(ConstVal::Integral(const_index)) = const_index {
if size <= const_index {
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds");
Expand Down
2 changes: 1 addition & 1 deletion src/block_in_if_condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<'v> Visitor<'v> for ExVisitor<'v> {
}
};
if complex {
self.found_block = Some(&expr);
self.found_block = Some(expr);
return;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/booleans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
s.push('(');
}
}
s.push_str(&snip(&terminals[n as usize]));
s.push_str(&snip(terminals[n as usize]));
if brackets {
if let ExprBinary(..) = terminals[n as usize].node {
s.push(')');
Expand Down Expand Up @@ -319,7 +319,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
}
let mut improvements = Vec::new();
'simplified: for suggestion in &simplified {
let simplified_stats = terminal_stats(&suggestion);
let simplified_stats = terminal_stats(suggestion);
let mut improvement = false;
for i in 0..32 {
// ignore any "simplifications" that end up requiring a terminal more often than in the original expression
Expand Down
4 changes: 2 additions & 2 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,14 @@ impl PartialOrd for Constant {
}
}
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r),
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) |
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(r),
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => {
match lv.partial_cmp(rv) {
Some(Equal) => Some(ls.cmp(rs)),
x => x,
}
}
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l.partial_cmp(r),
_ => None, //TODO: Are there any useful inter-type orderings?
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) {
};

if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node {
if let Some((i, j)) = search_same(&arms, hash, eq) {
if let Some((i, j)) = search_same(arms, hash, eq) {
span_note_and_lint(cx,
MATCH_SAME_ARMS,
j.body.span,
Expand Down Expand Up @@ -256,8 +256,8 @@ fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)>
match map.entry(hash(expr)) {
Entry::Occupied(o) => {
for o in o.get() {
if eq(&o, expr) {
return Some((&o, expr));
if eq(o, expr) {
return Some((o, expr));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/cyclomatic_complexity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl CyclomaticComplexity {
divergence: 0,
short_circuits: 0,
returns: 0,
tcx: &cx.tcx,
tcx: cx.tcx,
};
helper.visit_block(block);
let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper;
Expand Down
8 changes: 4 additions & 4 deletions src/enum_variants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ impl EarlyLintPass for EnumVariantNames {
for var in &def.variants {
let name = var2str(var);

let pre_match = partial_match(&pre, &name);
let pre_match = partial_match(pre, &name);
pre = &pre[..pre_match];
let pre_camel = camel_case_until(&pre);
let pre_camel = camel_case_until(pre);
pre = &pre[..pre_camel];
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
if next.is_lowercase() {
Expand All @@ -82,10 +82,10 @@ impl EarlyLintPass for EnumVariantNames {
}
}

let post_match = partial_rmatch(&post, &name);
let post_match = partial_rmatch(post, &name);
let post_end = post.len() - post_match;
post = &post[post_end..];
let post_camel = camel_case_from(&post);
let post_camel = camel_case_from(post);
post = &post[post_camel..];
}
let (what, value) = match (pre.is_empty(), post.is_empty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/len_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
})
}

let ty = &walk_ptrs_ty(&cx.tcx.expr_ty(expr));
let ty = &walk_ptrs_ty(cx.tcx.expr_ty(expr));
match ty.sty {
ty::TyTrait(_) => {
cx.tcx
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub mod mut_mut;
pub mod mut_reference;
pub mod mutex_atomic;
pub mod needless_bool;
pub mod needless_borrow;
pub mod needless_update;
pub mod neg_multiply;
pub mod new_without_default;
Expand Down Expand Up @@ -140,7 +141,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
("clippy.toml", false)
};

let (conf, errors) = utils::conf::read_conf(&file_name, must_exist);
let (conf, errors) = utils::conf::read_conf(file_name, must_exist);

// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
Expand Down Expand Up @@ -210,6 +211,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass);
reg.register_late_lint_pass(box mutex_atomic::MutexAtomic);
reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass);
reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow);
reg.register_late_lint_pass(box no_effect::NoEffectPass);
reg.register_late_lint_pass(box map_clone::MapClonePass);
reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass);
Expand Down Expand Up @@ -364,6 +366,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
mutex_atomic::MUTEX_ATOMIC,
needless_bool::BOOL_COMPARISON,
needless_bool::NEEDLESS_BOOL,
needless_borrow::NEEDLESS_BORROW,
needless_update::NEEDLESS_UPDATE,
neg_multiply::NEG_MULTIPLY,
new_without_default::NEW_WITHOUT_DEFAULT,
Expand Down
4 changes: 2 additions & 2 deletions src/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl LintPass for LifetimePass {
impl LateLintPass for LifetimePass {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node {
check_fn_inner(cx, decl, None, &generics, item.span);
check_fn_inner(cx, decl, None, generics, item.span);
}
}

Expand Down Expand Up @@ -102,7 +102,7 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g
span,
"explicit lifetimes given in parameter types where they could be elided");
}
report_extra_lifetimes(cx, decl, &generics, slf);
report_extra_lifetimes(cx, decl, generics, slf);
}

fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>,
Expand Down
10 changes: 5 additions & 5 deletions src/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E
/// Check for looping over a range and then indexing a sequence with it.
/// The iteratee must be a range literal.
fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(&arg) {
if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(arg) {
// the var must be a single name
if let PatKind::Ident(_, ref ident, _) = pat.node {
let mut visitor = VarVisitor {
Expand Down Expand Up @@ -363,7 +363,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex
};

let take: Cow<_> = if let Some(ref end) = *end {
if is_len_call(&end, &indexed) {
if is_len_call(end, &indexed) {
"".into()
} else {
format!(".take({})", snippet(cx, end.span, "..")).into()
Expand Down Expand Up @@ -422,10 +422,10 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool {

fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
// if this for loop is iterating over a two-sided range...
if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(&arg) {
if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(arg) {
// ...and both sides are compile-time constant integers...
if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start, ExprTypeChecked, None) {
if let Ok(end_idx) = eval_const_expr_partial(&cx.tcx, end, ExprTypeChecked, None) {
if let Ok(start_idx) = eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None) {
if let Ok(end_idx) = eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None) {
// ...and the start index is greater than the end index,
// this loop will never run. This is often confusing for developers
// who think that this will iterate from the larger value to the
Expand Down
6 changes: 3 additions & 3 deletions src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
let mut values = Vec::with_capacity(2 * ranges.len());

for r in ranges {
values.push(Kind::Start(r.node.0, &r));
values.push(Kind::End(r.node.1, &r));
values.push(Kind::Start(r.node.0, r));
values.push(Kind::End(r.node.1, r));
}

values.sort();
Expand All @@ -475,7 +475,7 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
}
}
(&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (),
_ => return Some((&a.range(), &b.range())),
_ => return Some((a.range(), b.range())),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ impl LateLintPass for MethodsPass {
lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]);
}

lint_or_fun_call(cx, expr, &name.node.as_str(), &args);
lint_or_fun_call(cx, expr, &name.node.as_str(), args);

let self_ty = cx.tcx.expr_ty_adjusted(&args[0]);
if args.len() == 1 && name.node.as_str() == "clone" {
Expand Down Expand Up @@ -420,7 +420,7 @@ impl LateLintPass for MethodsPass {

// check conventions w.r.t. conversion method names and predicates
let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty;
let is_copy = is_copy(cx, &ty, &item);
let is_copy = is_copy(cx, ty, item);
for &(ref conv, self_kinds) in &CONVENTIONS {
if conv.check(&name.as_str()) &&
!self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) {
Expand Down
2 changes: 1 addition & 1 deletion src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool {
match parent.node {
ExprAssign(_, ref rhs) |
ExprAssignOp(_, _, ref rhs) => **rhs == *expr,
_ => is_used(cx, &parent),
_ => is_used(cx, parent),
}
} else {
true
Expand Down
4 changes: 2 additions & 2 deletions src/mut_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ impl LateLintPass for UnnecessaryMutPassed {
If this happened, the compiler would have \
aborted the compilation long ago");
if let ExprPath(_, ref path) = fn_expr.node {
check_arguments(cx, &arguments, function_type, &path.to_string());
check_arguments(cx, arguments, function_type, &path.to_string());
}
}
ExprMethodCall(ref name, _, ref arguments) => {
let method_call = MethodCall::expr(e.id);
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
check_arguments(cx, &arguments, method_type.ty, &name.node.as_str())
check_arguments(cx, arguments, method_type.ty, &name.node.as_str())
}
_ => (),
}
Expand Down
50 changes: 50 additions & 0 deletions src/needless_borrow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! Checks for needless address of operations (`&`)
//!
//! This lint is **warn** by default

use rustc::lint::*;
use rustc::hir::*;
use rustc::ty::TyRef;
use utils::{span_lint, in_macro};

/// **What it does:** This lint checks for address of operations (`&`) that are going to be dereferenced immediately by the compiler
///
/// **Why is this bad?** Suggests that the receiver of the expression borrows the expression
///
/// **Known problems:**
///
/// **Example:** `let x: &i32 = &&&&&&5;`
declare_lint! {
pub NEEDLESS_BORROW,
Warn,
"taking a reference that is going to be automatically dereferenced"
}

#[derive(Copy,Clone)]
pub struct NeedlessBorrow;

impl LintPass for NeedlessBorrow {
fn get_lints(&self) -> LintArray {
lint_array!(NEEDLESS_BORROW)
}
}

impl LateLintPass for NeedlessBorrow {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
if in_macro(cx, e.span) {
return;
}
if let ExprAddrOf(MutImmutable, ref inner) = e.node {
if let TyRef(..) = cx.tcx.expr_ty(inner).sty {
let ty = cx.tcx.expr_ty(e);
let adj_ty = cx.tcx.expr_ty_adjusted(e);
if ty != adj_ty {
span_lint(cx,
NEEDLESS_BORROW,
e.span,
"this expression borrows a reference that is immediately dereferenced by the compiler");
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/non_expressive_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ impl EarlyLintPass for NonExpressiveNames {
let mut visitor = SimilarNamesLocalVisitor {
names: Vec::new(),
cx: cx,
lint: &self,
lint: self,
single_char_names: Vec::new(),
};
// initialize with function arguments
Expand Down
2 changes: 1 addition & 1 deletion src/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) {
let len = bindings.len();
for ref arm in arms {
for ref pat in &arm.pats {
check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
check_pat(cx, pat, &Some(&**init), pat.span, bindings);
// This is ugly, but needed to get the right type
if let Some(ref guard) = arm.guard {
check_expr(cx, guard, bindings);
Expand Down
6 changes: 3 additions & 3 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub {
err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne);
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
}
} else if match rel {
Rel::Lt => {
Expand All @@ -929,7 +929,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
}
Rel::Eq | Rel::Ne => unreachable!(),
} {
err_upcast_comparison(cx, &span, lhs, true)
err_upcast_comparison(cx, span, lhs, true)
} else if match rel {
Rel::Lt => {
if invert {
Expand All @@ -947,7 +947,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
}
Rel::Eq | Rel::Ne => unreachable!(),
} {
err_upcast_comparison(cx, &span, lhs, false)
err_upcast_comparison(cx, span, lhs, false)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/compile-fail/eta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn main() {
//~| SUGGESTION let c = Some(1u8).map({1+2; foo});
let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
//~^ WARN needless_borrow
unsafe {
Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
}
Expand Down
Loading