diff --git a/CHANGELOG.md b/CHANGELOG.md index bd3a04e34ae..12d4918ca55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5891,6 +5891,7 @@ Released 2018-09-13 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index fe0e9b80b11..f6af9810ca1 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -132,6 +132,16 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` * [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) +## `allow-useless-vec-in-tests` +Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) + + ## `allowed-dotfiles` Additional dotfiles (files or directories starting with a dot) to allow diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index bbce4180dc4..5cfcbdb57d7 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -463,6 +463,10 @@ define_Conf! { /// /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` (allow_print_in_tests: bool = false), + /// Lint: USELESS_VEC. + /// + /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + (allow_useless_vec_in_tests: bool = false), /// Lint: RESULT_LARGE_ERR. /// /// The maximum size of the `Err`-variant in a `Result` returned from a function diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index e2296767431..db593726604 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, Node}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -63,7 +63,7 @@ impl LateLintPass<'_> for DbgMacro { !in_external_macro(cx.sess(), macro_call.span) && self.checked_dbg_call_site.insert(macro_call.span) && // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml - !(self.allow_dbg_in_tests && is_in_test(cx, expr.hir_id)) + !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id)) { let mut applicability = Applicability::MachineApplicable; @@ -129,10 +129,6 @@ impl LateLintPass<'_> for DbgMacro { } } -fn is_in_test(cx: &LateContext<'_>, hir_id: HirId) -> bool { - is_in_test_function(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id) -} - fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e2aac58bf97..2c44c3881aa 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -535,6 +535,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_print_in_tests, allow_private_module_inception, allow_unwrap_in_tests, + allow_useless_vec_in_tests, ref allowed_dotfiles, ref allowed_idents_below_min_chars, ref allowed_scripts, @@ -754,6 +755,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { too_large_for_stack, msrv: msrv(), span_to_lint_map: BTreeMap::new(), + allow_in_test: allow_useless_vec_in_tests, }) }); store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 27ead55bf39..9edf7579d48 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -7,7 +7,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_trait_method}; +use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -22,6 +22,7 @@ pub struct UselessVec { pub too_large_for_stack: u64, pub msrv: Msrv, pub span_to_lint_map: BTreeMap>, + pub allow_in_test: bool, } declare_clippy_lint! { @@ -57,6 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) else { return; }; + if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) { + return; + }; // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!` let callsite = expr.span.parent_callsite().unwrap_or(expr.span); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fccd75d8153..26ee5225f99 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2548,6 +2548,11 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { .any(|parent_id| is_cfg_test(tcx, parent_id)) } +/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]` +pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { + is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id) +} + /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let hir = tcx.hir(); diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 24645b61fdb..722e9b3bc8d 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -11,6 +11,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars @@ -91,6 +92,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars @@ -171,6 +173,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars diff --git a/tests/ui-toml/useless_vec/clippy.toml b/tests/ui-toml/useless_vec/clippy.toml new file mode 100644 index 00000000000..230ca2d0ab7 --- /dev/null +++ b/tests/ui-toml/useless_vec/clippy.toml @@ -0,0 +1 @@ +allow-useless-vec-in-tests = true diff --git a/tests/ui-toml/useless_vec/useless_vec.fixed b/tests/ui-toml/useless_vec/useless_vec.fixed new file mode 100644 index 00000000000..08323a0dcc9 --- /dev/null +++ b/tests/ui-toml/useless_vec/useless_vec.fixed @@ -0,0 +1,26 @@ +//@compile-flags: --test +#![warn(clippy::useless_vec)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(_: &[u32]) {} + +fn main() { + foo(&[1_u32]); +} + +#[test] +pub fn in_test() { + foo(&vec![2_u32]); +} + +#[cfg(test)] +fn in_cfg_test() { + foo(&vec![3_u32]); +} + +#[cfg(test)] +mod mod1 { + fn in_cfg_test_mod() { + super::foo(&vec![4_u32]); + } +} diff --git a/tests/ui-toml/useless_vec/useless_vec.rs b/tests/ui-toml/useless_vec/useless_vec.rs new file mode 100644 index 00000000000..1f4b27c5342 --- /dev/null +++ b/tests/ui-toml/useless_vec/useless_vec.rs @@ -0,0 +1,26 @@ +//@compile-flags: --test +#![warn(clippy::useless_vec)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(_: &[u32]) {} + +fn main() { + foo(&vec![1_u32]); +} + +#[test] +pub fn in_test() { + foo(&vec![2_u32]); +} + +#[cfg(test)] +fn in_cfg_test() { + foo(&vec![3_u32]); +} + +#[cfg(test)] +mod mod1 { + fn in_cfg_test_mod() { + super::foo(&vec![4_u32]); + } +} diff --git a/tests/ui-toml/useless_vec/useless_vec.stderr b/tests/ui-toml/useless_vec/useless_vec.stderr new file mode 100644 index 00000000000..633110c3c8d --- /dev/null +++ b/tests/ui-toml/useless_vec/useless_vec.stderr @@ -0,0 +1,11 @@ +error: useless use of `vec!` + --> tests/ui-toml/useless_vec/useless_vec.rs:8:9 + | +LL | foo(&vec![1_u32]); + | ^^^^^^^^^^^^ help: you can use a slice directly: `&[1_u32]` + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` + +error: aborting due to 1 previous error +