Skip to content

Commit 488199d

Browse files
committed
Merge pull request #884 from oli-obk/needless_ref2
Add a `needless_borrow` lint
2 parents d70e7bb + ba8653a commit 488199d

23 files changed

+120
-37
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ All notable changes to this project will be documented in this file.
149149
[`mutex_atomic`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic
150150
[`mutex_integer`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_integer
151151
[`needless_bool`]: https://github.com/Manishearth/rust-clippy/wiki#needless_bool
152+
[`needless_borrow`]: https://github.com/Manishearth/rust-clippy/wiki#needless_borrow
152153
[`needless_lifetimes`]: https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes
153154
[`needless_range_loop`]: https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop
154155
[`needless_return`]: https://github.com/Manishearth/rust-clippy/wiki#needless_return

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Table of contents:
1717

1818
## Lints
1919

20-
There are 146 lints included in this crate:
20+
There are 147 lints included in this crate:
2121

2222
name | default | meaning
2323
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -97,6 +97,7 @@ name
9797
[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead
9898
[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type
9999
[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 }`
100+
[needless_borrow](https://github.com/Manishearth/rust-clippy/wiki#needless_borrow) | warn | taking a reference that is going to be automatically dereferenced
100101
[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
101102
[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
102103
[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice

src/array_indexing.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl LateLintPass for ArrayIndexing {
6767
let size = ConstInt::Infer(size as u64);
6868

6969
// Index is a constant uint
70-
let const_index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None);
70+
let const_index = eval_const_expr_partial(cx.tcx, index, ExprTypeChecked, None);
7171
if let Ok(ConstVal::Integral(const_index)) = const_index {
7272
if size <= const_index {
7373
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds");

src/block_in_if_condition.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<'v> Visitor<'v> for ExVisitor<'v> {
5959
}
6060
};
6161
if complex {
62-
self.found_block = Some(&expr);
62+
self.found_block = Some(expr);
6363
return;
6464
}
6565
}

src/booleans.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
221221
s.push('(');
222222
}
223223
}
224-
s.push_str(&snip(&terminals[n as usize]));
224+
s.push_str(&snip(terminals[n as usize]));
225225
if brackets {
226226
if let ExprBinary(..) = terminals[n as usize].node {
227227
s.push(')');
@@ -319,7 +319,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
319319
}
320320
let mut improvements = Vec::new();
321321
'simplified: for suggestion in &simplified {
322-
let simplified_stats = terminal_stats(&suggestion);
322+
let simplified_stats = terminal_stats(suggestion);
323323
let mut improvement = false;
324324
for i in 0..32 {
325325
// ignore any "simplifications" that end up requiring a terminal more often than in the original expression

src/consts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ impl PartialOrd for Constant {
164164
}
165165
}
166166
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
167-
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r),
167+
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) |
168+
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(r),
168169
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => {
169170
match lv.partial_cmp(rv) {
170171
Some(Equal) => Some(ls.cmp(rs)),
171172
x => x,
172173
}
173174
}
174-
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l.partial_cmp(r),
175175
_ => None, //TODO: Are there any useful inter-type orderings?
176176
}
177177
}

src/copies.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) {
142142
};
143143

144144
if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node {
145-
if let Some((i, j)) = search_same(&arms, hash, eq) {
145+
if let Some((i, j)) = search_same(arms, hash, eq) {
146146
span_note_and_lint(cx,
147147
MATCH_SAME_ARMS,
148148
j.body.span,
@@ -256,8 +256,8 @@ fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)>
256256
match map.entry(hash(expr)) {
257257
Entry::Occupied(o) => {
258258
for o in o.get() {
259-
if eq(&o, expr) {
260-
return Some((&o, expr));
259+
if eq(o, expr) {
260+
return Some((o, expr));
261261
}
262262
}
263263
}

src/cyclomatic_complexity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl CyclomaticComplexity {
5858
divergence: 0,
5959
short_circuits: 0,
6060
returns: 0,
61-
tcx: &cx.tcx,
61+
tcx: cx.tcx,
6262
};
6363
helper.visit_block(block);
6464
let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper;

src/enum_variants.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ impl EarlyLintPass for EnumVariantNames {
6868
for var in &def.variants {
6969
let name = var2str(var);
7070

71-
let pre_match = partial_match(&pre, &name);
71+
let pre_match = partial_match(pre, &name);
7272
pre = &pre[..pre_match];
73-
let pre_camel = camel_case_until(&pre);
73+
let pre_camel = camel_case_until(pre);
7474
pre = &pre[..pre_camel];
7575
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
7676
if next.is_lowercase() {
@@ -82,10 +82,10 @@ impl EarlyLintPass for EnumVariantNames {
8282
}
8383
}
8484

85-
let post_match = partial_rmatch(&post, &name);
85+
let post_match = partial_rmatch(post, &name);
8686
let post_end = post.len() - post_match;
8787
post = &post[post_end..];
88-
let post_camel = camel_case_from(&post);
88+
let post_camel = camel_case_from(post);
8989
post = &post[post_camel..];
9090
}
9191
let (what, value) = match (pre.is_empty(), post.is_empty()) {

src/len_zero.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
184184
})
185185
}
186186

187-
let ty = &walk_ptrs_ty(&cx.tcx.expr_ty(expr));
187+
let ty = &walk_ptrs_ty(cx.tcx.expr_ty(expr));
188188
match ty.sty {
189189
ty::TyTrait(_) => {
190190
cx.tcx

src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub mod mut_mut;
9696
pub mod mut_reference;
9797
pub mod mutex_atomic;
9898
pub mod needless_bool;
99+
pub mod needless_borrow;
99100
pub mod needless_update;
100101
pub mod neg_multiply;
101102
pub mod new_without_default;
@@ -140,7 +141,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
140141
("clippy.toml", false)
141142
};
142143

143-
let (conf, errors) = utils::conf::read_conf(&file_name, must_exist);
144+
let (conf, errors) = utils::conf::read_conf(file_name, must_exist);
144145

145146
// all conf errors are non-fatal, we just use the default conf in case of error
146147
for error in errors {
@@ -210,6 +211,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
210211
reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass);
211212
reg.register_late_lint_pass(box mutex_atomic::MutexAtomic);
212213
reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass);
214+
reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow);
213215
reg.register_late_lint_pass(box no_effect::NoEffectPass);
214216
reg.register_late_lint_pass(box map_clone::MapClonePass);
215217
reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass);
@@ -364,6 +366,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
364366
mutex_atomic::MUTEX_ATOMIC,
365367
needless_bool::BOOL_COMPARISON,
366368
needless_bool::NEEDLESS_BOOL,
369+
needless_borrow::NEEDLESS_BORROW,
367370
needless_update::NEEDLESS_UPDATE,
368371
neg_multiply::NEG_MULTIPLY,
369372
new_without_default::NEW_WITHOUT_DEFAULT,

src/lifetimes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl LintPass for LifetimePass {
4646
impl LateLintPass for LifetimePass {
4747
fn check_item(&mut self, cx: &LateContext, item: &Item) {
4848
if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node {
49-
check_fn_inner(cx, decl, None, &generics, item.span);
49+
check_fn_inner(cx, decl, None, generics, item.span);
5050
}
5151
}
5252

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

108108
fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>,

src/loops.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E
328328
/// Check for looping over a range and then indexing a sequence with it.
329329
/// The iteratee must be a range literal.
330330
fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
331-
if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(&arg) {
331+
if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(arg) {
332332
// the var must be a single name
333333
if let PatKind::Ident(_, ref ident, _) = pat.node {
334334
let mut visitor = VarVisitor {
@@ -363,7 +363,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex
363363
};
364364

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

423423
fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
424424
// if this for loop is iterating over a two-sided range...
425-
if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(&arg) {
425+
if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(arg) {
426426
// ...and both sides are compile-time constant integers...
427-
if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start, ExprTypeChecked, None) {
428-
if let Ok(end_idx) = eval_const_expr_partial(&cx.tcx, end, ExprTypeChecked, None) {
427+
if let Ok(start_idx) = eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None) {
428+
if let Ok(end_idx) = eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None) {
429429
// ...and the start index is greater than the end index,
430430
// this loop will never run. This is often confusing for developers
431431
// who think that this will iterate from the larger value to the

src/matches.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,8 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
461461
let mut values = Vec::with_capacity(2 * ranges.len());
462462

463463
for r in ranges {
464-
values.push(Kind::Start(r.node.0, &r));
465-
values.push(Kind::End(r.node.1, &r));
464+
values.push(Kind::Start(r.node.0, r));
465+
values.push(Kind::End(r.node.1, r));
466466
}
467467

468468
values.sort();
@@ -475,7 +475,7 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
475475
}
476476
}
477477
(&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (),
478-
_ => return Some((&a.range(), &b.range())),
478+
_ => return Some((a.range(), b.range())),
479479
}
480480
}
481481

src/methods.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ impl LateLintPass for MethodsPass {
365365
lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]);
366366
}
367367

368-
lint_or_fun_call(cx, expr, &name.node.as_str(), &args);
368+
lint_or_fun_call(cx, expr, &name.node.as_str(), args);
369369

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

421421
// check conventions w.r.t. conversion method names and predicates
422422
let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty;
423-
let is_copy = is_copy(cx, &ty, &item);
423+
let is_copy = is_copy(cx, ty, item);
424424
for &(ref conv, self_kinds) in &CONVENTIONS {
425425
if conv.check(&name.as_str()) &&
426426
!self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) {

src/misc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool {
424424
match parent.node {
425425
ExprAssign(_, ref rhs) |
426426
ExprAssignOp(_, _, ref rhs) => **rhs == *expr,
427-
_ => is_used(cx, &parent),
427+
_ => is_used(cx, parent),
428428
}
429429
} else {
430430
true

src/mut_reference.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ impl LateLintPass for UnnecessaryMutPassed {
3939
If this happened, the compiler would have \
4040
aborted the compilation long ago");
4141
if let ExprPath(_, ref path) = fn_expr.node {
42-
check_arguments(cx, &arguments, function_type, &path.to_string());
42+
check_arguments(cx, arguments, function_type, &path.to_string());
4343
}
4444
}
4545
ExprMethodCall(ref name, _, ref arguments) => {
4646
let method_call = MethodCall::expr(e.id);
4747
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
48-
check_arguments(cx, &arguments, method_type.ty, &name.node.as_str())
48+
check_arguments(cx, arguments, method_type.ty, &name.node.as_str())
4949
}
5050
_ => (),
5151
}

src/needless_borrow.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//! Checks for needless address of operations (`&`)
2+
//!
3+
//! This lint is **warn** by default
4+
5+
use rustc::lint::*;
6+
use rustc::hir::*;
7+
use rustc::ty::TyRef;
8+
use utils::{span_lint, in_macro};
9+
10+
/// **What it does:** This lint checks for address of operations (`&`) that are going to be dereferenced immediately by the compiler
11+
///
12+
/// **Why is this bad?** Suggests that the receiver of the expression borrows the expression
13+
///
14+
/// **Known problems:**
15+
///
16+
/// **Example:** `let x: &i32 = &&&&&&5;`
17+
declare_lint! {
18+
pub NEEDLESS_BORROW,
19+
Warn,
20+
"taking a reference that is going to be automatically dereferenced"
21+
}
22+
23+
#[derive(Copy,Clone)]
24+
pub struct NeedlessBorrow;
25+
26+
impl LintPass for NeedlessBorrow {
27+
fn get_lints(&self) -> LintArray {
28+
lint_array!(NEEDLESS_BORROW)
29+
}
30+
}
31+
32+
impl LateLintPass for NeedlessBorrow {
33+
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
34+
if in_macro(cx, e.span) {
35+
return;
36+
}
37+
if let ExprAddrOf(MutImmutable, ref inner) = e.node {
38+
if let TyRef(..) = cx.tcx.expr_ty(inner).sty {
39+
let ty = cx.tcx.expr_ty(e);
40+
let adj_ty = cx.tcx.expr_ty_adjusted(e);
41+
if ty != adj_ty {
42+
span_lint(cx,
43+
NEEDLESS_BORROW,
44+
e.span,
45+
"this expression borrows a reference that is immediately dereferenced by the compiler");
46+
}
47+
}
48+
}
49+
}
50+
}

src/non_expressive_names.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ impl EarlyLintPass for NonExpressiveNames {
249249
let mut visitor = SimilarNamesLocalVisitor {
250250
names: Vec::new(),
251251
cx: cx,
252-
lint: &self,
252+
lint: self,
253253
single_char_names: Vec::new(),
254254
};
255255
// initialize with function arguments

src/shadow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) {
278278
let len = bindings.len();
279279
for ref arm in arms {
280280
for ref pat in &arm.pats {
281-
check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
281+
check_pat(cx, pat, &Some(&**init), pat.span, bindings);
282282
// This is ugly, but needed to get the right type
283283
if let Some(ref guard) = arm.guard {
284284
check_expr(cx, guard, bindings);

src/types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
910910
if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
911911
if rel == Rel::Eq || rel == Rel::Ne {
912912
if norm_rhs_val < lb || norm_rhs_val > ub {
913-
err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne);
913+
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
914914
}
915915
} else if match rel {
916916
Rel::Lt => {
@@ -929,7 +929,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
929929
}
930930
Rel::Eq | Rel::Ne => unreachable!(),
931931
} {
932-
err_upcast_comparison(cx, &span, lhs, true)
932+
err_upcast_comparison(cx, span, lhs, true)
933933
} else if match rel {
934934
Rel::Lt => {
935935
if invert {
@@ -947,7 +947,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
947947
}
948948
Rel::Eq | Rel::Ne => unreachable!(),
949949
} {
950-
err_upcast_comparison(cx, &span, lhs, false)
950+
err_upcast_comparison(cx, span, lhs, false)
951951
}
952952
}
953953
}

tests/compile-fail/eta.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ fn main() {
1818
//~| SUGGESTION let c = Some(1u8).map({1+2; foo});
1919
let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
2020
all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
21+
//~^ WARN needless_borrow
2122
unsafe {
2223
Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
2324
}

0 commit comments

Comments
 (0)