add box-default
lint
This commit is contained in:
parent
7248d06384
commit
63f441ec85
@ -3609,6 +3609,7 @@ Released 2018-09-13
|
||||
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
|
||||
[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
|
||||
[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
|
||||
[`box_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_default
|
||||
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
|
||||
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
|
||||
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
|
||||
|
61
clippy_lints/src/box_default.rs
Normal file
61
clippy_lints/src/box_default.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use clippy_utils::{diagnostics::span_lint_and_help, is_default_equivalent, path_def_id};
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// checks for `Box::new(T::default())`, which is better written as
|
||||
/// `Box::<T>::default()`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// First, it's more complex, involving two calls instead of one.
|
||||
/// Second, `Box::default()` can be faster
|
||||
/// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
|
||||
///
|
||||
/// ### Known problems
|
||||
/// The lint may miss some cases (e.g. Box::new(String::from(""))).
|
||||
/// On the other hand, it will trigger on cases where the `default`
|
||||
/// code comes from a macro that does something different based on
|
||||
/// e.g. target operating system.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let x: Box<String> = Box::new(Default::default());
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let x: Box<String> = Box::default();
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub BOX_DEFAULT,
|
||||
perf,
|
||||
"Using Box::new(T::default()) instead of Box::default()"
|
||||
}
|
||||
|
||||
declare_lint_pass!(BoxDefault => [BOX_DEFAULT]);
|
||||
|
||||
impl LateLintPass<'_> for BoxDefault {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::Call(box_new, [arg]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
|
||||
&& let ExprKind::Call(..) = arg.kind
|
||||
&& !in_external_macro(cx.sess(), expr.span)
|
||||
&& expr.span.eq_ctxt(arg.span)
|
||||
&& seg.ident.name == sym::new
|
||||
&& path_def_id(cx, ty) == cx.tcx.lang_items().owned_box()
|
||||
&& is_default_equivalent(cx, arg)
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
BOX_DEFAULT,
|
||||
expr.span,
|
||||
"`Box::new(_)` of default value",
|
||||
None,
|
||||
"use `Box::default()` instead",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec.
|
||||
|
||||
### Known problems
|
||||
The lint may miss some cases (e.g. Box::new(String::from(""))).
|
||||
On the other hand, it will trigger on cases where the `default`
|
||||
code comes from a macro that does something different based on
|
||||
e.g. target operating system.
|
||||
|
||||
### Example
|
||||
```
|
||||
let x: Box<String> = Box::new(Default::default());
|
||||
```
|
||||
Use instead:
|
||||
```
|
||||
let x: Box<String> = Box::default();
|
||||
```
|
@ -15,7 +15,7 @@ macro_rules! boxit {
|
||||
}
|
||||
|
||||
fn test_macro() {
|
||||
boxit!(Vec::new(), Vec<u8>);
|
||||
boxit!(vec![1], Vec<u8>);
|
||||
}
|
||||
|
||||
fn test1(foo: Box<Vec<bool>>) {}
|
||||
@ -50,7 +50,7 @@ fn test_local_not_linted() {
|
||||
pub fn pub_test(foo: Box<Vec<bool>>) {}
|
||||
|
||||
pub fn pub_test_ret() -> Box<Vec<bool>> {
|
||||
Box::new(Vec::new())
|
||||
Box::default()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
31
tests/ui/box_default.rs
Normal file
31
tests/ui/box_default.rs
Normal file
@ -0,0 +1,31 @@
|
||||
#![warn(clippy::box_default)]
|
||||
|
||||
#[derive(Default)]
|
||||
struct ImplementsDefault;
|
||||
|
||||
struct OwnDefault;
|
||||
|
||||
impl OwnDefault {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! outer {
|
||||
($e: expr) => {
|
||||
$e
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _string: Box<String> = Box::new(Default::default());
|
||||
let _byte = Box::new(u8::default());
|
||||
let _vec = Box::new(Vec::<u8>::new());
|
||||
let _impl = Box::new(ImplementsDefault::default());
|
||||
let _impl2 = Box::new(<ImplementsDefault as Default>::default());
|
||||
let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
|
||||
let _own = Box::new(OwnDefault::default()); // should not lint
|
||||
let _in_macro = outer!(Box::new(String::new()));
|
||||
// false negative: default is from different expansion
|
||||
let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
|
||||
}
|
59
tests/ui/box_default.stderr
Normal file
59
tests/ui/box_default.stderr
Normal file
@ -0,0 +1,59 @@
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:21:32
|
||||
|
|
||||
LL | let _string: Box<String> = Box::new(Default::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::box-default` implied by `-D warnings`
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:22:17
|
||||
|
|
||||
LL | let _byte = Box::new(u8::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:23:16
|
||||
|
|
||||
LL | let _vec = Box::new(Vec::<u8>::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:24:17
|
||||
|
|
||||
LL | let _impl = Box::new(ImplementsDefault::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:25:18
|
||||
|
|
||||
LL | let _impl2 = Box::new(<ImplementsDefault as Default>::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:26:42
|
||||
|
|
||||
LL | let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: `Box::new(_)` of default value
|
||||
--> $DIR/box_default.rs:28:28
|
||||
|
|
||||
LL | let _in_macro = outer!(Box::new(String::new()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `Box::default()` instead
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user