Fix ICE in vec_box lint and add run-rustfix

`hir::Ty` doesn't seem to know anything about type bounds and
`cx.tcx.type_of(def_id)` caused an ICE when it was passed a generic type
with a bound:

```
src/librustc_typeck/collect.rs:1311: unexpected non-type Node::GenericParam: Type { default: None, synthetic: None }
```

Converting it to a proper `Ty` fixes the ICE and catches a few more
places where the lint applies.
This commit is contained in:
Philipp Hansch 2019-02-01 08:21:32 +01:00
parent 5176a5c4b7
commit 4aff8711f0
No known key found for this signature in database
GPG Key ID: B6FA06A6E0E2665B
5 changed files with 96 additions and 31 deletions

View File

@ -275,28 +275,26 @@ fn check_ty(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool) {
if Some(def_id) == cx.tcx.lang_items().owned_box(); if Some(def_id) == cx.tcx.lang_items().owned_box();
// At this point, we know ty is Box<T>, now get T // At this point, we know ty is Box<T>, now get T
if let Some(ref last) = last_path_segment(ty_qpath).args; if let Some(ref last) = last_path_segment(ty_qpath).args;
if let Some(ty) = last.args.iter().find_map(|arg| match arg { if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty), GenericArg::Type(ty) => Some(ty),
GenericArg::Lifetime(_) => None, GenericArg::Lifetime(_) => None,
}); });
if let TyKind::Path(ref ty_qpath) = ty.node;
let def = cx.tables.qpath_def(ty_qpath, ty.hir_id);
if let Some(def_id) = opt_def_id(def);
let boxed_type = cx.tcx.type_of(def_id);
if boxed_type.is_sized(cx.tcx.at(ty.span), cx.param_env);
then { then {
let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env) {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
VEC_BOX, VEC_BOX,
hir_ty.span, hir_ty.span,
"`Vec<T>` is already on the heap, the boxing is unnecessary.", "`Vec<T>` is already on the heap, the boxing is unnecessary.",
"try", "try",
format!("Vec<{}>", boxed_type), format!("Vec<{}>", ty_ty),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
return; // don't recurse into the type return; // don't recurse into the type
} }
} }
}
} else if match_def_path(cx.tcx, def_id, &paths::OPTION) { } else if match_def_path(cx.tcx, def_id, &paths::OPTION) {
if match_type_parameter(cx, qpath, &paths::OPTION) { if match_type_parameter(cx, qpath, &paths::OPTION) {
span_lint( span_lint(

View File

@ -1,5 +1,5 @@
#![warn(clippy::all)] #![warn(clippy::all)]
#![allow(unused, clippy::needless_pass_by_value)] #![allow(unused, clippy::needless_pass_by_value, clippy::vec_box)]
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here

View File

@ -0,0 +1,36 @@
// run-rustfix
#![allow(dead_code)]
struct SizedStruct(i32);
struct UnsizedStruct([i32]);
/// The following should trigger the lint
mod should_trigger {
use super::SizedStruct;
struct StructWithVecBox {
sized_type: Vec<SizedStruct>,
}
struct A(Vec<SizedStruct>);
struct B(Vec<Vec<u32>>);
}
/// The following should not trigger the lint
mod should_not_trigger {
use super::UnsizedStruct;
struct C(Vec<Box<UnsizedStruct>>);
struct StructWithVecBoxButItsUnsized {
unsized_type: Vec<Box<UnsizedStruct>>,
}
struct TraitVec<T: ?Sized> {
// Regression test for #3720. This was causing an ICE.
inner: Vec<Box<T>>,
}
}
fn main() {}

View File

@ -1,17 +1,36 @@
struct SizedStruct { // run-rustfix
_a: i32,
}
struct UnsizedStruct { #![allow(dead_code)]
_a: [i32],
} struct SizedStruct(i32);
struct UnsizedStruct([i32]);
/// The following should trigger the lint
mod should_trigger {
use super::SizedStruct;
struct StructWithVecBox { struct StructWithVecBox {
sized_type: Vec<Box<SizedStruct>>, sized_type: Vec<Box<SizedStruct>>,
} }
struct A(Vec<Box<SizedStruct>>);
struct B(Vec<Vec<Box<(u32)>>>);
}
/// The following should not trigger the lint
mod should_not_trigger {
use super::UnsizedStruct;
struct C(Vec<Box<UnsizedStruct>>);
struct StructWithVecBoxButItsUnsized { struct StructWithVecBoxButItsUnsized {
unsized_type: Vec<Box<UnsizedStruct>>, unsized_type: Vec<Box<UnsizedStruct>>,
} }
struct TraitVec<T: ?Sized> {
// Regression test for #3720. This was causing an ICE.
inner: Vec<Box<T>>,
}
}
fn main() {} fn main() {}

View File

@ -1,10 +1,22 @@
error: `Vec<T>` is already on the heap, the boxing is unnecessary. error: `Vec<T>` is already on the heap, the boxing is unnecessary.
--> $DIR/vec_box_sized.rs:10:17 --> $DIR/vec_box_sized.rs:13:21
| |
LL | sized_type: Vec<Box<SizedStruct>>, LL | sized_type: Vec<Box<SizedStruct>>,
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>` | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
| |
= note: `-D clippy::vec-box` implied by `-D warnings` = note: `-D clippy::vec-box` implied by `-D warnings`
error: aborting due to previous error error: `Vec<T>` is already on the heap, the boxing is unnecessary.
--> $DIR/vec_box_sized.rs:16:14
|
LL | struct A(Vec<Box<SizedStruct>>);
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
error: `Vec<T>` is already on the heap, the boxing is unnecessary.
--> $DIR/vec_box_sized.rs:17:18
|
LL | struct B(Vec<Vec<Box<(u32)>>>);
| ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
error: aborting due to 3 previous errors