Skip to content

Commit 7056018

Browse files
authored
Merge pull request #1501 from scott-linder/types-borrow-box
Types borrow box
2 parents 92fac4a + 5db8647 commit 7056018

File tree

8 files changed

+163
-16
lines changed

8 files changed

+163
-16
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ All notable changes to this project will be documented in this file.
364364
[`block_in_if_condition_expr`]: https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr
365365
[`block_in_if_condition_stmt`]: https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt
366366
[`bool_comparison`]: https://github.com/Manishearth/rust-clippy/wiki#bool_comparison
367+
[`borrowed_box`]: https://github.com/Manishearth/rust-clippy/wiki#borrowed_box
367368
[`box_vec`]: https://github.com/Manishearth/rust-clippy/wiki#box_vec
368369
[`boxed_local`]: https://github.com/Manishearth/rust-clippy/wiki#boxed_local
369370
[`builtin_type_shadow`]: https://github.com/Manishearth/rust-clippy/wiki#builtin_type_shadow

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ name
194194
[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces that can be eliminated in conditions, e.g. `if { true } ...`
195195
[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | complex blocks in conditions, e.g. `if { let x = true; x } ...`
196196
[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true`
197+
[borrowed_box](https://github.com/Manishearth/rust-clippy/wiki#borrowed_box) | warn | a borrow of a boxed type
197198
[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap
198199
[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using `Box<T>` where unnecessary
199200
[builtin_type_shadow](https://github.com/Manishearth/rust-clippy/wiki#builtin_type_shadow) | warn | shadowing a builtin type

clippy_lints/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
506506
transmute::USELESS_TRANSMUTE,
507507
transmute::WRONG_TRANSMUTE,
508508
types::ABSURD_EXTREME_COMPARISONS,
509+
types::BORROWED_BOX,
509510
types::BOX_VEC,
510511
types::CHAR_LIT_AS_U8,
511512
types::LET_UNIT_VALUE,

clippy_lints/src/types.rs

+81-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::cmp::Ordering;
88
use syntax::ast::{IntTy, UintTy, FloatTy};
99
use syntax::attr::IntType;
1010
use syntax::codemap::Span;
11-
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint,
11+
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, span_lint_and_then,
1212
opt_def_id, last_path_segment, type_size};
1313
use utils::paths;
1414

@@ -65,9 +65,25 @@ declare_lint! {
6565
structure like a VecDeque"
6666
}
6767

68+
/// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
69+
///
70+
/// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more general.
71+
///
72+
/// **Known problems:** None.
73+
///
74+
/// **Example:**
75+
/// ```rust
76+
/// fn foo(bar: &Box<T>) { ... }
77+
/// ```
78+
declare_lint! {
79+
pub BORROWED_BOX,
80+
Warn,
81+
"a borrow of a boxed type"
82+
}
83+
6884
impl LintPass for TypePass {
6985
fn get_lints(&self) -> LintArray {
70-
lint_array!(BOX_VEC, LINKEDLIST)
86+
lint_array!(BOX_VEC, LINKEDLIST, BORROWED_BOX)
7187
}
7288
}
7389

@@ -84,35 +100,46 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass {
84100
}
85101

86102
fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) {
87-
check_ty(cx, &field.ty);
103+
check_ty(cx, &field.ty, false);
88104
}
89105

90106
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
91107
match item.node {
92108
TraitItemKind::Const(ref ty, _) |
93-
TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty),
109+
TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty, false),
94110
TraitItemKind::Method(ref sig, _) => check_fn_decl(cx, &sig.decl),
95111
_ => (),
96112
}
97113
}
114+
115+
fn check_local(&mut self, cx: &LateContext, local: &Local) {
116+
if let Some(ref ty) = local.ty {
117+
check_ty(cx, ty, true);
118+
}
119+
}
98120
}
99121

100122
fn check_fn_decl(cx: &LateContext, decl: &FnDecl) {
101123
for input in &decl.inputs {
102-
check_ty(cx, input);
124+
check_ty(cx, input, false);
103125
}
104126

105127
if let FunctionRetTy::Return(ref ty) = decl.output {
106-
check_ty(cx, ty);
128+
check_ty(cx, ty, false);
107129
}
108130
}
109131

