diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | book/src/lint_configuration.md | 1 | ||||
| -rw-r--r-- | clippy_dev/src/new_lint.rs | 63 | ||||
| -rw-r--r-- | clippy_lints/Cargo.toml | 3 | ||||
| -rw-r--r-- | clippy_lints/src/declared_lints.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/manual_hash_one.rs | 133 | ||||
| -rw-r--r-- | clippy_lints/src/utils/conf.rs | 43 | ||||
| -rw-r--r-- | clippy_lints/src/wildcard_imports.rs | 1 | ||||
| -rw-r--r-- | clippy_utils/src/msrvs.rs | 2 | ||||
| -rw-r--r-- | clippy_utils/src/visitors.rs | 44 | ||||
| -rw-r--r-- | tests/ui/manual_hash_one.fixed | 89 | ||||
| -rw-r--r-- | tests/ui/manual_hash_one.rs | 89 | ||||
| -rw-r--r-- | tests/ui/manual_hash_one.stderr | 56 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports.fixed | 28 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports.rs | 28 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports.stderr | 38 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports_2021.edition2018.fixed | 28 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports_2021.edition2018.stderr | 38 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports_2021.edition2021.fixed | 28 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports_2021.edition2021.stderr | 38 | ||||
| -rw-r--r-- | tests/ui/wildcard_imports_2021.rs | 28 |
22 files changed, 720 insertions, 62 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9ab1e2402..db54bfbf0b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5072,6 +5072,7 @@ Released 2018-09-13 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten +[`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index b980083f1f5..2c958ccbbc2 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -151,6 +151,7 @@ The minimum rust version that the project supports * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) +* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) ## `cognitive-complexity-threshold` diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index e64cf2c8749..be2386bb1d2 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -58,7 +58,7 @@ pub fn create( }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; - create_test(&lint).context("Unable to create a test for the new lint")?; + create_test(&lint, msrv).context("Unable to create a test for the new lint")?; if lint.ty.is_none() { add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; @@ -88,15 +88,21 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { } } -fn create_test(lint: &LintData<'_>) -> io::Result<()> { - fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> { +fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { + fn create_project_layout<P: Into<PathBuf>>( + lint_name: &str, + location: P, + case: &str, + hint: &str, + msrv: bool, + ) -> io::Result<()> { let mut path = location.into().join(case); fs::create_dir(&path)?; write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?; path.push("src"); fs::create_dir(&path)?; - write_file(path.join("main.rs"), get_test_file_contents(lint_name))?; + write_file(path.join("main.rs"), get_test_file_contents(lint_name, msrv))?; Ok(()) } @@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { let test_dir = lint.project_root.join(&relative_test_dir); fs::create_dir(&test_dir)?; - create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; - create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?; + create_project_layout( + lint.name, + &test_dir, + "fail", + "Content that triggers the lint goes here", + msrv, + )?; + create_project_layout( + lint.name, + &test_dir, + "pass", + "This file should not trigger the lint", + false, + )?; println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); } else { let test_path = format!("tests/ui/{}.rs", lint.name); - let test_contents = get_test_file_contents(lint.name); + let test_contents = get_test_file_contents(lint.name, msrv); write_file(lint.project_root.join(&test_path), test_contents)?; println!("Generated test file: `{test_path}`"); @@ -194,8 +212,8 @@ pub(crate) fn get_stabilization_version() -> String { parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") } -fn get_test_file_contents(lint_name: &str) -> String { - formatdoc!( +fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { + let mut test = formatdoc!( r#" #![warn(clippy::{lint_name})] @@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String { // test code goes here }} "# - ) + ); + + if msrv { + let _ = writedoc!( + test, + r#" + + // TODO: set xx to the version one below the MSRV used by the lint, and yy to + // the version used by the lint + #[clippy::msrv = "1.xx"] + fn msrv_1_xx() {{ + // a simple example that would trigger the lint if the MSRV were met + }} + + #[clippy::msrv = "1.yy"] + fn msrv_1_yy() {{ + // the same example as above + }} + "# + ); + } + + test } fn get_manifest_contents(lint_name: &str, hint: &str) -> String { @@ -258,7 +298,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ) }); - let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category)); + let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category)); result.push_str(&if enable_msrv { formatdoc!( @@ -281,7 +321,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. - // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` "# ) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index dcd9a4adcbd..834753a2301 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,6 +28,9 @@ semver = "1.0" rustc-semver = "1.1" url = "2.2" +[dev-dependencies] +walkdir = "2.3" + [features] deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4d1281ec1e7..b4b84b36044 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -280,6 +280,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_INFO, crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, + crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1271be2fd93..63a3fbcb897 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -190,6 +190,7 @@ mod manual_async_fn; mod manual_bits; mod manual_clamp; mod manual_float_methods; +mod manual_hash_one; mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; @@ -1119,6 +1120,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv(), )) }); + store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs new file mode 100644 index 00000000000..ea911335450 --- /dev/null +++ b/clippy_lints/src/manual_hash_one.rs @@ -0,0 +1,133 @@ +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_opt; +use clippy_utils::visitors::{is_local_used, local_used_once}; +use clippy_utils::{is_trait_method, path_to_local_id}; +use rustc_errors::Applicability; +use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for cases where [`BuildHasher::hash_one`] can be used. + /// + /// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one + /// + /// ### Why is this bad? + /// It is more concise to use the `hash_one` method. + /// + /// ### Example + /// ```rust + /// use std::hash::{BuildHasher, Hash, Hasher}; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let mut hasher = s.build_hasher(); + /// value.hash(&mut hasher); + /// let hash = hasher.finish(); + /// ``` + /// Use instead: + /// ```rust + /// use std::hash::BuildHasher; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let hash = s.hash_one(&value); + /// ``` + #[clippy::version = "1.74.0"] + pub MANUAL_HASH_ONE, + complexity, + "manual implementations of `BuildHasher::hash_one`" +} + +pub struct ManualHashOne { + msrv: Msrv, +} + +impl ManualHashOne { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]); + +impl LateLintPass<'_> for ManualHashOne { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + // `let mut hasher = seg.build_hasher();` + if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind + && let Some(init) = local.init + && !init.span.from_expansion() + && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind + && seg.ident.name == sym!(build_hasher) + + && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id) + && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id) + + && let mut stmts = block.stmts.iter() + .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id) + .skip(1) + .filter(|&stmt| is_local_used(cx, stmt, hasher)) + + // `hashed_value.hash(&mut hasher);` + && let Some(hash_stmt) = stmts.next() + && let StmtKind::Semi(hash_expr) = hash_stmt.kind + && !hash_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind + && seg.ident.name == sym::hash + && is_trait_method(cx, hash_expr, sym::Hash) + && path_to_local_id(ref_to_hasher.peel_borrows(), hasher) + + && let maybe_finish_stmt = stmts.next() + // There should be no more statements referencing `hasher` + && stmts.next().is_none() + + // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block + && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher) + && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id) + && !finish_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind + && seg.ident.name == sym!(finish) + + && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE) + { + span_lint_hir_and_then( + cx, + MANUAL_HASH_ONE, + finish_expr.hir_id, + finish_expr.span, + "manual implementation of `BuildHasher::hash_one`", + |diag| { + if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) + && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + { + diag.multipart_suggestion( + "try", + vec![ + (local_stmt.span, String::new()), + (hash_stmt.span, String::new()), + ( + finish_expr.span, + // `needless_borrows_for_generic_args` will take care of + // removing the `&` when it isn't needed + format!("{build_hasher}.hash_one(&{hashed_value})") + ) + ], + Applicability::MachineApplicable, + ); + + } + }, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 75c3c7a958a..23da1de7730 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -294,7 +294,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. /// /// The minimum rust version that the project supports (msrv: Option<String> = None), @@ -744,3 +744,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) { (rows, column_widths) } + +#[cfg(test)] +mod tests { + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + use serde::de::IgnoredAny; + use std::fs; + use walkdir::WalkDir; + + #[test] + fn configs_are_tested() { + let mut names: FxHashSet<String> = super::metadata::get_configuration_metadata() + .into_iter() + .map(|meta| meta.name.replace('_', "-")) + .collect(); + + let toml_files = WalkDir::new("../tests") + .into_iter() + .map(Result::unwrap) + .filter(|entry| entry.file_name() == "clippy.toml"); + + for entry in toml_files { + let file = fs::read_to_string(entry.path()).unwrap(); + #[allow(clippy::zero_sized_map_values)] + if let Ok(map) = toml::from_str::<FxHashMap<String, IgnoredAny>>(&file) { + for name in map.keys() { + names.remove(name.as_str()); + } + } + } + + assert!( + names.remove("allow-one-hash-in-raw-strings"), + "remove this when #11481 is fixed" + ); + + assert!( + names.is_empty(), + "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`" + ); + } +} diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index d09d02a7dfd..70b83149ce1 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports { if self.warn_on_all || !self.check_exceptions(item, use_path.segments); let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id); if !used_imports.is_empty(); // Already handled by `unused_imports` + if !used_imports.contains(&kw::Underscore); then { let mut applicability = Applicability::MachineApplicable; let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 0faff05eb23..df839c2106f 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,7 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,71,0 { TUPLE_ARRAY_CONVERSIONS } + 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 3b47a451345..d752fe7d97e 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -62,6 +62,27 @@ where } } } +impl<'tcx, A, B> Visitable<'tcx> for (A, B) +where + A: Visitable<'tcx>, + B: Visitable<'tcx>, +{ + fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) { + let (a, b) = self; + a.visit(visitor); + b.visit(visitor); + } +} +impl<'tcx, T> Visitable<'tcx> for Option<T> +where + T: Visitable<'tcx>, +{ + fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) { + if let Some(x) = self { + x.visit(visitor); + } + } +} macro_rules! visitable_ref { ($t:ident, $f:ident) => { impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { @@ -748,3 +769,26 @@ pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { }) .is_some() } + +/// If the local is only used once in `visitable` returns the path expression referencing the given +/// local +pub fn local_used_once<'tcx>( + cx: &LateContext<'tcx>, + visitable: impl Visitable<'tcx>, + id: HirId, +) -> Option<&'tcx Expr<'tcx>> { + let mut expr = None; + + let cf = for_each_expr_with_closures(cx, visitable, |e| { + if path_to_local_id(e, id) && expr.replace(e).is_some() { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }); + if cf.is_some() { + return None; + } + + expr +} diff --git a/tests/ui/manual_hash_one.fixed b/tests/ui/manual_hash_one.fixed new file mode 100644 index 00000000000..edfd9c4a47b --- /dev/null +++ b/tests/ui/manual_hash_one.fixed @@ -0,0 +1,89 @@ +#![warn(clippy::manual_hash_one)] +#![allow(clippy::needless_borrows_for_generic_args)] + +use std::hash::{BuildHasher, Hash, Hasher}; + +fn returned(b: impl BuildHasher) -> u64 { + + + b.hash_one(&true) +} + +fn unsized_receiver(b: impl BuildHasher, s: &str) { + + + let _ = b.hash_one(&s[4..10]); +} + +fn owned_value(b: impl BuildHasher, v: Vec<u32>) -> Vec<u32> { + + + let _ = b.hash_one(&v); + v +} + +fn reused_hasher(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + let _ = hasher.finish(); +} + +fn reused_hasher_in_return(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + hasher.finish() +} + +fn no_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); +} + +fn hash_twice(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + true.hash(&mut hasher); + let _ = hasher.finish(); +} + +fn other_hasher(b: impl BuildHasher) { + let mut other_hasher = b.build_hasher(); + + let mut hasher = b.build_hasher(); + true.hash(&mut other_hasher); + let _ = hasher.finish(); +} + +fn finish_then_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); + true.hash(&mut hasher); +} + +fn in_macro(b: impl BuildHasher) { + macro_rules! m { + ($b:expr) => {{ + let mut hasher = $b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + }}; + } + + m!(b); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} + +#[clippy::msrv = "1.71"] +fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { + + + let _ = b.hash_one(&v); +} diff --git a/tests/ui/manual_hash_one.rs b/tests/ui/manual_hash_one.rs new file mode 100644 index 00000000000..ee61522853f --- /dev/null +++ b/tests/ui/manual_hash_one.rs @@ -0,0 +1,89 @@ +#![warn(clippy::manual_hash_one)] +#![allow(clippy::needless_borrows_for_generic_args)] + +use std::hash::{BuildHasher, Hash, Hasher}; + +fn returned(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + hasher.finish() +} + +fn unsized_receiver(b: impl BuildHasher, s: &str) { + let mut hasher = b.build_hasher(); + s[4..10].hash(&mut hasher); + let _ = hasher.finish(); +} + +fn owned_value(b: impl BuildHasher, v: Vec<u32>) -> Vec<u32> { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); + v +} + +fn reused_hasher(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + let _ = hasher.finish(); +} + +fn reused_hasher_in_return(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + hasher.finish() +} + +fn no_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); +} + +fn hash_twice(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + true.hash(&mut hasher); + let _ = hasher.finish(); +} + +fn other_hasher(b: impl BuildHasher) { + let mut other_hasher = b.build_hasher(); + + let mut hasher = b.build_hasher(); + true.hash(&mut other_hasher); + let _ = hasher.finish(); +} + +fn finish_then_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); + true.hash(&mut hasher); +} + +fn in_macro(b: impl BuildHasher) { + macro_rules! m { + ($b:expr) => {{ + let mut hasher = $b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + }}; + } + + m!(b); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} + +#[clippy::msrv = "1.71"] +fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} diff --git a/tests/ui/manual_hash_one.stderr b/tests/ui/manual_hash_one.stderr new file mode 100644 index 00000000000..3ce6f41e1f9 --- /dev/null +++ b/tests/ui/manual_hash_one.stderr @@ -0,0 +1,56 @@ +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:9:5 + | +LL | hasher.finish() + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-hash-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_hash_one)]` +help: try + | +LL ~ +LL ~ +LL ~ b.hash_one(&true) + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:15:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&s[4..10]); + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:21:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&v); + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:88:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&v); + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 2828f9d048e..6fdd728b9b7 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -69,6 +69,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use self::exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use self::exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index cbe70e505d8..20e06d4b366 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -69,6 +69,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use self::exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use self::exports_underscore_ish::*; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 3c750815baf..01a5414778c 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:97:13 + --> $DIR/wildcard_imports.rs:94:13 + | +LL | use self::exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `self::exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports.rs:125:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:103:75 + --> $DIR/wildcard_imports.rs:131:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:104:13 + --> $DIR/wildcard_imports.rs:132:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:20 + --> $DIR/wildcard_imports.rs:144:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:30 + --> $DIR/wildcard_imports.rs:144:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:123:13 + --> $DIR/wildcard_imports.rs:151:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:152:9 + --> $DIR/wildcard_imports.rs:180:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:161:9 + --> $DIR/wildcard_imports.rs:189:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:162:9 + --> $DIR/wildcard_imports.rs:190:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:173:13 + --> $DIR/wildcard_imports.rs:201:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:208:17 + --> $DIR/wildcard_imports.rs:236:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:216:13 + --> $DIR/wildcard_imports.rs:244:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:225:17 + --> $DIR/wildcard_imports.rs:253:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:234:13 + --> $DIR/wildcard_imports.rs:262:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:242:13 + --> $DIR/wildcard_imports.rs:270:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index b27281fa25c..6a9fe007d65 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr index 709a665d65c..e39f240a4aa 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:91:13 + --> $DIR/wildcard_imports_2021.rs:89:13 + | +LL | use exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:119:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:97:75 + --> $DIR/wildcard_imports_2021.rs:125:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:98:13 + --> $DIR/wildcard_imports_2021.rs:126:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:20 + --> $DIR/wildcard_imports_2021.rs:138:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:30 + --> $DIR/wildcard_imports_2021.rs:138:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:117:13 + --> $DIR/wildcard_imports_2021.rs:145:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:146:9 + --> $DIR/wildcard_imports_2021.rs:174:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:183:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:156:9 + --> $DIR/wildcard_imports_2021.rs:184:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:167:13 + --> $DIR/wildcard_imports_2021.rs:195:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:202:17 + --> $DIR/wildcard_imports_2021.rs:230:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:210:13 + --> $DIR/wildcard_imports_2021.rs:238:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:219:17 + --> $DIR/wildcard_imports_2021.rs:247:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:228:13 + --> $DIR/wildcard_imports_2021.rs:256:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:236:13 + --> $DIR/wildcard_imports_2021.rs:264:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index b27281fa25c..6a9fe007d65 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr index 709a665d65c..e39f240a4aa 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:91:13 + --> $DIR/wildcard_imports_2021.rs:89:13 + | +LL | use exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:119:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:97:75 + --> $DIR/wildcard_imports_2021.rs:125:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:98:13 + --> $DIR/wildcard_imports_2021.rs:126:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:20 + --> $DIR/wildcard_imports_2021.rs:138:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:30 + --> $DIR/wildcard_imports_2021.rs:138:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:117:13 + --> $DIR/wildcard_imports_2021.rs:145:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:146:9 + --> $DIR/wildcard_imports_2021.rs:174:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:183:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:156:9 + --> $DIR/wildcard_imports_2021.rs:184:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:167:13 + --> $DIR/wildcard_imports_2021.rs:195:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:202:17 + --> $DIR/wildcard_imports_2021.rs:230:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:210:13 + --> $DIR/wildcard_imports_2021.rs:238:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:219:17 + --> $DIR/wildcard_imports_2021.rs:247:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:228:13 + --> $DIR/wildcard_imports_2021.rs:256:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:236:13 + --> $DIR/wildcard_imports_2021.rs:264:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index 7dd2103eca7..18ebc0f5127 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::*; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); |
