use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::attr::IntType;
use syntax::codemap::Span;
-use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint,
+use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, span_lint_and_then,
opt_def_id, last_path_segment, type_size};
use utils::paths;
structure like a VecDeque"
}
+/// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
+///
+/// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more general.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+/// ```rust
+/// fn foo(bar: &Box<T>) { ... }
+/// ```
+declare_lint! {
+ pub BORROWED_BOX,
+ Warn,
+ "a borrow of a boxed type"
+}
+
impl LintPass for TypePass {
fn get_lints(&self) -> LintArray {
- lint_array!(BOX_VEC, LINKEDLIST)
+ lint_array!(BOX_VEC, LINKEDLIST, BORROWED_BOX)
}
}
}
fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) {
- check_ty(cx, &field.ty);
+ check_ty(cx, &field.ty, false);
}
fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
match item.node {
TraitItemKind::Const(ref ty, _) |
- TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty),
+ TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty, false),
TraitItemKind::Method(ref sig, _) => check_fn_decl(cx, &sig.decl),
_ => (),
}
}
+
+ fn check_local(&mut self, cx: &LateContext, local: &Local) {
+ if let Some(ref ty) = local.ty {
+ check_ty(cx, ty, true);
+ }
+ }
}
fn check_fn_decl(cx: &LateContext, decl: &FnDecl) {
for input in &decl.inputs {
- check_ty(cx, input);
+ check_ty(cx, input, false);
}
if let FunctionRetTy::Return(ref ty) = decl.output {
- check_ty(cx, ty);
+ check_ty(cx, ty, false);
}
}
-fn check_ty(cx: &LateContext, ast_ty: &hir::Ty) {
+/// Recursively check for `TypePass` lints in the given type. Stop at the first
+/// lint found.
+///
+/// The parameter `is_local` distinguishes the context of the type; types from
+/// local bindings should only be checked for the `BORROWED_BOX` lint.
+fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
if in_macro(ast_ty.span) {
return;
}
match ast_ty.node {
- TyPath(ref qpath) => {
+ TyPath(ref qpath) if !is_local => {
let def = cx.tables.qpath_def(qpath, ast_ty.id);
if let Some(def_id) = opt_def_id(def) {
if Some(def_id) == cx.tcx.lang_items.owned_box() {
}
match *qpath {
QPath::Resolved(Some(ref ty), ref p) => {
- check_ty(cx, ty);
+ check_ty(cx, ty, is_local);
for ty in p.segments.iter().flat_map(|seg| seg.parameters.types()) {
- check_ty(cx, ty);
+ check_ty(cx, ty, is_local);
}
},
QPath::Resolved(None, ref p) => {
for ty in p.segments.iter().flat_map(|seg| seg.parameters.types()) {
- check_ty(cx, ty);
+ check_ty(cx, ty, is_local);
}
},
QPath::TypeRelative(ref ty, ref seg) => {
- check_ty(cx, ty);
+ check_ty(cx, ty, is_local);
for ty in seg.parameters.types() {
- check_ty(cx, ty);
+ check_ty(cx, ty, is_local);
}
},
}
},
+ TyRptr(ref lt, MutTy { ref ty, ref mutbl }) => {
+ match ty.node {
+ TyPath(ref qpath) => {
+ let def = cx.tables.qpath_def(qpath, ast_ty.id);
+ if_let_chain! {[
+ let Some(def_id) = opt_def_id(def),
+ Some(def_id) == cx.tcx.lang_items.owned_box(),
+ let QPath::Resolved(None, ref path) = *qpath,
+ let [ref bx] = *path.segments,
+ let PathParameters::AngleBracketedParameters(ref ab_data) = bx.parameters,
+ let [ref inner] = *ab_data.types
+ ], {
+ let ltopt = if lt.is_elided() {
+ "".to_owned()
+ } else {
+ format!("{} ", lt.name.as_str())
+ };
+ let mutopt = if *mutbl == Mutability::MutMutable {
+ "mut "
+ } else {
+ ""
+ };
+ span_lint_and_then(cx,
+ BORROWED_BOX,
+ ast_ty.span,
+ "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
+ |db| {
+ db.span_suggestion(ast_ty.span,
+ "try",
+ format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, "..")));
+ }
+ );
+ return; // don't recurse into the type
+ }};
+ check_ty(cx, ty, is_local);
+ },
+ _ => check_ty(cx, ty, is_local),
+ }
+ },
// recurse
TySlice(ref ty) |
TyArray(ref ty, _) |
- TyPtr(MutTy { ref ty, .. }) |
- TyRptr(_, MutTy { ref ty, .. }) => check_ty(cx, ty),
+ TyPtr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local),
TyTup(ref tys) => {
for ty in tys {
- check_ty(cx, ty);
+ check_ty(cx, ty, is_local);
}
},
_ => {},