110-
fn check_ty(cx: &LateContext, ast_ty: &hir::Ty) {
132+
/// Recursively check for `TypePass` lints in the given type. Stop at the first
133+
/// lint found.
134+
///
135+
/// The parameter `is_local` distinguishes the context of the type; types from
136+
/// local bindings should only be checked for the `BORROWED_BOX` lint.
137+
fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
111138
if in_macro(ast_ty.span) {
112139
return;
113140
}
114141
match ast_ty.node {
115-
TyPath(ref qpath) => {
142+
TyPath(ref qpath) if !is_local => {
116143
let def = cx.tables.qpath_def(qpath, ast_ty.id);
117144
if let Some(def_id) = opt_def_id(def) {
118145
if Some(def_id) == cx.tcx.lang_items.owned_box() {
@@ -143,32 +170,70 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty) {
143170
}
144171
match *qpath {
145172
QPath::Resolved(Some(ref ty), ref p) => {
146-
check_ty(cx, ty);
173+
check_ty(cx, ty, is_local);
147174
for ty in p.segments.iter().flat_map(|seg| seg.parameters.types()) {
148-
check_ty(cx, ty);
175+
check_ty(cx, ty, is_local);
149176
}
150177
},
151178
QPath::Resolved(None, ref p) => {
152179
for ty in p.segments.iter().flat_map(|seg| seg.parameters.types()) {
153-
check_ty(cx, ty);
180+
check_ty(cx, ty, is_local);
154181
}
155182
},
156183
QPath::TypeRelative(ref ty, ref seg) => {
157-
check_ty(cx, ty);
184+
check_ty(cx, ty, is_local);
158185
for ty in seg.parameters.types() {
159-
check_ty(cx, ty);
186+
check_ty(cx, ty, is_local);
160187
}
161188
},
162189
}
163190
},
191+
TyRptr(ref lt, MutTy { ref ty, ref mutbl }) => {
192+
match ty.node {
193+
TyPath(ref qpath) => {
194+
let def = cx.tables.qpath_def(qpath, ast_ty.id);
195+
if_let_chain! {[
196+
let Some(def_id) = opt_def_id(def),
197+
Some(def_id) == cx.tcx.lang_items.owned_box(),
198+
let QPath::Resolved(None, ref path) = *qpath,
199+
let [ref bx] = *path.segments,
200+
let PathParameters::AngleBracketedParameters(ref ab_data) = bx.parameters,
201+
let [ref inner] = *ab_data.types
202+
], {
203+
let ltopt = if lt.is_elided() {
204+
"".to_owned()
205+
} else {
206+
format!("{} ", lt.name.as_str())
207+
};
208+
let mutopt = if *mutbl == Mutability::MutMutable {
209+
"mut "
210+
} else {
211+
""
212+
};
213+
span_lint_and_then(cx,
214+
BORROWED_BOX,
215+
ast_ty.span,
216+
"you seem to be trying to use `&Box<T>`. Consider using just `&T`",
217+
|db| {
218+
db.span_suggestion(ast_ty.span,
219+
"try",
220+
format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, "..")));
221+
}
222+
);
223+
return; // don't recurse into the type
224+
}};
225+
check_ty(cx, ty, is_local);
226+
},
227+
_ => check_ty(cx, ty, is_local),
228+
}
229+
},
164230
// recurse
165231
TySlice(ref ty) |
166232
TyArray(ref ty, _) |
167-
TyPtr(MutTy { ref ty, .. }) |
168-
TyRptr(_, MutTy { ref ty, .. }) => check_ty(cx, ty),
233+
TyPtr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local),
169234
TyTup(ref tys) => {
170235
for ty in tys {
171-
check_ty(cx, ty);
236+
check_ty(cx, ty, is_local);
172237
}
173238
},
174239
_ => {},

clippy_tests/examples/borrow_box.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
4+
#![deny(borrowed_box)]
5+
#![allow(blacklisted_name)]
6+
#![allow(unused_variables)]
7+
#![allow(dead_code)]
8+
9+
pub fn test1(foo: &mut Box<bool>) {
10+
println!("{:?}", foo)
11+
}
12+
13+
pub fn test2() {
14+
let foo: &Box<bool>;
15+
}
16+
17+
struct Test3<'a> {
18+
foo: &'a Box<bool>
19+
}
20+
21+
trait Test4 {
22+
fn test4(a: &Box<bool>);
23+
}
24+
25+
impl<'a> Test4 for Test3<'a> {
26+
fn test4(a: &Box<bool>) {
27+
unimplemented!();
28+
}
29+
}
30+
31+
fn main(){
32+
test1(&mut Box::new(false));
33+
test2();
34+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
2+
--> borrow_box.rs:9:19
3+
|
4+
9 | pub fn test1(foo: &mut Box<bool>) {
5+
| ^^^^^^^^^^^^^^ help: try `&mut bool`
6+
|
7+
note: lint level defined here
8+
--> borrow_box.rs:4:9
9+
|
10+
4 | #![deny(borrowed_box)]
11+
| ^^^^^^^^^^^^
12+
13+
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
14+
--> borrow_box.rs:14:14
15+
|
16+
14 | let foo: &Box<bool>;
17+
| ^^^^^^^^^^ help: try `&bool`
18+
19+
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
20+
--> borrow_box.rs:18:10
21+
|
22+
18 | foo: &'a Box<bool>
23+
| ^^^^^^^^^^^^^ help: try `&'a bool`
24+
25+
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
26+
--> borrow_box.rs:22:17
27+
|
28+
22 | fn test4(a: &Box<bool>);
29+
| ^^^^^^^^^^ help: try `&bool`
30+
31+
error: aborting due to previous error(s)
32+
33+
error: Could not compile `clippy_tests`.
34+
35+
To learn more, run the command again with --verbose.

clippy_tests/examples/box_vec.rs

+5
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ pub fn test2(foo: Box<Fn(Vec<u32>)>) { // pass if #31 is fixed
2222
foo(vec![1, 2, 3])
2323
}
2424

25+
pub fn test_local_not_linted() {
26+
let _: Box<Vec<bool>>;
27+
}
28+
2529
fn main(){
2630
test(Box::new(Vec::new()));
2731
test2(Box::new(|v| println!("{:?}", v)));
2832
test_macro();
33+
test_local_not_linted();
2934
}

clippy_tests/examples/dlist.rs

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ pub fn test_ret() -> Option<LinkedList<u8>> {
3434
unimplemented!();
3535
}
3636

37+
pub fn test_local_not_linted() {
38+
let _: LinkedList<u8>;
39+
}
40+
3741
fn main(){
3842
test(LinkedList::new());
43+
test_local_not_linted();
3944
}

0 commit comments

Comments
 (0)