diff --git a/Cargo.lock b/Cargo.lock index 47ad7ab3e9814..5e9808c806884 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -524,7 +524,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clippy" -version = "0.1.82" +version = "0.1.83" dependencies = [ "anstream", "cargo_metadata 0.18.1", @@ -547,13 +547,13 @@ dependencies = [ "termize", "tokio", "toml 0.7.8", - "ui_test 0.25.0", + "ui_test", "walkdir", ] [[package]] name = "clippy_config" -version = "0.1.82" +version = "0.1.83" dependencies = [ "itertools", "serde", @@ -576,7 +576,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.82" +version = "0.1.83" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -600,7 +600,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.82" +version = "0.1.83" dependencies = [ "arrayvec", "clippy_config", @@ -902,7 +902,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.82" +version = "0.1.83" dependencies = [ "itertools", "quote", @@ -2269,7 +2269,7 @@ dependencies = [ "rustc_version", "smallvec", "tempfile", - "ui_test 0.26.5", + "ui_test", "windows-sys 0.52.0", ] @@ -5485,33 +5485,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" -[[package]] -name = "ui_test" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e4f339f62edc873975c47115f9e71c5454ddaa37c1142b42fc0b2672c8dacb" -dependencies = [ - "annotate-snippets 0.11.4", - "anyhow", - "bstr", - "cargo-platform", - "cargo_metadata 0.18.1", - "color-eyre", - "colored", - "comma", - "crossbeam-channel", - "indicatif", - "lazy_static", - "levenshtein", - "prettydiff", - "regex", - "rustc_version", - "rustfix", - "serde", - "serde_json", - "spanned", -] - [[package]] name = "ui_test" version = "0.26.5" diff --git a/src/tools/clippy/.github/deploy.sh b/src/tools/clippy/.github/deploy.sh index d937661c0f828..5b4b4be4e36b5 100644 --- a/src/tools/clippy/.github/deploy.sh +++ b/src/tools/clippy/.github/deploy.sh @@ -25,16 +25,15 @@ if [[ $BETA = "true" ]]; then fi # Generate version index that is shown as root index page -cp util/gh-pages/versions.html out/index.html - -echo "Making the versions.json file" -python3 ./util/versions.py out +python3 ./util/versions.py ./util/gh-pages/versions.html out # Now let's go have some fun with the cloned repo cd out git config user.name "GHA CI" git config user.email "gha@ci.invalid" +git status + if [[ -n $TAG_NAME ]]; then # track files, so that the following check works git add --intent-to-add "$TAG_NAME" @@ -46,8 +45,6 @@ if [[ -n $TAG_NAME ]]; then git add "$TAG_NAME" # Update the symlink git add stable - # Update versions file - git add versions.json git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}" elif [[ $BETA = "true" ]]; then if git diff --exit-code --quiet -- beta/; then diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 2aa13313fa518..026771e6fcf42 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -162,7 +162,7 @@ jobs: find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf - name: Upload Binaries - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: binaries path: target/debug @@ -202,7 +202,7 @@ jobs: # Download - name: Download target dir - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: binaries path: target/debug diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 9bc4ad9698dbd..41a86e8ce5102 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,7 +6,61 @@ document. ## Unreleased / Beta / In Rust Nightly -[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master) +[b794b8e0...master](https://github.com/rust-lang/rust-clippy/compare/b794b8e0...master) + +## Rust 1.81 + +Current stable, released 2024-09-05 + +### New Lints + +* Added [`cfg_not_test`] to `restriction` + [#11293](https://github.com/rust-lang/rust-clippy/pull/11293) +* Added [`byte_char_slices`] to `style` + [#10155](https://github.com/rust-lang/rust-clippy/pull/10155) +* Added [`set_contains_or_insert`] to `nursery` + [#12873](https://github.com/rust-lang/rust-clippy/pull/12873) +* Added [`manual_rotate`] to `style` + [#12983](https://github.com/rust-lang/rust-clippy/pull/12983) +* Added [`unnecessary_min_or_max`] to `complexity` + [#12368](https://github.com/rust-lang/rust-clippy/pull/12368) +* Added [`manual_inspect`] to `complexity` + [#12287](https://github.com/rust-lang/rust-clippy/pull/12287) +* Added [`field_scoped_visibility_modifiers`] to `restriction` + [#12893](https://github.com/rust-lang/rust-clippy/pull/12893) +* Added [`manual_pattern_char_comparison`] to `style` + [#12849](https://github.com/rust-lang/rust-clippy/pull/12849) +* Added [`needless_maybe_sized`] to `suspicious` + [#10632](https://github.com/rust-lang/rust-clippy/pull/10632) +* Added [`needless_character_iteration`] to `suspicious` + [#12815](https://github.com/rust-lang/rust-clippy/pull/12815) + +### Moves and Deprecations + +* [`allow_attributes`], [`allow_attributes_without_reason`]: Now work on stable + [rust#120924](https://github.com/rust-lang/rust/pull/120924) +* Renamed `overflow_check_conditional` to [`panicking_overflow_checks`] + [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) +* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now deny-by-default) + [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) +* Renamed `thread_local_initializer_can_be_made_const` to [`missing_const_for_thread_local`] + [#12974](https://github.com/rust-lang/rust-clippy/pull/12974) +* Deprecated [`maybe_misused_cfg`] and [`mismatched_target_os`] as they are now caught by cargo + and rustc + [#12875](https://github.com/rust-lang/rust-clippy/pull/12875) + +### Enhancements + +* [`significant_drop_in_scrutinee`]: Now also checks scrutinies of `while let` and `for let` + expressions + [#12870](https://github.com/rust-lang/rust-clippy/pull/12870) +* [`std_instead_of_core`]: Now respects the `msrv` configuration + [#13168](https://github.com/rust-lang/rust-clippy/pull/13168) + +### ICE Fixes + +* [`suboptimal_flops`]: No longer crashes on custom `.log()` functions + [#12884](https://github.com/rust-lang/rust-clippy/pull/12884) ## Rust 1.80 @@ -5500,6 +5554,7 @@ Released 2018-09-13 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons [`invalid_utf8_in_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_utf8_in_unchecked +[`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements @@ -5559,6 +5614,7 @@ Released 2018-09-13 [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp +[`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find @@ -5570,6 +5626,7 @@ Released 2018-09-13 [`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 [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite +[`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two [`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str @@ -5716,6 +5773,7 @@ Released 2018-09-13 [`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty +[`non_zero_suggestions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_zero_suggestions [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces @@ -5757,6 +5815,7 @@ Released 2018-09-13 [`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false +[`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence @@ -5962,6 +6021,7 @@ Released 2018-09-13 [`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map +[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join @@ -6003,6 +6063,7 @@ Released 2018-09-13 [`unused_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_result_ok [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self +[`unused_trait_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result @@ -6013,6 +6074,7 @@ Released 2018-09-13 [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug [`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self [`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding +[`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion @@ -6047,6 +6109,7 @@ Released 2018-09-13 [`zero_repeat_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_repeat_side_effects [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space +[`zombie_processes`]: https://rust-lang.github.io/rust-clippy/master/index.html#zombie_processes [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index b48b881097f47..cf810798d8cc1 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.82" +version = "0.1.83" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -31,7 +31,7 @@ anstream = "0.6.0" [dev-dependencies] cargo_metadata = "0.18.1" -ui_test = "0.25" +ui_test = "0.26.4" regex = "1.5.5" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.122" diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 78348797588a6..91159bc79c511 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -727,6 +727,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) * [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) * [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [`unused_trait_names`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names) * [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index 5c4e0761dbca7..9da7112345de9 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.82" +version = "0.1.83" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index a6f1b958bfb17..757620341ccc1 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -1,6 +1,6 @@ +use crate::ClippyConfiguration; use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; -use crate::ClippyConfiguration; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -563,6 +563,7 @@ define_Conf! { uninlined_format_args, unnecessary_lazy_evaluations, unnested_or_patterns, + unused_trait_names, use_self, )] msrv: Msrv = Msrv::empty(), @@ -864,7 +865,7 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) }); - let rows = (fields.len() + (columns - 1)) / columns; + let rows = fields.len().div_ceil(columns); let column_widths = (0..columns) .map(|column| { diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs index ac838cc81d2f0..c63d98a0a13f9 100644 --- a/src/tools/clippy/clippy_config/src/lib.rs +++ b/src/tools/clippy/clippy_config/src/lib.rs @@ -26,5 +26,5 @@ mod metadata; pub mod msrvs; pub mod types; -pub use conf::{get_configuration_metadata, lookup_conf_file, Conf}; +pub use conf::{Conf, get_configuration_metadata, lookup_conf_file}; pub use metadata::ClippyConfiguration; diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index a2b4b6e256fa7..e30df3d32341a 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -1,7 +1,7 @@ use rustc_ast::Attribute; use rustc_attr::parse_version; use rustc_session::{RustcVersion, Session}; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use serde::Deserialize; use std::fmt; @@ -23,6 +23,7 @@ msrv_aliases! { 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } + 1,73,0 { MANUAL_DIV_CEIL } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } @@ -38,7 +39,7 @@ msrv_aliases! { 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,50,0 { BOOL_THEN, CLAMP } - 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } + 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } @@ -50,6 +51,7 @@ msrv_aliases! { 1,36,0 { ITERATOR_COPIED } 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } + 1,33,0 { UNDERSCORE_IMPORTS } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } 1,28,0 { FROM_BOOL } diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs index d47e34bb5bce5..bab63911182d1 100644 --- a/src/tools/clippy/clippy_config/src/types.rs +++ b/src/tools/clippy/clippy_config/src/types.rs @@ -1,5 +1,5 @@ use serde::de::{self, Deserializer, Visitor}; -use serde::{ser, Deserialize, Serialize}; +use serde::{Deserialize, Serialize, ser}; use std::fmt; #[derive(Debug, Deserialize)] diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs index 5fc4365c6e785..8c61c35533cf8 100644 --- a/src/tools/clippy/clippy_dev/src/fmt.rs +++ b/src/tools/clippy/clippy_dev/src/fmt.rs @@ -1,6 +1,6 @@ use crate::clippy_project_root; use itertools::Itertools; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use shell_escape::escape; use std::ffi::{OsStr, OsString}; use std::ops::ControlFlow; diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 87117832fb952..5fd65017cfb97 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -441,7 +441,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R #[allow(clippy::too_many_lines)] fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { - use super::update_lints::{match_tokens, LintDeclSearchResult}; + use super::update_lints::{LintDeclSearchResult, match_tokens}; use rustc_lexer::TokenKind; let lint_name_upper = lint.name.to_uppercase(); diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs index 19560b31fd3e2..cc14cd8dae69e 100644 --- a/src/tools/clippy/clippy_dev/src/serve.rs +++ b/src/tools/clippy/clippy_dev/src/serve.rs @@ -29,7 +29,7 @@ pub fn run(port: u16, lint: Option) -> ! { } if let Some(url) = url.take() { thread::spawn(move || { - Command::new(PYTHON) + let mut child = Command::new(PYTHON) .arg("-m") .arg("http.server") .arg(port.to_string()) @@ -40,6 +40,7 @@ pub fn run(port: u16, lint: Option) -> ! { thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up let _result = opener::open(url); + child.wait().unwrap(); }); } thread::sleep(Duration::from_millis(1000)); diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 8dbda1c634c28..d6ed36d52f4e0 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -1,7 +1,7 @@ use crate::clippy_project_root; use aho_corasick::AhoCorasickBuilder; use itertools::Itertools; -use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; +use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::{self, Write}; @@ -1048,23 +1048,17 @@ mod tests { Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - )], - ); + expected.insert("group1".to_string(), vec![ + Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), + ]); + expected.insert("group2".to_string(), vec![Lint::new( + "should_assert_eq2", + "group2", + "\"abc\"", + "module_name", + Range::default(), + )]); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); } } diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index fbd4566da58c7..d1188940b46a8 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.82" +version = "0.1.83" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs index c72b3f1318c86..1af6d448a93c7 100644 --- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs @@ -3,12 +3,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Symbol; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 451bae959874f..370f0c482fd54 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 56f5e903dc3e2..4f8f091a09569 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -1,10 +1,10 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{impl_lint_pass, RustcVersion}; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 4eafa330fafab..2643f850879cc 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -4,8 +4,8 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index 7eaac80f969f7..b6684825835a9 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_inside_always_const_context; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index f1cb4a05af86c..c073dee855e20 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 55645d04eef36..0b82c0cd04c12 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -1,7 +1,7 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; +use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 4ab97118df1d4..40959eccd3a9f 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -1,4 +1,4 @@ -use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON}; +use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{MetaItemKind, NestedMetaItem}; @@ -26,7 +26,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet cx, ALLOW_ATTRIBUTES_WITHOUT_REASON, attr.span, - format!("`{}` attribute without specifying a reason", name.as_str()), + format!("`{name}` attribute without specifying a reason"), |diag| { diag.help("try adding a reason at the end with `, reason = \"..\"`"); }, diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 9b08fd6d654a5..508963a20ea71 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,10 +1,10 @@ -use super::utils::extract_clippy_lint; use super::BLANKET_CLIPPY_RESTRICTION_LINTS; +use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use rustc_ast::NestedMetaItem; use rustc_lint::{LateContext, Level, LintContext}; use rustc_span::symbol::Symbol; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { for lint in items { diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs index e872ab6b4b5f5..abf924f7542e2 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,4 +1,4 @@ -use super::{unnecessary_clippy_cfg, Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR}; +use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::AttrStyle; diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 40a1c4e288422..55f8e1072db74 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( @@ -36,7 +36,7 @@ fn check_duplicated_attr( } let Some(ident) = attr.ident() else { return }; let name = ident.name; - if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented { + if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented || name == sym::reason { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. diff --git a/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs deleted file mode 100644 index 7ff644b4c445f..0000000000000 --- a/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt}; -use rustc_ast::{AttrKind, AttrStyle}; -use rustc_lint::EarlyContext; -use rustc_span::Span; - -/// Check for empty lines after outer attributes. -/// -/// Attributes and documentation comments are both considered outer attributes -/// by the AST. However, the average user likely considers them to be different. -/// Checking for empty lines after each of these attributes is split into two different -/// lints but can share the same logic. -pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - let mut iter = item.attrs.iter().peekable(); - while let Some(attr) = iter.next() { - if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) - && attr.style == AttrStyle::Outer - && is_present_in_source(cx, attr.span) - { - let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); - let end_of_attr_to_next_attr_or_item = Span::new( - attr.span.hi(), - iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), - item.span.ctxt(), - item.span.parent(), - ); - - if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) { - let lines = snippet.split('\n').collect::>(); - let lines = without_block_comments(lines); - - if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - let (lint_msg, lint_type) = match attr.kind { - AttrKind::DocComment(..) => ( - "found an empty line after a doc comment. \ - Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", - EMPTY_LINE_AFTER_DOC_COMMENTS, - ), - AttrKind::Normal(..) => ( - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - EMPTY_LINE_AFTER_OUTER_ATTR, - ), - }; - - span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); - } - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs index 3b5b80ffefaf2..d41bb580c6cd9 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -1,10 +1,10 @@ -use super::utils::is_word; use super::INLINE_ALWAYS; +use super::utils::is_word; use clippy_utils::diagnostics::span_lint; use rustc_ast::Attribute; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { if span.from_expansion() { diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 3b14e9aee7fc0..888f28fa2258c 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -4,7 +4,6 @@ mod blanket_clippy_restriction_lints; mod deprecated_cfg_attr; mod deprecated_semver; mod duplicated_attributes; -mod empty_line_after; mod inline_always; mod mixed_attributes_style; mod non_minimal_cfg; @@ -13,8 +12,8 @@ mod unnecessary_clippy_cfg; mod useless_attribute; mod utils; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -126,94 +125,6 @@ declare_clippy_lint! { "use of `#[deprecated(since = \"x\")]` where x is not semver" } -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after outer attributes - /// - /// ### Why is this bad? - /// Most likely the attribute was meant to be an inner attribute using a '!'. - /// If it was meant to be an outer attribute, then the following item - /// should not be separated by empty lines. - /// - /// ### Known problems - /// Can cause false positives. - /// - /// From the clippy side it's difficult to detect empty lines between an attributes and the - /// following item because empty lines and comments are not part of the AST. The parsing - /// currently works for basic cases but is not perfect. - /// - /// ### Example - /// ```no_run - /// #[allow(dead_code)] - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// // Good (as inner attribute) - /// #![allow(dead_code)] - /// - /// fn this_is_fine() { } - /// - /// // or - /// - /// // Good (as outer attribute) - /// #[allow(dead_code)] - /// fn this_is_fine_too() { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub EMPTY_LINE_AFTER_OUTER_ATTR, - nursery, - "empty line after outer attribute" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after documentation comments. - /// - /// ### Why is this bad? - /// The documentation comment was most likely meant to be an inner attribute or regular comment. - /// If it was intended to be a documentation comment, then the empty line should be removed to - /// be more idiomatic. - /// - /// ### Known problems - /// Only detects empty lines immediately following the documentation. If the doc comment is followed - /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` - /// in combination with this lint to detect both cases. - /// - /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). - /// - /// ### Example - /// ```no_run - /// /// Some doc comment with a blank line after it. - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// /// Good (no blank line) - /// fn this_is_fine() { } - /// ``` - /// - /// ```no_run - /// // Good (convert to a regular comment) - /// - /// fn this_is_fine_too() { } - /// ``` - /// - /// ```no_run - /// //! Good (convert to a comment on an inner attribute) - /// - /// fn this_is_fine_as_well() { } - /// ``` - #[clippy::version = "1.70.0"] - pub EMPTY_LINE_AFTER_DOC_COMMENTS, - nursery, - "empty line after documentation comments" -} - declare_clippy_lint! { /// ### What it does /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. @@ -601,18 +512,12 @@ impl EarlyAttributes { impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, - EMPTY_LINE_AFTER_OUTER_ATTR, - EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, ]); impl EarlyLintPass for EarlyAttributes { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - empty_line_after::check(cx, item); - } - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { deprecated_cfg_attr::check(cx, attr, &self.msrv); deprecated_cfg_attr::check_clippy(cx, attr); diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 67ba605a59fa5..12668c616c13e 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{first_line_of_span, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, first_line_of_span}; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; @@ -51,6 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) | "module_name_repetitions" | "single_component_path_imports" | "disallowed_types" + | "unused_trait_names" ) }) { return; diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index d5f017b26509b..9952d0af99e54 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index e933fdf1d6e6e..3c2af72624f60 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -4,12 +4,12 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 8459f051d3d9a..8261c65354fd5 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::expr_sig; use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs index a9fe190f1777e..dd2620b0b9df9 100644 --- a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs +++ b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```ignore /// b"Hello" /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.81.0"] pub BYTE_CHAR_SLICES, style, "hard to read byte char slice" diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs index e924542fea2aa..ffd6c520c9ae8 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs @@ -2,7 +2,7 @@ use super::LINT_GROUPS_PRIORITY; use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_lint::{unerased_lint_store, LateContext}; +use rustc_lint::{LateContext, unerased_lint_store}; use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index 346aed7e9f117..84a44b14dde5b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -10,7 +10,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::hygiene; -use super::{utils, CAST_LOSSLESS}; +use super::{CAST_LOSSLESS, utils}; pub(super) fn check( cx: &LateContext<'_>, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 5708aae3f3eca..40a1a9d1ce8fb 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::Span; use rustc_target::abi::IntegerType; -use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; +use super::{CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION, utils}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs index 11274383595a8..3cf4a43b0d4c7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs @@ -3,7 +3,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use super::{utils, CAST_POSSIBLE_WRAP}; +use super::{CAST_POSSIBLE_WRAP, utils}; // this should be kept in sync with the allowed bit widths of `usize` and `isize` const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64]; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs index 035666e4d4c92..1eb115ce6bdc0 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs @@ -4,7 +4,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use super::{utils, CAST_PRECISION_LOSS}; +use super::{CAST_PRECISION_LOSS, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { if !cast_from.is_integral() || cast_to.is_integral() { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 9daf237344a4b..4be53ace6871e 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index dbe03e4ae8095..ac1a355c8d962 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, UintTy}; -use super::{utils, FN_TO_NUMERIC_CAST}; +use super::{FN_TO_NUMERIC_CAST, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index dfbae1618ac62..18e7798452ead 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use super::{utils, FN_TO_NUMERIC_CAST_WITH_TRUNCATION}; +use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index c31716fbcee1d..3acd4eca420e0 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -23,8 +23,8 @@ mod unnecessary_cast; mod utils; mod zero_ptr; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -410,19 +410,27 @@ declare_clippy_lint! { /// ### Why is this bad? /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another - /// type. + /// type. Or, when null pointers are involved, `null()` and `null_mut()` can be used directly. /// /// ### Example /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr as *mut u32; /// let ptr = mut_ptr as *const u32; + /// let ptr1 = std::ptr::null::() as *mut u32; + /// let ptr2 = std::ptr::null_mut::() as *const u32; + /// let ptr3 = std::ptr::null::().cast_mut(); + /// let ptr4 = std::ptr::null_mut::().cast_const(); /// ``` /// Use instead: /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); + /// let ptr1 = std::ptr::null_mut::(); + /// let ptr2 = std::ptr::null::(); + /// let ptr3 = std::ptr::null_mut::(); + /// let ptr4 = std::ptr::null::(); /// ``` #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, @@ -809,6 +817,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, &self.msrv); cast_slice_different_sizes::check(cx, expr, &self.msrv); + ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } extract_msrv_attr!(LateContext); diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs index 7513e18d408b1..7518dd2435aee 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,10 +1,12 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, Mutability}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_span::sym; use super::PTR_CAST_CONSTNESS; @@ -16,8 +18,7 @@ pub(super) fn check<'tcx>( cast_to: Ty<'tcx>, msrv: &Msrv, ) { - if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) - && let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() + if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() && matches!( (from_mutbl, to_mutbl), @@ -26,20 +27,74 @@ pub(super) fn check<'tcx>( && from_ty == to_ty && !from_ty.has_erased_regions() { - let sugg = Sugg::hir(cx, cast_expr, "_"); - let constness = match *to_mutbl { - Mutability::Not => "const", - Mutability::Mut => "mut", - }; + if let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind + && let Some(defid) = path.res.opt_def_id() + && let Some(prefix) = std_or_core(cx) + && let mut app = Applicability::MachineApplicable + && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let Some((_, after_lt)) = sugg.split_once("::<") + && let Some((source, target, target_func)) = match cx.tcx.get_diagnostic_name(defid) { + Some(sym::ptr_null) => Some(("const", "mutable", "null_mut")), + Some(sym::ptr_null_mut) => Some(("mutable", "const", "null")), + _ => None, + } + { + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + format!("`as` casting to make a {source} null pointer into a {target} null pointer"), + format!("use `{target_func}()` directly instead"), + format!("{prefix}::ptr::{target_func}::<{after_lt}"), + app, + ); + return; + } + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) { + let sugg = Sugg::hir(cx, cast_expr, "_"); + let constness = match *to_mutbl { + Mutability::Not => "const", + Mutability::Mut => "mut", + }; + + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + "`as` casting between raw pointers while changing only its constness", + format!("try `pointer::cast_{constness}`, a safer alternative"), + format!("{}.cast_{constness}()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } + } +} + +pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind + && let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind + && let Some(defid) = path.res.opt_def_id() + && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) { + (Some(sym::ptr_null), "cast_mut") => "null_mut", + (Some(sym::ptr_null_mut), "cast_const") => "null", + _ => return, + } + && let Some(prefix) = std_or_core(cx) + && let mut app = Applicability::MachineApplicable + && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let Some((_, after_lt)) = sugg.split_once("::<") + { span_lint_and_sugg( cx, PTR_CAST_CONSTNESS, expr.span, - "`as` casting between raw pointers while changing only its constness", - format!("try `pointer::cast_{constness}`, a safer alternative"), - format!("{}.cast_{constness}()", sugg.maybe_par()), - Applicability::MachineApplicable, + "changing constness of a null pointer", + format!("use `{method}()` directly instead"), + format!("{prefix}::ptr::{method}::<{after_lt}"), + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs index 5f48b8bd2063e..dfa240ccec623 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{expr_use_ctxt, is_no_std_crate, ExprUseNode}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 566adc83d6903..811d33c8bde2f 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::{snippet_opt, SpanRangeExt}; -use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; +use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs index 5a4f20f099060..5ccba92a0afe8 100644 --- a/src/tools/clippy/clippy_lints/src/casts/utils.rs +++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs @@ -1,4 +1,4 @@ -use clippy_utils::ty::{read_explicit_enum_value, EnumValue}; +use clippy_utils::ty::{EnumValue, read_explicit_enum_value}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; /// Returns the size in bits of an integral type. diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index d820c1e0720b8..884d15cabffcb 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// # fn important_check() {} /// important_check(); /// ``` - #[clippy::version = "1.73.0"] + #[clippy::version = "1.81.0"] pub CFG_NOT_TEST, restriction, "enforce against excluding code from test builds" diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index dd7c34d1e4687..d3aa2fd1ea12c 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_const_context, is_integer_literal, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 0099eefbc8dc1..495d8ce3fa701 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; +use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; @@ -11,7 +11,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index c6847411c75ab..8276e53648c0e 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{Visitable, for_each_expr}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index 5d78744e9b5e2..b9baf9af248ed 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::implements_trait; -use clippy_utils::{if_sequence, is_else_clause, is_in_const_context, SpanlessEq}; +use clippy_utils::{SpanlessEq, if_sequence, is_else_clause, is_in_const_context}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 86e0368c4e423..d90a22bb62a60 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,16 +1,17 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; -use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; -use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ - capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, - is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, eq_expr_value, find_binding_init, + get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, is_lint_allowed, path_to_local, + search_same, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index 678bdbc0ffb8a..c8f814137289c 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index 93c8fff05e9ed..a96c86f076574 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{macro_backtrace, MacroCall}; +use clippy_utils::macros::{MacroCall, macro_backtrace}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -9,7 +9,7 @@ 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; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 60e517131737a..2b229d2fe6ac5 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -49,8 +49,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, crate::attrs::DUPLICATED_ATTRIBUTES_INFO, - crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, - crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, @@ -138,6 +136,8 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, crate::doc::EMPTY_DOCS_INFO, + crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, + crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO, crate::doc::MISSING_SAFETY_DOC_INFO, @@ -217,6 +217,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::implicit_return::IMPLICIT_RETURN_INFO, crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO, + crate::implicit_saturating_sub::INVERTED_SATURATING_SUB_INFO, crate::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO, crate::incompatible_msrv::INCOMPATIBLE_MSRV_INFO, crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO, @@ -300,10 +301,12 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, crate::manual_clamp::MANUAL_CLAMP_INFO, + crate::manual_div_ceil::MANUAL_DIV_CEIL_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_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, @@ -464,6 +467,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, + crate::methods::UNNECESSARY_FIRST_THEN_CHECK_INFO, crate::methods::UNNECESSARY_FOLD_INFO, crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO, crate::methods::UNNECESSARY_JOIN_INFO, @@ -486,6 +490,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::misc::SHORT_CIRCUIT_STATEMENT_INFO, crate::misc::TOPLEVEL_REF_ARG_INFO, crate::misc::USED_UNDERSCORE_BINDING_INFO, + crate::misc::USED_UNDERSCORE_ITEMS_INFO, crate::misc_early::BUILTIN_TYPE_SHADOW_INFO, crate::misc_early::DOUBLE_NEG_INFO, crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, @@ -553,6 +558,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::non_expressive_names::SIMILAR_NAMES_INFO, crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO, crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO, + crate::non_zero_suggestions::NON_ZERO_SUGGESTIONS_INFO, crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO, crate::octal_escapes::OCTAL_ESCAPES_INFO, crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO, @@ -598,6 +604,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, + crate::pointers_in_nomem_asm_block::POINTERS_IN_NOMEM_ASM_BLOCK_INFO, crate::precedence::PRECEDENCE_INFO, crate::ptr::CMP_NULL_INFO, crate::ptr::INVALID_NULL_PTR_USAGE_INFO, @@ -741,6 +748,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unused_result_ok::UNUSED_RESULT_OK_INFO, crate::unused_rounding::UNUSED_ROUNDING_INFO, crate::unused_self::UNUSED_SELF_INFO, + crate::unused_trait_names::UNUSED_TRAIT_NAMES_INFO, crate::unused_unit::UNUSED_UNIT_INFO, crate::unwrap::PANICKING_UNWRAP_INFO, crate::unwrap::UNNECESSARY_UNWRAP_INFO, @@ -767,4 +775,5 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO, crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO, crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO, + crate::zombie_processes::ZOMBIE_PROCESSES_INFO, ]; diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 0b7279f2b360d..dc10b64698b4f 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -11,7 +11,7 @@ use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index 137781754966a..33a97222b8f8f 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_ty_alias; -use hir::def::Res; use hir::ExprKind; +use hir::def::Res; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index ac49e6f1a482a..056e39c02af90 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::{last_path_segment, std_or_core}; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, GenericArg, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 05c3cd3c81407..a065dc2cf7e52 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -3,7 +3,7 @@ use clippy_utils::numeric_literal; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 0e55d3db469ae..f34f5e056064d 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -3,14 +3,14 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, - ExprUseNode, + DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, + peel_middle_ty_refs, }; use core::mem; use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{ self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, @@ -290,13 +290,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { && let Some(ty) = use_node.defined_ty(cx) && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable() { - self.state = Some(( - State::ExplicitDeref { mutability: None }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::ExplicitDeref { mutability: None }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, RefOp::Method { mutbl, is_ufcs } @@ -458,13 +455,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) { - self.state = Some(( - State::Borrow { mutability }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::Borrow { mutability }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, _ => {}, @@ -508,13 +502,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let stability = state.stability; report(cx, expr, State::DerefedBorrow(state), data, typeck); if stability.is_deref_stable() { - self.state = Some(( - State::Borrow { mutability }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::Borrow { mutability }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => { @@ -539,13 +530,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } else if stability.is_deref_stable() && let Some(parent) = get_parent_expr(cx, expr) { - self.state = Some(( - State::ExplicitDeref { mutability: None }, - StateData { - first_expr: parent, - adjusted_ty, - }, - )); + self.state = Some((State::ExplicitDeref { mutability: None }, StateData { + first_expr: parent, + adjusted_ty, + })); } }, @@ -1138,20 +1126,17 @@ impl<'tcx> Dereferencing<'tcx> { if let Some(outer_pat) = self.ref_locals.get_mut(&local) { if let Some(pat) = outer_pat { // Check for auto-deref - if !matches!( - cx.typeck_results().expr_adjustments(e), - [ - Adjustment { - kind: Adjust::Deref(_), - .. - }, - Adjustment { - kind: Adjust::Deref(_), - .. - }, + if !matches!(cx.typeck_results().expr_adjustments(e), [ + Adjustment { + kind: Adjust::Deref(_), + .. + }, + Adjustment { + kind: Adjust::Deref(_), .. - ] - ) { + }, + .. + ]) { match get_parent_expr(cx, e) { // Field accesses are the same no matter the number of references. Some(Expr { diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index f27f68e2cbc5f..2920bbb4c81e8 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 649c480fb92a1..35a97adfb452a 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item}; use rustc_hir::{ self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource, }; @@ -15,7 +15,7 @@ use rustc_middle::ty::{ }; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs new file mode 100644 index 0000000000000..de7a2c2433f46 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs @@ -0,0 +1,342 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{SpanRangeExt, snippet_indent}; +use clippy_utils::tokenize_with_text; +use itertools::Itertools; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_errors::{Applicability, Diag, SuggestionStyle}; +use rustc_hir::{ItemKind, Node}; +use rustc_lexer::TokenKind; +use rustc_lint::LateContext; +use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData}; + +use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; + +#[derive(Debug, PartialEq, Clone, Copy)] +enum StopKind { + Attr, + Doc(CommentKind), +} + +impl StopKind { + fn is_doc(self) -> bool { + matches!(self, StopKind::Doc(_)) + } +} + +#[derive(Debug)] +struct Stop { + span: Span, + kind: StopKind, + first: usize, + last: usize, +} + +impl Stop { + fn convert_to_inner(&self) -> (Span, String) { + let inner = match self.kind { + // #|[...] + StopKind::Attr => InnerSpan::new(1, 1), + // /// or /** + // ^ ^ + StopKind::Doc(_) => InnerSpan::new(2, 3), + }; + (self.span.from_inner(inner), "!".into()) + } + + fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) { + match self.kind { + StopKind::Attr => { + if cx.tcx.sess.source_map().is_multiline(self.span) { + suggestions.extend([ + (self.span.shrink_to_lo(), "/* ".into()), + (self.span.shrink_to_hi(), " */".into()), + ]); + } else { + suggestions.push((self.span.shrink_to_lo(), "// ".into())); + } + }, + StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())), + StopKind::Doc(CommentKind::Block) => { + // /** outer */ /*! inner */ + // ^ ^ + let asterisk = self.span.from_inner(InnerSpan::new(1, 2)); + suggestions.push((asterisk, String::new())); + }, + } + } + + fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option { + let SpanData { lo, hi, .. } = attr.span.data(); + let file = cx.tcx.sess.source_map().lookup_source_file(lo); + + Some(Self { + span: attr.span, + kind: match attr.kind { + AttrKind::Normal(_) => StopKind::Attr, + AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind), + }, + first: file.lookup_line(file.relative_position(lo))?, + last: file.lookup_line(file.relative_position(hi))?, + }) + } +} + +/// Represents a set of attrs/doc comments separated by 1 or more empty lines +/// +/// ```ignore +/// /// chunk 1 docs +/// // not an empty line so also part of chunk 1 +/// #[chunk_1_attrs] // <-- prev_stop +/// +/// /* gap */ +/// +/// /// chunk 2 docs // <-- next_stop +/// #[chunk_2_attrs] +/// ``` +struct Gap<'a> { + /// The span of individual empty lines including the newline at the end of the line + empty_lines: Vec, + has_comment: bool, + next_stop: &'a Stop, + prev_stop: &'a Stop, + /// The chunk that includes [`prev_stop`](Self::prev_stop) + prev_chunk: &'a [Stop], +} + +impl<'a> Gap<'a> { + fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option { + let prev_stop = prev_chunk.last()?; + let next_stop = next_chunk.first()?; + let gap_span = prev_stop.span.between(next_stop.span); + let gap_snippet = gap_span.get_source_text(cx)?; + + let mut has_comment = false; + let mut empty_lines = Vec::new(); + + for (token, source, inner_span) in tokenize_with_text(&gap_snippet) { + match token { + TokenKind::BlockComment { + doc_style: None, + terminated: true, + } + | TokenKind::LineComment { doc_style: None } => has_comment = true, + TokenKind::Whitespace => { + let newlines = source.bytes().positions(|b| b == b'\n'); + empty_lines.extend( + newlines + .tuple_windows() + .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b)) + .map(|inner_span| gap_span.from_inner(inner_span)), + ); + }, + // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro + // shenanigans + _ => return None, + } + } + + (!empty_lines.is_empty()).then_some(Self { + empty_lines, + has_comment, + next_stop, + prev_stop, + prev_chunk, + }) + } + + fn contiguous_empty_lines(&self) -> impl Iterator + '_ { + self.empty_lines + // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1". + .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo()) + .map(|chunk| { + let first = chunk.first().expect("at least one empty line"); + let last = chunk.last().expect("at least one empty line"); + // The BytePos subtraction here is safe, as before an empty line, there must be at least one + // attribute/comment. The span needs to start at the end of the previous line. + first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi()) + }) + } +} + +/// If the node the attributes/docs apply to is the first in the module/crate suggest converting +/// them to inner attributes/docs +fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) { + let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else { + return; + }; + let parent_desc = match cx.tcx.parent_hir_node(owner.into()) { + Node::Item(item) + if let ItemKind::Mod(parent_mod) = item.kind + && let [first, ..] = parent_mod.item_ids + && first.owner_id == owner => + { + "parent module" + }, + Node::Crate(crate_mod) + if let Some(first) = crate_mod + .item_ids + .iter() + .map(|&id| cx.tcx.hir().item(id)) + // skip prelude imports + .find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) + && first.owner_id == owner => + { + "crate" + }, + _ => return, + }; + + diag.multipart_suggestion_verbose( + match kind { + StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"), + StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"), + }, + gaps.iter() + .flat_map(|gap| gap.prev_chunk) + .map(Stop::convert_to_inner) + .collect(), + Applicability::MaybeIncorrect, + ); +} + +fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { + let Some(first_gap) = gaps.first() else { + return false; + }; + let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied()); + let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines); + let mut has_comment = false; + let mut has_attr = false; + for gap in gaps { + has_comment |= gap.has_comment; + if !has_attr { + has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr); + } + } + let kind = first_gap.prev_stop.kind; + let (lint, kind_desc) = match kind { + StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"), + StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"), + }; + let (lines, are, them) = if empty_lines().nth(1).is_some() { + ("lines", "are", "them") + } else { + ("line", "is", "it") + }; + span_lint_and_then( + cx, + lint, + first_gap.prev_stop.span.to(empty_lines().last().unwrap()), + format!("empty {lines} after {kind_desc}"), + |diag| { + if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() { + let def_id = owner.to_def_id(); + let def_descr = cx.tcx.def_descr(def_id); + diag.span_label(cx.tcx.def_span(def_id), match kind { + StopKind::Attr => format!("the attribute applies to this {def_descr}"), + StopKind::Doc(_) => format!("the comment documents this {def_descr}"), + }); + } + + diag.multipart_suggestion_with_style( + format!("if the empty {lines} {are} unintentional remove {them}"), + contiguous_empty_lines() + .map(|empty_lines| (empty_lines, String::new())) + .collect(), + Applicability::MaybeIncorrect, + SuggestionStyle::HideCodeAlways, + ); + + if has_comment && kind.is_doc() { + // Likely doc comments that applied to some now commented out code + // + // /// Old docs for Foo + // // struct Foo; + + let mut suggestions = Vec::new(); + for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) { + stop.comment_out(cx, &mut suggestions); + } + let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) { + Some(name) => format!("`{name}`"), + None => "this".into(), + }; + diag.multipart_suggestion_verbose( + format!("if the doc comment should not document {name} comment it out"), + suggestions, + Applicability::MaybeIncorrect, + ); + } else { + suggest_inner(cx, diag, kind, gaps); + } + + if kind == StopKind::Doc(CommentKind::Line) + && gaps + .iter() + .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line)) + { + // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown + + let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default(); + diag.multipart_suggestion_verbose( + format!("if the documentation should include the empty {lines} include {them} in the comment"), + empty_lines() + .map(|empty_line| (empty_line, format!("{indent}///"))) + .collect(), + Applicability::MaybeIncorrect, + ); + } + }, + ); + kind.is_doc() +} + +/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment +/// lints where they would be confusing +/// +/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return +/// `true` if it triggers +pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool { + let mut outer = attrs + .iter() + .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion()) + .map(|attr| Stop::from_attr(cx, attr)) + .collect::>>() + .unwrap_or_default(); + + if outer.is_empty() { + return false; + } + + // Push a fake attribute Stop for the item itself so we check for gaps between the last outer + // attr/doc comment and the item they apply to + let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs); + if !span.from_expansion() + && let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo()) + { + outer.push(Stop { + span, + kind: StopKind::Attr, + first: line.line, + // last doesn't need to be accurate here, we don't compare it with anything + last: line.line, + }); + } + + let mut gaps = Vec::new(); + let mut last = 0; + for pos in outer + .array_windows() + .positions(|[a, b]| b.first.saturating_sub(a.last) > 1) + { + // we want to be after the first stop in the window + let pos = pos + 1; + if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) { + last = pos; + gaps.push(gap); + } + } + + check_gaps(cx, &gaps) +} diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs index 771bcac244187..f9e4a43c0e7a8 100644 --- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs +++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs @@ -22,7 +22,6 @@ pub(super) fn check( range: Range, mut span: Span, containers: &[super::Container], - line_break_span: Span, ) { if doc[range.clone()].contains('\t') { // We don't do tab stops correctly. @@ -52,29 +51,6 @@ pub(super) fn check( "doc list item without indentation" }; span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { - let snippet = clippy_utils::source::snippet(cx, line_break_span, ""); - if snippet.chars().filter(|&c| c == '\n').count() > 1 - && let Some(doc_comment_start) = snippet.rfind('\n') - && let doc_comment = snippet[doc_comment_start..].trim() - && (doc_comment == "///" || doc_comment == "//!") - { - // suggest filling in a blank line - diag.span_suggestion_verbose( - line_break_span.shrink_to_lo(), - "if this should be its own paragraph, add a blank doc comment line", - format!("\n{doc_comment}"), - Applicability::MaybeIncorrect, - ); - if ccount > 0 || blockquote_level > 0 { - diag.help("if this not intended to be a quote at all, escape it with `\\>`"); - } else { - let indent = list_indentation - lcount; - diag.help(format!( - "if this is intended to be part of the list, indent {indent} spaces" - )); - } - return; - } if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; diff --git a/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs b/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs index 01191e811b003..1d4345e4541d7 100644 --- a/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs +++ b/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs @@ -3,7 +3,7 @@ use std::ops::Range; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; -use super::{Fragments, DOC_LINK_WITH_QUOTES}; +use super::{DOC_LINK_WITH_QUOTES, Fragments}; pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range, fragments: Fragments<'_>) { if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'')) diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs index e3d7484072612..c9173030a55e1 100644 --- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_doc_hidden, return_ty}; use rustc_hir::{BodyId, FnSig, OwnerId, Safety}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub fn check( cx: &LateContext<'_>, diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 790579b21c902..0ae1fad569213 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -23,15 +23,16 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_resolve::rustdoc::{ - add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, - DocFragment, + DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, + span_of_fragments, }; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::ops::Range; use url::Url; +mod empty_line_after; mod link_with_quotes; mod markdown; mod missing_headers; @@ -449,13 +450,88 @@ declare_clippy_lint! { /// /// and probably spanning a many rows. /// struct Foo {} /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.82.0"] pub TOO_LONG_FIRST_DOC_PARAGRAPH, style, "ensure that the first line of a documentation paragraph isn't too long" } -#[derive(Clone)] +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after outer attributes + /// + /// ### Why is this bad? + /// The attribute may have meant to be an inner attribute (`#![attr]`). If + /// it was meant to be an outer attribute (`#[attr]`) then the empty line + /// should be removed + /// + /// ### Example + /// ```no_run + /// #[allow(dead_code)] + /// + /// fn not_quite_good_code() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// // Good (as inner attribute) + /// #![allow(dead_code)] + /// + /// fn this_is_fine() {} + /// + /// // or + /// + /// // Good (as outer attribute) + /// #[allow(dead_code)] + /// fn this_is_fine_too() {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub EMPTY_LINE_AFTER_OUTER_ATTR, + suspicious, + "empty line after outer attribute" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after doc comments. + /// + /// ### Why is this bad? + /// The doc comment may have meant to be an inner doc comment, regular + /// comment or applied to some old code that is now commented out. If it was + /// intended to be a doc comment, then the empty line should be removed. + /// + /// ### Example + /// ```no_run + /// /// Some doc comment with a blank line after it. + /// + /// fn f() {} + /// + /// /// Docs for `old_code` + /// // fn old_code() {} + /// + /// fn new_code() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// //! Convert it to an inner doc comment + /// + /// // Or a regular comment + /// + /// /// Or remove the empty line + /// fn f() {} + /// + /// // /// Docs for `old_code` + /// // fn old_code() {} + /// + /// fn new_code() {} + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + suspicious, + "empty line after doc comments" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -482,6 +558,8 @@ impl_lint_pass!(Documentation => [ SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, DOC_LAZY_CONTINUATION, + EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, TOO_LONG_FIRST_DOC_PARAGRAPH, ]); @@ -612,12 +690,10 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ Some(("fake".into(), "fake".into())) } - if is_doc_hidden(attrs) { + if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) { return None; } - suspicious_doc_comments::check(cx, attrs); - let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { if in_external_macro(cx.sess(), attr.span) { @@ -816,7 +892,6 @@ fn check_doc<'a, Events: Iterator, Range, attrs: &[Attribute]) { +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool { let replacements: Vec<_> = collect_doc_replacements(attrs); if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { @@ -24,6 +24,10 @@ pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { ); }, ); + + true + } else { + false } } diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs index 7bb3bb12f2ca9..0165d24c7df27 100644 --- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -79,10 +79,17 @@ pub(super) fn check( && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) && let Some(snippet) = snippet_opt(cx, new_span) { + let Some(first) = snippet_opt(cx, first_span) else { + return; + }; + let Some(comment_form) = first.get(..3) else { + return; + }; + diag.span_suggestion( new_span, "add an empty line", - format!("{snippet}///\n"), + format!("{snippet}{comment_form}{snippet}"), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 9c5100a8c1af8..70524e458c78b 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ - can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, - peel_hir_expr_while, SpanlessEq, + SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, + peel_hir_expr_while, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; use rustc_hir::hir_id::HirIdSet; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 4755cefe784c5..e9e9d00907ea0 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{mir_to_const, Constant}; +use clippy_utils::consts::{Constant, mir_to_const}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 803606979410b..5588124e791ea 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -1,15 +1,15 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir; -use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; +use rustc_hir::{AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind, intravisit}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::Span; use rustc_target::spec::abi::Abi; pub struct BoxedLocal { diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 8f469efb1b502..c88fb50b5afc8 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -5,8 +5,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs index 5154edd4399b2..ce0e0faa01489 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use rustc_ast::node_id::NodeSet; -use rustc_ast::visit::{walk_block, walk_item, Visitor}; +use rustc_ast::visit::{Visitor, walk_block, walk_item}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 3c4a043a732b7..5b423a96918f6 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; use rustc_errors::Applicability; @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, ExpnId}; +use rustc_span::{ExpnId, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index bfe4e253ae47f..bf9388b4a70fd 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::{is_from_proc_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, @@ -12,8 +12,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 0446943321aa9..747ea9a434464 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs index 95b8e882da792..ba2b37fbf11a3 100644 --- a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs +++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub FIELD_SCOPED_VISIBILITY_MODIFIERS, restriction, "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index bf4bcabfe8911..8da6623f34de9 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::Constant::{Int, F32, F64}; +use clippy_utils::consts::Constant::{F32, F64, Int}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 4dedff69b9abd..5e3f6b6a13707 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; +use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, root_macro_call_first_node}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 020c0c5440d93..83ab9f6557bdd 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use arrayvec::ArrayVec; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ - find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, - is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, + FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span, + format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, + root_macro_call_first_node, }; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -18,11 +19,11 @@ use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 7cd12ac7db852..c196f404ce677 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs index c6f03c3a7cf9a..8b1f86cbb9139 100644 --- a/src/tools/clippy/clippy_lints/src/format_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_type_lang_item; use clippy_utils::higher; +use clippy_utils::ty::is_type_lang_item; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index b84bf7c821ce8..8832cd42dd98f 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -1,11 +1,11 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::path_def_id; use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty, TyKind, diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index e5fa67d696427..7361546153c27 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 0f48941783b26..ba8a459c917e6 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -14,8 +14,8 @@ use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefIdSet, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefIdSet, LocalDefId}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 9382812104706..cfd11e9339fb7 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 1aeefe73cf68f..c2b40ae01d4cc 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -1,4 +1,4 @@ -use rustc_hir::{self as hir, intravisit, HirId, HirIdSet}; +use rustc_hir::{self as hir, HirId, HirIdSet, intravisit}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::def_id::LocalDefId; diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index c7de0385c021b..ac2e866e4ff7e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -4,8 +4,8 @@ use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::hir_id::OwnerId; use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, kw}; use super::RENAMED_FUNCTION_PARAMS; diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index c3a0b40a677aa..d4eaa1663208c 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -3,11 +3,11 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::trait_ref_of_method; -use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo}; +use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item}; use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 9488ba7568656..a4dbe134f3650 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 0bca53c1536de..d63c18c0edaab 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_context; @@ -105,6 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app); let closure = if method_name == "then" { "|| " } else { "" }; format!("{closure} {{ {block_snippet}; {arg_snip} }}") + } else if method_name == "then" { + (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() } else { arg_snip.into_owned() }; diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index e56f33f8dcfe2..f683925145a28 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -3,18 +3,18 @@ use std::collections::BTreeMap; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr, walk_inf, walk_ty}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 127c73ed637b2..f4a64f5c20b44 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -1,11 +1,17 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; +use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; +use clippy_utils::{ + SpanlessEq, higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, +}; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -39,7 +45,49 @@ declare_clippy_lint! { "Perform saturating subtraction instead of implicitly checking lower bound of data type" } -declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]); +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons between integers, followed by subtracting the greater value from the + /// lower one. + /// + /// ### Why is this bad? + /// This could result in an underflow and is most likely not what the user wants. If this was + /// intended to be a saturated subtraction, consider using the `saturating_sub` method directly. + /// + /// ### Example + /// ```no_run + /// let a = 12u32; + /// let b = 13u32; + /// + /// let result = if a > b { b - a } else { 0 }; + /// ``` + /// + /// Use instead: + /// ```no_run + /// let a = 12u32; + /// let b = 13u32; + /// + /// let result = a.saturating_sub(b); + /// ``` + #[clippy::version = "1.44.0"] + pub INVERTED_SATURATING_SUB, + correctness, + "Check if a variable is smaller than another one and still subtract from it even if smaller" +} + +pub struct ImplicitSaturatingSub { + msrv: Msrv, +} + +impl_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATURATING_SUB]); + +impl ImplicitSaturatingSub { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -50,73 +98,260 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Check if the conditional expression is a binary operation && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind + { + check_with_condition(cx, expr, cond_op.node, cond_left, cond_right, then); + } else if let Some(higher::If { + cond, + then: if_block, + r#else: Some(else_block), + }) = higher::If::hir(expr) + && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind + { + check_manual_check( + cx, expr, cond_op, cond_left, cond_right, if_block, else_block, &self.msrv, + ); + } + } + + extract_msrv_attr!(LateContext); +} - // Ensure that the binary operator is >, !=, or < - && (BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node) +#[allow(clippy::too_many_arguments)] +fn check_manual_check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + condition: &BinOp, + left_hand: &Expr<'tcx>, + right_hand: &Expr<'tcx>, + if_block: &Expr<'tcx>, + else_block: &Expr<'tcx>, + msrv: &Msrv, +) { + let ty = cx.typeck_results().expr_ty(left_hand); + if ty.is_numeric() && !ty.is_signed() { + match condition.node { + BinOpKind::Gt | BinOpKind::Ge => check_gt( + cx, + condition.span, + expr.span, + left_hand, + right_hand, + if_block, + else_block, + msrv, + ), + BinOpKind::Lt | BinOpKind::Le => check_gt( + cx, + condition.span, + expr.span, + right_hand, + left_hand, + if_block, + else_block, + msrv, + ), + _ => {}, + } + } +} - // Check if assign operation is done - && let Some(target) = subtracts_one(cx, then) +#[allow(clippy::too_many_arguments)] +fn check_gt( + cx: &LateContext<'_>, + condition_span: Span, + expr_span: Span, + big_var: &Expr<'_>, + little_var: &Expr<'_>, + if_block: &Expr<'_>, + else_block: &Expr<'_>, + msrv: &Msrv, +) { + if let Some(big_var) = Var::new(big_var) + && let Some(little_var) = Var::new(little_var) + { + check_subtraction( + cx, + condition_span, + expr_span, + big_var, + little_var, + if_block, + else_block, + msrv, + ); + } +} - // Extracting out the variable name - && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind +struct Var { + span: Span, + hir_id: HirId, +} + +impl Var { + fn new(expr: &Expr<'_>) -> Option { + path_to_local(expr).map(|hir_id| Self { + span: expr.span, + hir_id, + }) + } +} + +#[allow(clippy::too_many_arguments)] +fn check_subtraction( + cx: &LateContext<'_>, + condition_span: Span, + expr_span: Span, + big_var: Var, + little_var: Var, + if_block: &Expr<'_>, + else_block: &Expr<'_>, + msrv: &Msrv, +) { + let if_block = peel_blocks(if_block); + let else_block = peel_blocks(else_block); + if is_integer_literal(if_block, 0) { + // We need to check this case as well to prevent infinite recursion. + if is_integer_literal(else_block, 0) { + // Well, seems weird but who knows? + return; + } + // If the subtraction is done in the `else` block, then we need to also revert the two + // variables as it means that the check was reverted too. + check_subtraction( + cx, + condition_span, + expr_span, + little_var, + big_var, + else_block, + if_block, + msrv, + ); + return; + } + if is_integer_literal(else_block, 0) + && let ExprKind::Binary(op, left, right) = if_block.kind + && let BinOpKind::Sub = op.node + { + let local_left = path_to_local(left); + let local_right = path_to_local(right); + if Some(big_var.hir_id) == local_left && Some(little_var.hir_id) == local_right { + // This part of the condition is voluntarily split from the one before to ensure that + // if `snippet_opt` fails, it won't try the next conditions. + if let Some(big_var_snippet) = snippet_opt(cx, big_var.span) + && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) + && (!is_in_const_context(cx) || msrv.meets(msrvs::SATURATING_SUB_CONST)) + { + span_lint_and_sugg( + cx, + IMPLICIT_SATURATING_SUB, + expr_span, + "manual arithmetic check found", + "replace it with", + format!("{big_var_snippet}.saturating_sub({little_var_snippet})"), + Applicability::MachineApplicable, + ); + } + } else if Some(little_var.hir_id) == local_left + && Some(big_var.hir_id) == local_right + && let Some(big_var_snippet) = snippet_opt(cx, big_var.span) + && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) { - // Handle symmetric conditions in the if statement - let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { - if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_left, cond_right) - } else { - return; - } - } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { - if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_right, cond_left) - } else { - return; - } + span_lint_and_then( + cx, + INVERTED_SATURATING_SUB, + condition_span, + "inverted arithmetic check before subtraction", + |diag| { + diag.span_note( + if_block.span, + format!("this subtraction underflows when `{little_var_snippet} < {big_var_snippet}`"), + ); + diag.span_suggestion( + if_block.span, + "try replacing it with", + format!("{big_var_snippet} - {little_var_snippet}"), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} + +fn check_with_condition<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + cond_op: BinOpKind, + cond_left: &Expr<'tcx>, + cond_right: &Expr<'tcx>, + then: &Expr<'tcx>, +) { + // Ensure that the binary operator is >, !=, or < + if (BinOpKind::Ne == cond_op || BinOpKind::Gt == cond_op || BinOpKind::Lt == cond_op) + + // Check if assign operation is done + && let Some(target) = subtracts_one(cx, then) + + // Extracting out the variable name + && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind + { + // Handle symmetric conditions in the if statement + let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { + if BinOpKind::Gt == cond_op || BinOpKind::Ne == cond_op { + (cond_left, cond_right) } else { return; - }; - - // Check if the variable in the condition statement is an integer - if !cx.typeck_results().expr_ty(cond_var).is_integral() { + } + } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { + if BinOpKind::Lt == cond_op || BinOpKind::Ne == cond_op { + (cond_right, cond_left) + } else { return; } + } else { + return; + }; - // Get the variable name - let var_name = ares_path.segments[0].ident.name.as_str(); - match cond_num_val.kind { - ExprKind::Lit(cond_lit) => { - // Check if the constant is zero - if let LitKind::Int(Pu128(0), _) = cond_lit.node { - if cx.typeck_results().expr_ty(cond_left).is_signed() { - } else { - print_lint_and_sugg(cx, var_name, expr); - }; - } - }, - ExprKind::Path(QPath::TypeRelative(_, name)) => { - if name.ident.as_str() == "MIN" - && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) - && let Some(impl_id) = cx.tcx.impl_of_method(const_id) - && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl - && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() - { - print_lint_and_sugg(cx, var_name, expr); - } - }, - ExprKind::Call(func, []) => { - if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind - && name.ident.as_str() == "min_value" - && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) - && let Some(impl_id) = cx.tcx.impl_of_method(func_id) - && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl - && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() - { + // Check if the variable in the condition statement is an integer + if !cx.typeck_results().expr_ty(cond_var).is_integral() { + return; + } + + // Get the variable name + let var_name = ares_path.segments[0].ident.name.as_str(); + match cond_num_val.kind { + ExprKind::Lit(cond_lit) => { + // Check if the constant is zero + if let LitKind::Int(Pu128(0), _) = cond_lit.node { + if cx.typeck_results().expr_ty(cond_left).is_signed() { + } else { print_lint_and_sugg(cx, var_name, expr); - } - }, - _ => (), - } + }; + } + }, + ExprKind::Path(QPath::TypeRelative(_, name)) => { + if name.ident.as_str() == "MIN" + && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(const_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr); + } + }, + ExprKind::Call(func, []) => { + if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind + && name.ident.as_str() == "min_value" + && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(func_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr); + } + }, + _ => (), } } } diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 2ad045e12686c..0b3a6ee1beaeb 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_session::{impl_lint_pass, RustcVersion}; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::def_id::DefId; use rustc_span::{ExpnKind, Span}; diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 2f9661c9ea385..39afb6810b8e2 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; @@ -8,14 +8,14 @@ use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; +use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs index af5b1f9573991..3a28553b55e25 100644 --- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs +++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 6d6820311b679..66931a7f98c36 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 74bf82f58bdcf..66a8a3167a4f2 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -8,8 +8,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs index 8caa484bb9934..1ac549b74ac66 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -6,7 +6,7 @@ use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::hygiene::AstPass; -use rustc_span::{sym, ExpnKind}; +use rustc_span::{ExpnKind, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index ba0cd5d6eb359..b19b348c7430d 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs index f162948bb4457..5131f5b7269b6 100644 --- a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs +++ b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs @@ -55,7 +55,9 @@ impl LateLintPass<'_> for IterOverHashType { if let Some(for_loop) = ForLoop::hir(expr) && !for_loop.body.span.from_expansion() && let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs() - && hash_iter_tys.into_iter().any(|sym| is_type_diagnostic_item(cx, ty, sym)) + && hash_iter_tys + .into_iter() + .any(|sym| is_type_diagnostic_item(cx, ty, sym)) { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index 2f027c1170728..923089c722322 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo}; +use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy}; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 15a75b0608965..0f061d6de504f 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -8,7 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index ccab1e27d3b0c..e17d6213679a6 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_config::Conf; +use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::{get_parent_expr, is_from_proc_macro}; use hir::def_id::DefId; @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 16f86b18e2e55..8bc2a56af9938 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; -use clippy_utils::sugg::{has_enclosing_paren, Sugg}; -use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -185,6 +185,19 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ); } + if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind + && is_trait_method(cx, expr, sym::PartialEq) + && !expr.span.from_expansion() + { + check_empty_expr( + cx, + expr.span, + lhs_expr, + peel_ref_operators(cx, rhs_expr), + (method.ident.name == sym::ne).then_some("!").unwrap_or_default(), + ); + } + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind && !expr.span.from_expansion() { diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 2ac06b360bea4..1d41f568f3785 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -203,9 +203,11 @@ mod manual_assert; mod manual_async_fn; mod manual_bits; mod manual_clamp; +mod manual_div_ceil; mod manual_float_methods; mod manual_hash_one; mod manual_is_ascii_check; +mod manual_is_power_of_two; mod manual_let_else; mod manual_main_separator_str; mod manual_non_exhaustive; @@ -271,6 +273,7 @@ mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; mod non_send_fields_in_send_ty; +mod non_zero_suggestions; mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; @@ -287,6 +290,7 @@ mod pass_by_ref_or_value; mod pathbuf_init_then_push; mod pattern_type_mismatch; mod permissions_set_readonly_false; +mod pointers_in_nomem_asm_block; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -372,6 +376,7 @@ mod unused_peekable; mod unused_result_ok; mod unused_rounding; mod unused_self; +mod unused_trait_names; mod unused_unit; mod unwrap; mod unwrap_in_result; @@ -386,9 +391,10 @@ mod write; mod zero_div_zero; mod zero_repeat_side_effects; mod zero_sized_map_values; +mod zombie_processes; // end lints modules, do not remove this comment, it’s used in `update_lints` -use clippy_config::{get_configuration_metadata, Conf}; +use clippy_config::{Conf, get_configuration_metadata}; use clippy_utils::macros::FormatArgsStorage; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; @@ -623,7 +629,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|_| Box::new(strings::StringAdd)); store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn)); - store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); + store.register_late_pass(move |_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub::new(conf))); store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback)); store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); @@ -632,8 +638,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone()))); store.register_late_pass(move |_| Box::new(matches::Matches::new(conf))); - store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf))); - store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf))); + store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustive::new(conf))); store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf))); store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf))); store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf))); @@ -933,5 +938,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(set_contains_or_insert::SetContainsOrInsert)); store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); + store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); + store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); + store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); + store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); + store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); + store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index ba34af9c100ea..755afe959b37a 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -3,25 +3,25 @@ use clippy_utils::trait_ref_of_method; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; +use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor, + Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + walk_poly_trait_ref, walk_trait_ref, walk_ty, }; -use rustc_hir::FnRetTy::Return; use rustc_hir::{ - lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, - Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, - PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, + ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{Ident, Symbol, kw}; use std::ops::ControlFlow; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs index 73a23615c2dc7..9aa4d2f0adc2c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,4 +1,4 @@ -use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP}; +use super::{EXPLICIT_COUNTER_LOOP, IncrementVisitor, InitializeVisitor, make_iterator_snippet}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{get_enclosing_block, is_integer_const}; diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs index 5b5bb88c17908..858e3be5093ef 100644 --- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; -use hir::intravisit::{walk_expr, Visitor}; +use hir::intravisit::{Visitor, walk_expr}; use hir::{Expr, ExprKind, FnRetTy, FnSig, Node}; use rustc_ast::Label; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs index b27528c11d488..bfe2e68b5d1fa 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::MANUAL_FIND; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index dbc094a6d73fc..366c310592f57 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt}; diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs index 55d1b9ee67671..7476a87267f3b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs @@ -1,10 +1,10 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol, Span}; +use rustc_span::{Span, Symbol, sym}; use std::borrow::Cow; use super::MANUAL_WHILE_LET_SOME; diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 92ccc0cc0a15e..17215621d2aa1 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -22,15 +22,15 @@ mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::higher; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::Span; -use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; +use utils::{IncrementVisitor, InitializeVisitor, make_iterator_snippet}; declare_clippy_lint! { /// ### What it does @@ -188,22 +188,22 @@ declare_clippy_lint! { /// The `while let` loop is usually shorter and more /// readable. /// - /// ### Known problems - /// Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). - /// /// ### Example /// ```rust,no_run - /// # let y = Some(1); + /// let y = Some(1); /// loop { /// let x = match y { /// Some(x) => x, /// None => break, /// }; - /// // .. do something with x + /// // .. /// } - /// // is easier written as + /// ``` + /// Use instead: + /// ```rust,no_run + /// let y = Some(1); /// while let Some(x) = y { - /// // .. do something with x + /// // .. /// }; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index e18e4374667de..20dd5a311dca0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -3,17 +3,17 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; -use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq}; +use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, sugg}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use std::{iter, mem}; /// Checks for looping over a range and then indexing a sequence with it. diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 313a5bfefbc8d..1c55e3e22e8c1 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::NEVER_LOOP; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; @@ -7,7 +7,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::iter::once; pub(super) fn check<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 9185cf1f8b2ee..5662d3013e15b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -6,11 +6,11 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::SyntaxContext; +use rustc_span::symbol::sym; /// Detects for loop pushing the same item into a Vec pub(super) fn check<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index 2b41911e8ec79..70f76ced09a43 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -2,10 +2,10 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet, snippet_with_applicability}; use clippy_utils::visitors::contains_break_or_continue; -use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; +use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; -use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind, is_range_literal}; use rustc_lint::LateContext; use rustc_span::edition::Edition; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 7b45cc95431c2..9a89a41d2b395 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -2,13 +2,13 @@ use clippy_utils::ty::{has_iter_method, implements_trait}; use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_local, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_local}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; #[derive(Debug, PartialEq, Eq)] enum IncrementVisitorVarState { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index cc1bd5929d0fc..eab096e9a227d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Expr, ExprKind, HirIdSet, QPath}; use rustc_lint::LateContext; use std::ops::ControlFlow; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index c171fa1c622af..7d9fbaf3ceabf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -5,13 +5,13 @@ use clippy_utils::visitors::is_res_used; use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, LetStmt, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::symbol::sym; use rustc_span::Symbol; +use rustc_span::symbol::sym; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr) diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs index e215097142be9..ccc554042d685 100644 --- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -3,13 +3,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_lint_allowed; use itertools::Itertools; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; -use std::collections::btree_map::Entry; +use rustc_span::{Span, SyntaxContext, sym}; use std::collections::BTreeMap; +use std::collections::btree_map::Entry; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 067384b09015a..bd6b3f1a47b16 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::collections::BTreeMap; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 61723aec59049..fc3bba9e51232 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{position_before_rarrow, snippet_block, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -9,7 +9,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 5cbdc7f864a75..c0e87e8a1faed 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 4123c933660bc..788649fd4f90e 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; @@ -7,8 +7,8 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{ - eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, peel_blocks, - peel_blocks_with_stmt, MaybePath, + MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, + peel_blocks, peel_blocks_with_stmt, }; use itertools::Itertools; use rustc_errors::{Applicability, Diag}; @@ -17,8 +17,8 @@ use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, HirId, PatKind, PathSegme use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use std::cmp::Ordering; use std::ops::Deref; diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs new file mode 100644 index 0000000000000..00e02e2a33652 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -0,0 +1,158 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use rustc_ast::{BinOpKind, LitKind}; +use rustc_data_structures::packed::Pu128; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self}; +use rustc_session::impl_lint_pass; +use rustc_span::symbol::Symbol; + +use clippy_config::Conf; + +declare_clippy_lint! { + /// ### What it does + /// Checks for an expression like `(x + (y - 1)) / y` which is a common manual reimplementation + /// of `x.div_ceil(y)`. + /// + /// ### Why is this bad? + /// It's simpler, clearer and more readable. + /// + /// ### Example + /// ```no_run + /// let x: i32 = 7; + /// let y: i32 = 4; + /// let div = (x + (y - 1)) / y; + /// ``` + /// Use instead: + /// ```no_run + /// #![feature(int_roundings)] + /// let x: i32 = 7; + /// let y: i32 = 4; + /// let div = x.div_ceil(y); + /// ``` + #[clippy::version = "1.81.0"] + pub MANUAL_DIV_CEIL, + complexity, + "manually reimplementing `div_ceil`" +} + +pub struct ManualDivCeil { + msrv: Msrv, +} + +impl ManualDivCeil { + #[must_use] + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]); + +impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if !self.msrv.meets(msrvs::MANUAL_DIV_CEIL) { + return; + } + + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(div_op, div_lhs, div_rhs) = expr.kind + && div_op.node == BinOpKind::Div + && check_int_ty_and_feature(cx, div_lhs) + && check_int_ty_and_feature(cx, div_rhs) + && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = div_lhs.kind + { + // (x + (y - 1)) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, div_rhs) + { + build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + return; + } + + // ((y - 1) + x) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, div_rhs) + { + build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability); + return; + } + + // (x + y - 1) / y + if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Sub + && add_op.node == BinOpKind::Add + && check_literal(inner_rhs) + && check_eq_expr(cx, add_rhs, div_rhs) + { + build_suggestion(cx, expr, add_lhs, div_rhs, &mut applicability); + } + } + } + + extract_msrv_attr!(LateContext); +} + +fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr); + match expr_ty.peel_refs().kind() { + ty::Uint(_) => true, + ty::Int(_) => cx + .tcx + .features() + .declared_features + .contains(&Symbol::intern("int_roundings")), + + _ => false, + } +} + +fn check_literal(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(Pu128(1), _) = lit.node + { + return true; + } + false +} + +fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(lhs, rhs) +} + +fn build_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + lhs: &Expr<'_>, + rhs: &Expr<'_>, + applicability: &mut Applicability, +) { + let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par(); + let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); + + let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})"); + + span_lint_and_sugg( + cx, + MANUAL_DIV_CEIL, + expr.span, + "manually reimplementing `div_ceil`", + "consider using `.div_ceil()`", + sugg, + *applicability, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index 11716a539ab5c..c62bd65bea683 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 31c37c3bc3b14..24207705743d1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -1,17 +1,17 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; -use rustc_ast::ast::RangeLimits; use rustc_ast::LitKind::{Byte, Char}; +use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs new file mode 100644 index 0000000000000..da2a982ee170a --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs @@ -0,0 +1,142 @@ +use clippy_utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Uint; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0`, with x and unsigned integer, which are manual + /// reimplementations of `x.is_power_of_two()`. + /// ### Why is this bad? + /// Manual reimplementations of `is_power_of_two` increase code complexity for little benefit. + /// ### Example + /// ```no_run + /// let a: u32 = 4; + /// let result = a.count_ones() == 1; + /// ``` + /// Use instead: + /// ```no_run + /// let a: u32 = 4; + /// let result = a.is_power_of_two(); + /// ``` + #[clippy::version = "1.82.0"] + pub MANUAL_IS_POWER_OF_TWO, + complexity, + "manually reimplementing `is_power_of_two`" +} + +declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); + +impl LateLintPass<'_> for ManualIsPowerOfTwo { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(bin_op, left, right) = expr.kind + && bin_op.node == BinOpKind::Eq + { + // a.count_ones() == 1 + if let ExprKind::MethodCall(method_name, reciever, _, _) = left.kind + && method_name.ident.as_str() == "count_ones" + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && check_lit(right, 1) + { + build_sugg(cx, expr, reciever, &mut applicability); + } + + // 1 == a.count_ones() + if let ExprKind::MethodCall(method_name, reciever, _, _) = right.kind + && method_name.ident.as_str() == "count_ones" + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && check_lit(left, 1) + { + build_sugg(cx, expr, reciever, &mut applicability); + } + + // a & (a - 1) == 0 + if let ExprKind::Binary(op1, left1, right1) = left.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, left1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && check_lit(right2, 1) + && check_lit(right, 0) + { + build_sugg(cx, expr, left1, &mut applicability); + } + + // (a - 1) & a == 0; + if let ExprKind::Binary(op1, left1, right1) = left.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = left1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, right1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() + && check_lit(right2, 1) + && check_lit(right, 0) + { + build_sugg(cx, expr, right1, &mut applicability); + } + + // 0 == a & (a - 1); + if let ExprKind::Binary(op1, left1, right1) = right.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, left1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && check_lit(right2, 1) + && check_lit(left, 0) + { + build_sugg(cx, expr, left1, &mut applicability); + } + + // 0 == (a - 1) & a + if let ExprKind::Binary(op1, left1, right1) = right.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = left1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, right1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() + && check_lit(right2, 1) + && check_lit(left, 0) + { + build_sugg(cx, expr, right1, &mut applicability); + } + } + } +} + +fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, reciever: &Expr<'_>, applicability: &mut Applicability) { + let snippet = snippet_with_applicability(cx, reciever.span, "..", applicability); + + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + format!("{snippet}.is_power_of_two()"), + *applicability, + ); +} + +fn check_lit(expr: &Expr<'_>, expected_num: u128) -> bool { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(Pu128(num), _) = lit.node + && num == expected_num + { + return true; + } + false +} + +fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(lhs, rhs) +} diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index ebebdf679a863..17185df5d76fa 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -1,4 +1,4 @@ -use crate::question_mark::{QuestionMark, QUESTION_MARK}; +use crate::question_mark::{QUESTION_MARK, QuestionMark}; use clippy_config::msrvs; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_then; @@ -12,8 +12,8 @@ use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use std::slice; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs index 5198d7838a281..85e99a92cf598 100644 --- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_trait_method, peel_hir_expr_refs}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 6b1d90483ccd1..25868ccae4003 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -1,18 +1,18 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::source::SpanRangeExt; -use rustc_ast::ast::{self, VisibilityKind}; +use clippy_utils::source::snippet_indent; +use itertools::Itertools; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::{self as hir, Expr, ExprKind, QPath}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::{sym, Span}; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -62,29 +62,13 @@ declare_clippy_lint! { "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" } -#[expect(clippy::module_name_repetitions)] -pub struct ManualNonExhaustiveStruct { +pub struct ManualNonExhaustive { msrv: Msrv, -} - -impl ManualNonExhaustiveStruct { - pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } - } -} - -impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]); - -#[expect(clippy::module_name_repetitions)] -pub struct ManualNonExhaustiveEnum { - msrv: Msrv, - constructed_enum_variants: FxHashSet<(DefId, DefId)>, + constructed_enum_variants: FxHashSet, potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>, } -impl ManualNonExhaustiveEnum { +impl ManualNonExhaustive { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv.clone(), @@ -94,96 +78,78 @@ impl ManualNonExhaustiveEnum { } } -impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); - -impl EarlyLintPass for ManualNonExhaustiveStruct { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Struct(variant_data, _) = &item.kind - && let (fields, delimiter) = match variant_data { - ast::VariantData::Struct { fields, .. } => (&**fields, '{'), - ast::VariantData::Tuple(fields, _) => (&**fields, '('), - ast::VariantData::Unit(_) => return, - } - && fields.len() > 1 - && self.msrv.meets(msrvs::NON_EXHAUSTIVE) - { - let mut iter = fields.iter().filter_map(|f| match f.vis.kind { - VisibilityKind::Public => None, - VisibilityKind::Inherited => Some(Ok(f)), - VisibilityKind::Restricted { .. } => Some(Err(())), - }); - if let Some(Ok(field)) = iter.next() - && iter.next().is_none() - && field.ty.kind.is_unit() - { - span_lint_and_then( - cx, - MANUAL_NON_EXHAUSTIVE, - item.span, - "this seems like a manual implementation of the non-exhaustive pattern", - |diag| { - if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) - && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) - && let Some(snippet) = header_span.get_source_text(cx) - { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); - } - diag.span_help(field.span, "remove this field"); - }, - ); - } - } - } - - extract_msrv_attr!(EarlyContext); -} +impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); -impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { +impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) || !cx.effective_visibilities.is_exported(item.owner_id.def_id) { return; } - if let hir::ItemKind::Enum(def, _) = &item.kind - && def.variants.len() > 1 - { - let mut iter = def.variants.iter().filter_map(|v| { - (matches!(v.data, hir::VariantData::Unit(_, _)) - && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) - && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) - .then_some((v.def_id, v.span)) - }); - if let Some((id, span)) = iter.next() - && iter.next().is_none() - { - self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); - } + match item.kind { + ItemKind::Enum(def, _) if def.variants.len() > 1 => { + let iter = def.variants.iter().filter_map(|v| { + (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + .then_some((v.def_id, v.span)) + }); + if let Ok((id, span)) = iter.exactly_one() + && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + { + self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); + } + }, + ItemKind::Struct(variant_data, _) => { + let fields = variant_data.fields(); + let private_fields = fields + .iter() + .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); + if fields.len() > 1 + && let Ok(field) = private_fields.exactly_one() + && let TyKind::Tup([]) = field.ty.kind + { + span_lint_and_then( + cx, + MANUAL_NON_EXHAUSTIVE, + item.span, + "this seems like a manual implementation of the non-exhaustive pattern", + |diag| { + if let Some(non_exhaustive) = + attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + { + diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive"); + } else { + let indent = snippet_indent(cx, item.span).unwrap_or_default(); + diag.span_suggestion_verbose( + item.span.shrink_to_lo(), + "use the `#[non_exhaustive]` attribute instead", + format!("#[non_exhaustive]\n{indent}"), + Applicability::MaybeIncorrect, + ); + } + diag.span_help(field.span, "remove this field"); + }, + ); + } + }, + _ => {}, } } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind - && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res + && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), ctor_id) = p.res + && let Some(local_ctor) = ctor_id.as_local() { - let variant_id = cx.tcx.parent(id); - let enum_id = cx.tcx.parent(variant_id); - - self.constructed_enum_variants.insert((enum_id, variant_id)); + let variant_id = cx.tcx.local_parent(local_ctor); + self.constructed_enum_variants.insert(variant_id); } } fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for &(enum_id, _, enum_span, variant_span) in - self.potential_enums.iter().filter(|&&(enum_id, variant_id, _, _)| { - !self - .constructed_enum_variants - .contains(&(enum_id.to_def_id(), variant_id.to_def_id())) - }) + for &(enum_id, _, enum_span, variant_span) in self + .potential_enums + .iter() + .filter(|(_, variant_id, _, _)| !self.constructed_enum_variants.contains(variant_id)) { let hir_id = cx.tcx.local_def_id_to_hir_id(enum_id); span_lint_hir_and_then( @@ -193,15 +159,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); - if let Some(snippet) = header_span.get_source_text(cx) { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); - } + let indent = snippet_indent(cx, enum_span).unwrap_or_default(); + diag.span_suggestion_verbose( + enum_span.shrink_to_lo(), + "use the `#[non_exhaustive]` attribute instead", + format!("#[non_exhaustive]\n{indent}"), + Applicability::MaybeIncorrect, + ); diag.span_help(variant_span, "remove this variant"); }, ); diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index 9afb2b5bc84cd..ffa3eacf3544f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; declare_clippy_lint! { /// ### What it does @@ -77,9 +77,10 @@ impl Num { impl LateLintPass<'_> for ManualRangePatterns { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives - // or at least one range + // or more then one range (exclude triggering on stylistic using OR with one element + // like described https://github.com/rust-lang/rust-clippy/issues/11825) if let PatKind::Or(pats) = pat.kind - && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))) + && (pats.len() >= 3 || (pats.len() > 1 && pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))) && !in_external_macro(cx.sess(), pat.span) { let mut min = Num::dummy(i128::MAX); diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index 6cf5d272d7d82..86293169ea28c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index a35b0f914e058..a60163be770d0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -1,17 +1,17 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; +use rustc_hir::def_id::DefId; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; const ACCEPTABLE_METHODS: [Symbol; 5] = [ sym::binaryheap_iter, diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index 781db4b97f083..198f7aaddc71b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, symbol, Span}; +use rustc_span::{Span, sym, symbol}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 02d433ecc5aaa..9aceca66bf774 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; @@ -8,13 +8,13 @@ use clippy_utils::{eq_expr_value, higher}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 2db71b1f7a388..a97dbbbc33fd0 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index b666e77c09ecb..50e6dfc6298dc 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -4,7 +4,7 @@ use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; use clippy_utils::{ - is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq, + SpanlessEq, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, }; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; @@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; -use super::{pat_contains_disallowed_or, COLLAPSIBLE_MATCH}; +use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or}; pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs index 619ec83127aba..cfa054706d6bf 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs @@ -6,10 +6,10 @@ use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; -use super::manual_utils::{check_with, SomeExpr}; use super::MANUAL_FILTER; +use super::manual_utils::{SomeExpr, check_with}; // Function called on the of `[&+]Some((ref | ref mut) x) => ` // Need to check if it's of the form `=if {} else {}` diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs index ed3d8b09fdcda..de57d1eee9249 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs @@ -1,5 +1,5 @@ -use super::manual_utils::{check_with, SomeExpr}; use super::MANUAL_MAP; +use super::manual_utils::{SomeExpr, check_with}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_res_lang_ctor, path_res}; diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs index d5d83df93471c..59d3752001178 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,12 +1,12 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{OptionNone, ResultErr}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index be80aebed6dfb..d38560998a5a7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -4,16 +4,16 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ - can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, - peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, + CaptureKind, can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, + path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, }; use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::def::Res; use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; #[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_lines)] diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index da8c918a62bb6..f9ffbc5dc0b8e 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same}; use core::cmp::Ordering; use core::{iter, slice}; use rustc_arena::DroplessArena; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 322e9c3ebe5b3..40518ce2ca775 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use super::MATCH_STR_CASE_MISMATCH; diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index cf5377e0725dd..686fc4a0fa0a5 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -24,8 +24,8 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index 71f211be925bf..6a4c553cee0ee 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{mir_to_const, ConstEvalCtxt, FullInt}; +use clippy_utils::consts::{ConstEvalCtxt, FullInt, mir_to_const}; use clippy_utils::diagnostics::span_lint_and_note; use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 8222c3057f73e..564c598a334c7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -10,11 +10,11 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use std::borrow::Cow; use std::ops::ControlFlow; -use super::{pat_contains_disallowed_or, REDUNDANT_GUARDS}; +use super::{REDUNDANT_GUARDS, pat_contains_disallowed_or}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) { for outer_arm in arms { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 0e4b2d9d34a02..b646e87a43930 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,18 +1,18 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, walk_span_to_context}; -use clippy_utils::sugg::{make_unop, Sugg}; +use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; use clippy_utils::{higher, is_expn_of, is_trait_method}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use std::fmt::Write; use std::ops::ControlFlow; diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 9c2f42d218702..537f7272f7f34 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -8,7 +8,7 @@ use clippy_utils::{get_attr, is_lint_allowed}; use itertools::Itertools; use rustc_ast::Mutability; use rustc_errors::{Applicability, Diag}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor}; diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index b6930f7b9d10f..2eda238ae8cdb 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, expr_block, snippet, snippet_block_with_context}; use clippy_utils::ty::implements_trait; use clippy_utils::{ is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, @@ -8,11 +8,11 @@ use core::ops::ControlFlow; use rustc_arena::DroplessArena; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_pat, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath}; +use rustc_hir::intravisit::{Visitor, walk_pat}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; @@ -91,6 +91,29 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); + if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") { + let msg = "this pattern is irrefutable, `match` is useless"; + let (sugg, help) = if is_unit_expr(arm.body) { + (String::new(), "`match` expression can be removed") + } else { + let mut sugg = snippet_block_with_context(cx, arm.body.span, ctxt, "..", Some(expr.span), &mut app) + .0 + .to_string(); + if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) + && let StmtKind::Expr(_) = stmt.kind + && match arm.body.kind { + ExprKind::Block(block, _) => block.span.from_expansion(), + _ => true, + } + { + sugg.push(';'); + } + (sugg, "try") + }; + span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg.to_string(), app); + return; + } + let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat); let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 72a5945ad9bca..146748734cff4 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; @@ -13,8 +13,8 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index 2a8a5fcc3b6f9..91a5de16e9670 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,4 +1,4 @@ -use super::{contains_return, BIND_INSTEAD_OF_MAP}; +use super::{BIND_INSTEAD_OF_MAP, contains_return}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, snippet_with_context}; diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 740cce0a6c235..76bdbe55e2f3b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; diff --git a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs index 5389861245a28..6e24cabca8bba 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs @@ -4,8 +4,8 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::CLEAR_WITH_DRAIN; diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index e7a2060be046a..79a473e0e6f58 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -7,7 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::CLONE_ON_COPY; diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index e0826b53004b6..96e2de0dc1cbd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::CLONE_ON_REF_PTR; diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index fcafa16223658..fa04f74eec107 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::CLONED_INSTEAD_OF_COPIED; diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs index 1fab6c0e499d4..f7bf8764bdebc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::LateContext; use std::collections::VecDeque; -use super::{method_call, COLLAPSIBLE_STR_REPLACE}; +use super::{COLLAPSIBLE_STR_REPLACE, method_call}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs index 56171a134522d..10360b4817bc9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; /// Checks if both types match the given diagnostic item, e.g.: /// diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs index dc978c8a58456..3b1adb16b80e9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check( cx: &LateContext<'_>, diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index c9f56e1d98097..2922086522c2a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use std::borrow::Cow; use super::EXPECT_FUN_CALL; diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs index 2ab0401947c4c..35008c39c084d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs @@ -3,7 +3,7 @@ use clippy_utils::get_parent_expr; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FILETYPE_IS_FILE; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 02a11257007a9..06482a743ddf4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks}; use hir::{Body, HirId, MatchSource, Pat}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -10,8 +10,8 @@ use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, sym}; use std::borrow::Cow; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 77a62fbb4fb92..129e692542894 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -7,9 +7,9 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::Binder; -use rustc_span::{sym, Span}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_span::{Span, sym}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { if !in_external_macro(cx.sess(), expr.span) diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs index 999df875c753f..cf7f276dabb10 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FILTER_MAP_IDENTITY; diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs index 651ea34f9d0e8..0c2ecfbc8ffdf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FLAT_MAP_IDENTITY; diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs index 0a4a381b86186..3242dcadb7013 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FLAT_MAP_OPTION; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs index 6203765113428..5f6fb4c821d57 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_integer_literal, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index 230a8eb2ec47a..4ed7de81ea3d0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::INEFFICIENT_TO_STRING; diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs index ad4b6fa130e35..3706f3b670ba1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::INSPECT_FOR_EACH; diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs index bbc7ce8d78ab9..bedeb63367d06 100644 --- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs @@ -5,8 +5,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use super::INTO_ITER_ON_REF; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs index b93d51eac647b..f6612c984a7eb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs @@ -10,8 +10,8 @@ use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::QPath; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, sym}; use std::borrow::Cow; /// diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 33de3b87abc82..390dd24b5058d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -14,7 +14,6 @@ use rustc_span::sym; /// - `hashmap.into_iter().map(|(_, v)| v)` /// /// on `HashMaps` and `BTreeMaps` in std - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, map_type: &'tcx str, // iter / into_iter diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs index e31fa2f777d8e..82bda5d951225 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs @@ -3,8 +3,8 @@ use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::ITER_NTH; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 7f6b666e434e9..9d562f5e51d2c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -5,9 +5,9 @@ use clippy_utils::source::snippet; use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirId; -use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs index 1378a07cbc477..163058713377b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs @@ -3,8 +3,8 @@ use clippy_utils::is_range_full; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::ITER_WITH_DRAIN; diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs index 2dad7fcf3c129..2ad070793cbb2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs @@ -6,8 +6,8 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::JOIN_ABSOLUTE_PATHS; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs index cb9fb373c10a6..96af9db1af709 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs @@ -6,7 +6,7 @@ use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use super::MANUAL_C_STR_LITERALS; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index cac2e11f59166..64c19c327b254 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -3,13 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; -use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::MANUAL_INSPECT; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs index d29acd4622a0b..c377abd62377a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MANUAL_IS_VARIANT_AND; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs index b1a8e1e5e4709..4321dd6b0e098 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index 11fba35c16ea3..31449d417701c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MANUAL_TRY_FOLD; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index 08ce7e204dd27..ac378ff3702bb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MAP_CLONE; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs index 22a03825194e0..07a7a12b16279 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::MAP_FLATTEN; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs index 5dd7b1b02adef..1f204de01da06 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MAP_IDENTITY; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index f61bb3a6bf481..7696dd16b251c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -111,6 +111,7 @@ mod uninit_assumed_init; mod unit_hash; mod unnecessary_fallible_conversions; mod unnecessary_filter_map; +mod unnecessary_first_then_check; mod unnecessary_fold; mod unnecessary_get_then_check; mod unnecessary_iter_cloned; @@ -131,8 +132,8 @@ mod waker_clone_wake; mod wrong_self_convention; mod zst_offset; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::FormatArgsStorage; @@ -146,7 +147,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -441,6 +442,17 @@ declare_clippy_lint! { /// } /// } /// ``` + /// + /// Use instead: + /// ```no_run + /// # struct X; + /// impl X { + /// fn as_str(&self) -> &'static str { + /// // .. + /// # "" + /// } + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub WRONG_SELF_CONVENTION, style, @@ -3964,7 +3976,7 @@ declare_clippy_lint! { /// ```no_run /// let _ = 0; /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub UNNECESSARY_MIN_OR_MAX, complexity, "using 'min()/max()' when there is no need for it" @@ -4025,7 +4037,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MANUAL_C_STR_LITERALS, - pedantic, + complexity, r#"creating a `CStr` through functions when `c""` literals can be used"# } @@ -4099,7 +4111,7 @@ declare_clippy_lint! { /// ```no_run /// "foo".is_ascii(); /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub NEEDLESS_CHARACTER_ITERATION, suspicious, "is_ascii() called on a char iterator" @@ -4126,6 +4138,34 @@ declare_clippy_lint! { "use of `map` returning the original item" } +declare_clippy_lint! { + /// ### What it does + /// Checks the usage of `.first().is_some()` or `.first().is_none()` to check if a slice is + /// empty. + /// + /// ### Why is this bad? + /// Using `.is_empty()` is shorter and better communicates the intention. + /// + /// ### Example + /// ```no_run + /// let v = vec![1, 2, 3]; + /// if v.first().is_none() { + /// // The vector is empty... + /// } + /// ``` + /// Use instead: + /// ```no_run + /// let v = vec![1, 2, 3]; + /// if v.is_empty() { + /// // The vector is empty... + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub UNNECESSARY_FIRST_THEN_CHECK, + complexity, + "calling `.first().is_some()` or `.first().is_none()` instead of `.is_empty()`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4283,6 +4323,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, + UNNECESSARY_FIRST_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, MANUAL_INSPECT, UNNECESSARY_MIN_OR_MAX, @@ -5055,6 +5096,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, Some(("get", f_recv, [arg], _, _)) => { unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some); }, + Some(("first", f_recv, [], _, _)) => { + unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); + }, _ => {}, } } @@ -5130,12 +5174,9 @@ impl ShouldImplTraitCase { fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool { self.lint_explicit_lifetime || !impl_item.generics.params.iter().any(|p| { - matches!( - p.kind, - hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Explicit - } - ) + matches!(p.kind, hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + }) }) } } diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs index 1a0fce2876d40..83e8370f939bc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MUT_MUTEX_LOCK; diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs index 332da722a37dc..348f740e7ddf7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -4,8 +4,8 @@ use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use super::utils::get_last_chain_binding_hir_id; use super::NEEDLESS_CHARACTER_ITERATION; +use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::SpanRangeExt; use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index f61923e5bf569..421c7a5e070d9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -4,12 +4,12 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection}; use clippy_utils::{ - can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id, - CaptureKind, + CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, + path_to_local_id, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{ BindingMode, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind, }; @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs index 9f714fdd47bb3..538aa9097a40f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs @@ -4,8 +4,8 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::Expr; +use rustc_hir::def::Res; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs index a301a5f7d65be..32f32f1b21673 100644 --- a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs +++ b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs @@ -1,6 +1,6 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::SpanlessEq; use rustc_ast::LitKind; use rustc_hir::{ExprKind, LangItem}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index f1a3c81cebbdb..da084871402a7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; @@ -126,17 +126,13 @@ fn get_open_options( && let ExprKind::Path(path) = callee.kind && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() { - let std_file_options = [ - sym::file_options, - sym::open_options_new, - ]; + let std_file_options = [sym::file_options, sym::open_options_new]; - let tokio_file_options: &[&[&str]] = &[ - &paths::TOKIO_IO_OPEN_OPTIONS_NEW, - &paths::TOKIO_FILE_OPTIONS, - ]; + let tokio_file_options: &[&[&str]] = &[&paths::TOKIO_IO_OPEN_OPTIONS_NEW, &paths::TOKIO_FILE_OPTIONS]; - let is_std_options = std_file_options.into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, did)); + let is_std_options = std_file_options + .into_iter() + .any(|sym| cx.tcx.is_diagnostic_item(sym, did)); is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some() } else { false diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs index ba167f9d9c230..9b22494888fb2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -3,9 +3,9 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; -use super::{method_call, OPTION_AS_REF_CLONED}; +use super::{OPTION_AS_REF_CLONED, method_call}; pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 9a18d8a14219f..389e02056b2b8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::OPTION_AS_REF_DEREF; @@ -48,7 +48,9 @@ pub(super) fn check( .map_or(false, |fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) - || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) + || deref_aliases + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) }) }, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { @@ -69,7 +71,9 @@ pub(super) fn check( let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) - || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) + || deref_aliases + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index ed3bed42eb3a9..b160ab6de8e95 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -5,11 +5,11 @@ use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::ops::ControlFlow; use super::MAP_UNWRAP_OR; diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index af71799f0a731..c60a839432c97 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -11,8 +11,8 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{self, Symbol, sym}; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs index 7b0bdcf99e736..3e64e15dc8602 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::lang_items::LangItem; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::OR_THEN_UNWRAP; diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs index 28ca76832eb3a..f4d206c5307c1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; -use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, is_integer_const, is_trait_method}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index 3b2dd285b8c99..4ab165a5528bb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -8,8 +8,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs index 8bc535ac47a84..7ef07fe899c08 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs @@ -6,9 +6,9 @@ use rustc_lint::LateContext; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_enum_variant_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::is_enum_variant_ctor; use super::SEEK_FROM_CURRENT; diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7c09cc252e13a..9c966f010f130 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_used_or_unified, is_enum_variant_ctor}; +use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::SEEK_TO_START_INSTEAD_OF_REWIND; diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 12cabd43cb1b2..69032776b2b9f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -12,7 +12,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span, Symbol, SyntaxContext}; +use rustc_span::{Span, Symbol, SyntaxContext, sym}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs index 38f2c9169124a..c60a49067ec09 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::{Applicability, Diag}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs index db8cc4595d4df..e67ba5c4d3148 100644 --- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs +++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs @@ -7,7 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self, ExistentialPredicate, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; /// Checks if the given type is `dyn Any`, or a trait object that has `Any` as a supertrait. /// Only in those cases will its vtable have a `type_id` method that returns the implementor's diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index d46b584f8f444..ce81282ddfeb0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_FALLIBLE_CONVERSIONS; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index c9b9d98dbe607..ca46da81fa053 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_first_then_check.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_first_then_check.rs new file mode 100644 index 0000000000000..7ae1bb54e6098 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -0,0 +1,56 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::SpanRangeExt; + +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::UNNECESSARY_FIRST_THEN_CHECK; + +pub(super) fn check( + cx: &LateContext<'_>, + call_span: Span, + first_call: &Expr<'_>, + first_caller: &Expr<'_>, + is_some: bool, +) { + if !cx + .typeck_results() + .expr_ty_adjusted(first_caller) + .peel_refs() + .is_slice() + { + return; + } + + let ExprKind::MethodCall(_, _, _, first_call_span) = first_call.kind else { + return; + }; + + let both_calls_span = first_call_span.with_hi(call_span.hi()); + if let Some(both_calls_snippet) = both_calls_span.get_source_text(cx) + && let Some(first_caller_snippet) = first_caller.span.get_source_text(cx) + { + let (sugg_span, suggestion) = if is_some { + ( + first_caller.span.with_hi(call_span.hi()), + format!("!{first_caller_snippet}.is_empty()"), + ) + } else { + (both_calls_span, "is_empty()".to_owned()) + }; + span_lint_and_sugg( + cx, + UNNECESSARY_FIRST_THEN_CHECK, + sugg_span, + format!( + "unnecessary use of `{both_calls_snippet}` to check if slice {}", + if is_some { "is not empty" } else { "is empty" } + ), + "replace this with", + suggestion, + Applicability::MaybeIncorrect, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index ccc8d17970ece..b5d8972d7aad5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_FOLD; @@ -123,58 +123,32 @@ pub(super) fn check( if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Or, - Replacement { - has_args: true, - has_generic_return: false, - method_name: "any", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement { + has_args: true, + has_generic_return: false, + method_name: "any", + }); }, ast::LitKind::Bool(true) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::And, - Replacement { - has_args: true, - has_generic_return: false, - method_name: "all", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement { + has_args: true, + has_generic_return: false, + method_name: "all", + }); }, - ast::LitKind::Int(Pu128(0), _) => check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Add, - Replacement { + ast::LitKind::Int(Pu128(0), _) => { + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement { has_args: false, has_generic_return: needs_turbofish(cx, expr), method_name: "sum", - }, - ), + }); + }, ast::LitKind::Int(Pu128(1), _) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Mul, - Replacement { - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - method_name: "product", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "product", + }); }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs index 64eb84117954c..39fce2c40c91d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_GET_THEN_CHECK; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 4d18bc7ac7777..029704882dde2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -10,7 +10,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::UNNECESSARY_TO_OWNED; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 494d71fc053f6..6dc8adb42dfbe 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath}; +use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs index 86c0a6322b666..062d1348555cd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -1,16 +1,15 @@ use std::cmp::Ordering; use super::UNNECESSARY_MIN_OR_MAX; -use clippy_utils::diagnostics::span_lint_and_sugg; - use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Span; +use rustc_span::{Span, sym}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -21,26 +20,30 @@ pub(super) fn check<'tcx>( ) { let typeck_results = cx.typeck_results(); let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results); - if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) - && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) + if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id) + && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id)) { - let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { - return; - }; + if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) + && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) + { + let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { + return; + }; - lint(cx, expr, name, recv.span, arg.span, ord); - } else if let Some(extrema) = detect_extrema(cx, recv) { - let ord = match extrema { - Extrema::Minimum => Ordering::Less, - Extrema::Maximum => Ordering::Greater, - }; - lint(cx, expr, name, recv.span, arg.span, ord); - } else if let Some(extrema) = detect_extrema(cx, arg) { - let ord = match extrema { - Extrema::Minimum => Ordering::Greater, - Extrema::Maximum => Ordering::Less, - }; - lint(cx, expr, name, recv.span, arg.span, ord); + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, recv) { + let ord = match extrema { + Extrema::Minimum => Ordering::Less, + Extrema::Maximum => Ordering::Greater, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, arg) { + let ord = match extrema { + Extrema::Minimum => Ordering::Greater, + Extrema::Maximum => Ordering::Less, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index c14a87c153414..dc50717112d89 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -8,8 +8,8 @@ use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use super::utils::get_last_chain_binding_hir_id; use super::UNNECESSARY_RESULT_MAP_OR_ELSE; +use super::utils::get_last_chain_binding_hir_id; fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { let msg = "unused \"map closure\" when calling `Result::map_or_else` value"; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index bf7555a29e220..cfa1fdb81372f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,12 +2,11 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ - fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, - return_ty, + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, return_ty, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -20,7 +19,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -717,7 +716,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx // check that: // 1. This is a method with only one argument that doesn't come from a trait. // 2. That it has `Borrow` in its generic predicates. -// 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, BTreeSet`, `BTreeMap`). +// 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`). fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs index ee5177d1ffaa1..6c2ae9cc6bffd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::AdtDef; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use crate::loops::UNUSED_ENUMERATE_INDEX; diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs index ebad4ae6ee95d..eafe7486bb05a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -9,7 +9,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use core::ops::ControlFlow; diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index fe860e5ae2601..4e33dc1df54d8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -1,12 +1,12 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs index 3e271a606115a..5ea4ada128a24 100644 --- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::VEC_RESIZE_TO_ZERO; diff --git a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs index 9b64cc7589ccc..b5f34a9be2e23 100644 --- a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs +++ b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; use clippy_utils::is_trait_method; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index c83e5198c2748..a99e21d938c64 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_item, walk_trait_item, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index a9aafe7ed56cb..408dbef9cb16a 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -2,11 +2,12 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment, - SpanlessEq, + SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, + last_path_segment, }; use rustc_errors::Applicability; use rustc_hir::def::Res; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::intravisit::FnKind; use rustc_hir::{ BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, @@ -14,8 +15,8 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use crate::ref_patterns::REF_PATTERNS; @@ -80,6 +81,45 @@ declare_clippy_lint! { "using a binding which is prefixed with an underscore" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the use of item with a single leading + /// underscore. + /// + /// ### Why is this bad? + /// A single leading underscore is usually used to indicate + /// that a item will not be used. Using such a item breaks this + /// expectation. + /// + /// ### Example + /// ```no_run + /// fn _foo() {} + /// + /// struct _FooStruct {} + /// + /// fn main() { + /// _foo(); + /// let _ = _FooStruct{}; + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// fn foo() {} + /// + /// struct FooStruct {} + /// + /// fn main() { + /// foo(); + /// let _ = FooStruct{}; + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub USED_UNDERSCORE_ITEMS, + pedantic, + "using a item which is prefixed with an underscore" +} + declare_clippy_lint! { /// ### What it does /// Checks for the use of short circuit boolean conditions as @@ -104,6 +144,7 @@ declare_clippy_lint! { declare_lint_pass!(LintPass => [ TOPLEVEL_REF_ARG, USED_UNDERSCORE_BINDING, + USED_UNDERSCORE_ITEMS, SHORT_CIRCUIT_STATEMENT, ]); @@ -205,51 +246,104 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { { return; } - let (definition_hir_id, ident) = match expr.kind { - ExprKind::Path(ref qpath) => { - if let QPath::Resolved(None, path) = qpath - && let Res::Local(id) = path.res - && is_used(cx, expr) - { - (id, last_path_segment(qpath).ident) - } else { - return; - } - }, - ExprKind::Field(recv, ident) => { - if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def() - && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name) - && let Some(local_did) = field.did.as_local() - && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data() - { - (cx.tcx.local_def_id_to_hir_id(local_did), ident) - } else { - return; - } + + used_underscore_binding(cx, expr); + used_underscore_items(cx, expr); + } +} + +fn used_underscore_items<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (def_id, ident) = match expr.kind { + ExprKind::Call(func, ..) => { + if let ExprKind::Path(QPath::Resolved(.., path)) = func.kind + && let Some(last_segment) = path.segments.last() + && let Res::Def(_, def_id) = last_segment.res + { + (def_id, last_segment.ident) + } else { + return; + } + }, + ExprKind::MethodCall(path, ..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + (def_id, path.ident) + } else { + return; + } + }, + ExprKind::Struct(QPath::Resolved(_, path), ..) => { + if let Some(last_segment) = path.segments.last() + && let Res::Def(_, def_id) = last_segment.res + { + (def_id, last_segment.ident) + } else { + return; + } + }, + _ => return, + }; + + let name = ident.name.as_str(); + let definition_span = cx.tcx.def_span(def_id); + if name.starts_with('_') + && !name.starts_with("__") + && !definition_span.from_expansion() + && def_id.krate == LOCAL_CRATE + { + span_lint_and_then( + cx, + USED_UNDERSCORE_ITEMS, + expr.span, + "used underscore-prefixed item".to_string(), + |diag| { + diag.span_note(definition_span, "item is defined here".to_string()); }, - _ => return, - }; + ); + } +} - let name = ident.name.as_str(); - if name.starts_with('_') - && !name.starts_with("__") - && let definition_span = cx.tcx.hir().span(definition_hir_id) - && !definition_span.from_expansion() - && !fulfill_or_allowed(cx, USED_UNDERSCORE_BINDING, [expr.hir_id, definition_hir_id]) - { - span_lint_and_then( - cx, - USED_UNDERSCORE_BINDING, - expr.span, - format!( - "used binding `{name}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used" - ), - |diag| { - diag.span_note(definition_span, format!("`{name}` is defined here")); - }, - ); - } +fn used_underscore_binding<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (definition_hir_id, ident) = match expr.kind { + ExprKind::Path(ref qpath) => { + if let QPath::Resolved(None, path) = qpath + && let Res::Local(id) = path.res + && is_used(cx, expr) + { + (id, last_path_segment(qpath).ident) + } else { + return; + } + }, + ExprKind::Field(recv, ident) => { + if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def() + && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name) + && let Some(local_did) = field.did.as_local() + && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data() + { + (cx.tcx.local_def_id_to_hir_id(local_did), ident) + } else { + return; + } + }, + _ => return, + }; + + let name = ident.name.as_str(); + if name.starts_with('_') + && !name.starts_with("__") + && let definition_span = cx.tcx.hir().span(definition_hir_id) + && !definition_span.from_expansion() + && !fulfill_or_allowed(cx, USED_UNDERSCORE_BINDING, [expr.hir_id, definition_hir_id]) + { + span_lint_and_then( + cx, + USED_UNDERSCORE_BINDING, + expr.span, + "used underscore-prefixed binding".to_string(), + |diag| { + diag.span_note(definition_span, "binding is defined here".to_string()); + }, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs index a9ea11f4c2b06..86348f04600b8 100644 --- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs +++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, find_assert_eq_args, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 94c91b095171f..b40d7eba15e5e 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -1,7 +1,7 @@ use std::mem; use std::ops::ControlFlow; -use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; @@ -14,7 +14,7 @@ use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 859afe1b9636e..eea0459e026e8 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; @@ -11,8 +11,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs index 954216038fb58..c2f524a635316 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs @@ -1,12 +1,12 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{intravisit, Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym::{self, thread_local_macro}; diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 2166b0fe5a06d..64fc1a8a1a580 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -17,7 +17,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 77595b121aadb..fc01b6753f1c7 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{Visitable, for_each_expr}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 33a14d8b7fed3..d342be4545cea 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -3,7 +3,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index 0b3769ecb7cc4..d333b71edb1ae 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -134,6 +135,11 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { + if let Some(macro_call) = root_macro_call_first_node(self.cx, e) { + if self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { + return; + } + } span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges"); } } diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 0bde0da3cd814..12bcc608174f2 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{for_each_expr, Descend, Visitable}; +use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp}; @@ -153,19 +153,16 @@ fn collect_unsafe_exprs<'tcx>( ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => { if matches!( lhs.kind, - ExprKind::Path(QPath::Resolved( - _, - hir::Path { - res: Res::Def( - DefKind::Static { - mutability: Mutability::Mut, - .. - }, - _ - ), - .. - } - )) + ExprKind::Path(QPath::Resolved(_, hir::Path { + res: Res::Def( + DefKind::Static { + mutability: Mutability::Mut, + .. + }, + _ + ), + .. + })) ) { unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); collect_unsafe_exprs(cx, rhs, unsafe_ops); diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index f52b3a6a5a160..8118c14bd4a28 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -6,9 +6,9 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::Span; use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index e92ba93942eff..785bf70a3ec9f 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 60c44382059a5..3c47d0edfdc5b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -3,8 +3,8 @@ use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, P use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index df155a7a41257..2eacd6875d6b4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -2,16 +2,16 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, is_receiver_of_method_call, - peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, + SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, + is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 32e7fde03b2c8..f6db12ed84e86 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,10 +1,10 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; +use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir, expr_local, local_assignments, used_exactly_once}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; +use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_n_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 6390e51f916b2..b54eb164e81d5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -1,9 +1,9 @@ use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 62e41088f3708..bb44ff37b203b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// /// // or choose alternative bounds for `T` so that it can be unsized /// ``` - #[clippy::version = "1.79.0"] + #[clippy::version = "1.81.0"] pub NEEDLESS_MAYBE_SIZED, suspicious, "a `?Sized` bound that is unusable due to a `Sized` requirement" diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index d543fd467abe7..19cbf59590840 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -17,9 +17,9 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::Span; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index addb4b1aee807..0775d7abdbb37 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_self; use clippy_utils::ptr::get_spans; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }) .collect::>(); - // Collect moved variables and spans which will need dereferencings from the + // Collect moved variables and spans which will need dereferencing from the // function body. let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); @@ -148,12 +148,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { return; } - // Ignore `self`s. - if idx == 0 { - if let PatKind::Binding(.., ident, _) = arg.pat.kind { - if ident.name == kw::SelfLower { - continue; - } + // Ignore `self`s and params whose variable name starts with an underscore + if let PatKind::Binding(.., ident, _) = arg.pat.kind { + if idx == 0 && ident.name == kw::SelfLower { + continue; + } + if ident.name.as_str().starts_with('_') { + continue; } } @@ -181,14 +182,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.param_env) && !allowed_traits.iter().any(|&t| { - implements_trait_with_env_from_iter( - cx.tcx, - cx.param_env, - ty, - t, - None, - [Option::>::None], - ) + implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< + ty::GenericArg<'tcx>, + >::None]) }) && !implements_borrow_trait && !all_borrowable_trait @@ -207,7 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ) .is_ok() { - diag.span_help(span, "consider marking this type as `Copy`"); + diag.span_help(span, "or consider marking this type as `Copy`"); } } } diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index b181791699a5b..392cfcb813e85 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -7,8 +7,8 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, - Stmt, StmtKind, UnsafeSource, + BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, Stmt, StmtKind, + UnsafeSource, is_range_literal, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 25f547f1a43c0..5e20b40642607 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -4,7 +4,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::{implements_trait, InteriorMut}; +use clippy_utils::ty::{InteriorMut, implements_trait}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 832518d2d35b4..d85032e9eee84 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -3,12 +3,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use rustc_ast::ast::{ self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, }; -use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; +use rustc_ast::visit::{Visitor, walk_block, walk_expr, walk_pat}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index cfc15d9271583..3f156aa551040 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs new file mode 100644 index 0000000000000..90a9f2e994b81 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs @@ -0,0 +1,143 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use rustc_ast::ast::BinOpKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for conversions from `NonZero` types to regular integer types, + /// and suggests using `NonZero` types for the target as well. + /// + /// ### Why is this bad? + /// Converting from `NonZero` types to regular integer types and then back to `NonZero` + /// types is less efficient and loses the type-safety guarantees provided by `NonZero` types. + /// Using `NonZero` types consistently can lead to more optimized code and prevent + /// certain classes of errors related to zero values. + /// + /// ### Example + /// ```no_run + /// use std::num::{NonZeroU32, NonZeroU64}; + /// + /// fn example(x: u64, y: NonZeroU32) { + /// // Bad: Converting NonZeroU32 to u64 unnecessarily + /// let r1 = x / u64::from(y.get()); + /// let r2 = x % u64::from(y.get()); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// use std::num::{NonZeroU32, NonZeroU64}; + /// + /// fn example(x: u64, y: NonZeroU32) { + /// // Good: Preserving the NonZero property + /// let r1 = x / NonZeroU64::from(y); + /// let r2 = x % NonZeroU64::from(y); + /// } + /// ``` + #[clippy::version = "1.81.0"] + pub NON_ZERO_SUGGESTIONS, + restriction, + "suggests using `NonZero#` from `u#` or `i#` for more efficient and type-safe conversions" +} + +declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]); + +impl<'tcx> LateLintPass<'tcx> for NonZeroSuggestions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Binary(op, _, rhs) = expr.kind + && matches!(op.node, BinOpKind::Div | BinOpKind::Rem) + { + check_non_zero_conversion(cx, rhs, Applicability::MachineApplicable); + } else { + // Check if the parent expression is a binary operation + let parent_is_binary = cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { + matches!(node, rustc_hir::Node::Expr(parent_expr) if matches!(parent_expr.kind, ExprKind::Binary(..))) + }); + + if !parent_is_binary { + check_non_zero_conversion(cx, expr, Applicability::MaybeIncorrect); + } + } + } +} + +fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicability: Applicability) { + // Check if the expression is a function call with one argument + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(qpath) = &func.kind + && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() + && let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind + && rcv_path.ident.name.as_str() == "get" + { + let fn_name = cx.tcx.item_name(def_id); + let target_ty = cx.typeck_results().expr_ty(expr); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + + // Check if the receiver type is a NonZero type + if let ty::Adt(adt_def, _) = receiver_ty.kind() + && adt_def.is_struct() + && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + { + if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { + let arg_snippet = get_arg_snippet(cx, arg, rcv_path); + suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability); + } + } + } +} + +fn get_arg_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, rcv_path: &rustc_hir::PathSegment<'_>) -> String { + let arg_snippet = snippet(cx, arg.span, ".."); + if let Some(index) = arg_snippet.rfind(&format!(".{}", rcv_path.ident.name)) { + arg_snippet[..index].trim().to_string() + } else { + arg_snippet.to_string() + } +} + +fn suggest_non_zero_conversion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + fn_name: rustc_span::Symbol, + target_non_zero_type: &str, + arg_snippet: &str, + applicability: Applicability, +) { + let suggestion = format!("{target_non_zero_type}::{fn_name}({arg_snippet})"); + span_lint_and_sugg( + cx, + NON_ZERO_SUGGESTIONS, + expr.span, + format!("consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion"), + "replace with", + suggestion, + applicability, + ); +} + +fn get_target_non_zero_type(ty: Ty<'_>) -> Option<&'static str> { + match ty.kind() { + ty::Uint(uint_ty) => Some(match uint_ty { + ty::UintTy::U8 => "NonZeroU8", + ty::UintTy::U16 => "NonZeroU16", + ty::UintTy::U32 => "NonZeroU32", + ty::UintTy::U64 => "NonZeroU64", + ty::UintTy::U128 => "NonZeroU128", + ty::UintTy::Usize => "NonZeroUsize", + }), + ty::Int(int_ty) => Some(match int_ty { + ty::IntTy::I8 => "NonZeroI8", + ty::IntTy::I16 => "NonZeroI16", + ty::IntTy::I32 => "NonZeroI32", + ty::IntTy::I64 => "NonZeroI64", + ty::IntTy::I128 => "NonZeroI128", + ty::IntTy::Isize => "NonZeroIsize", + }), + _ => None, + } +} diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index 51ba29d7389b9..a13391a59457a 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,5 +1,5 @@ -use clippy_config::types::MacroMatcher; use clippy_config::Conf; +use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SourceText, SpanRangeExt}; use rustc_ast::ast; @@ -8,8 +8,8 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; +use rustc_span::hygiene::{ExpnKind, MacroKind}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index aadd729f32a45..372128ac16f0f 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -9,8 +9,8 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKi use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, kw}; use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs index a0de5ea711ca0..dbc9948eeedc7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -2,7 +2,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs index c131752439628..5d94cfab3b02a 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -7,12 +7,12 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; -use clippy_utils::SpanlessEq; use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS}; diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs index be97ad389bf60..34f7dbea84e49 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs @@ -6,7 +6,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, source_map::Spanned}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; use super::FLOAT_EQUALITY_WITHOUT_ABS; diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index ae02d22512e31..6d9e75f51d66e 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::{ - can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, - peel_blocks, peel_hir_expr_while, CaptureKind, + CaptureKind, can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, + is_res_lang_ctor, peel_blocks, peel_hir_expr_while, }; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::Res; use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index 381975199d285..eebc62e2a5a96 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -1,15 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; +use clippy_utils::{is_inside_always_const_context, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -68,10 +68,12 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; - if matches!( - cx.tcx.item_name(macro_call.def_id).as_str(), - "panic" | "assert" | "assert_eq" | "assert_ne" - ) { + if !is_inside_always_const_context(cx.tcx, e.hir_id) + && matches!( + cx.tcx.item_name(macro_call.def_id).as_str(), + "panic" | "assert" | "assert_eq" | "assert_ne" + ) + { panics.push(macro_call.span); ControlFlow::Continue(Descend::No) } else { diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index 4eefd0065f65c..fa5b02a5a41ba 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -1,8 +1,9 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use rustc_hir::Expr; +use clippy_utils::{is_in_test, match_def_path, paths}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -95,10 +96,49 @@ impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]) impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { - return; - }; - if is_panic(cx, macro_call.def_id) { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) { + if is_panic(cx, macro_call.def_id) { + if cx.tcx.hir().is_inside_const_context(expr.hir_id) + || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) + { + return; + } + + span_lint( + cx, + PANIC, + macro_call.span, + "`panic` should not be present in production code", + ); + return; + } + match cx.tcx.item_name(macro_call.def_id).as_str() { + "todo" => { + span_lint( + cx, + TODO, + macro_call.span, + "`todo` should not be present in production code", + ); + }, + "unimplemented" => { + span_lint( + cx, + UNIMPLEMENTED, + macro_call.span, + "`unimplemented` should not be present in production code", + ); + }, + "unreachable" => { + span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); + }, + _ => {}, + } + } else if let ExprKind::Call(func, [_]) = expr.kind + && let ExprKind::Path(QPath::Resolved(None, expr_path)) = func.kind + && let Res::Def(DefKind::Fn, def_id) = expr_path.res + && match_def_path(cx, def_id, &paths::PANIC_ANY) + { if cx.tcx.hir().is_inside_const_context(expr.hir_id) || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) { @@ -108,32 +148,10 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { span_lint( cx, PANIC, - macro_call.span, - "`panic` should not be present in production code", + expr.span, + "`panic_any` should not be present in production code", ); return; } - match cx.tcx.item_name(macro_call.def_id).as_str() { - "todo" => { - span_lint( - cx, - TODO, - macro_call.span, - "`todo` should not be present in production code", - ); - }, - "unimplemented" => { - span_lint( - cx, - UNIMPLEMENTED, - macro_call.span, - "`unimplemented` should not be present in production code", - ); - }, - "unreachable" => { - span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); - }, - _ => {}, - } } } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 5ca244f0141cb..75d8c09f2b08d 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs index d7fa48c1e38dd..1b9a5a4438297 100644 --- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_to_local_id; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; @@ -9,7 +9,7 @@ use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPa use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index c1296b04387a0..42fbba8ef6dcd 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::{ - intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, + Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, intravisit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs b/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs new file mode 100644 index 0000000000000..385f634a15050 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs @@ -0,0 +1,88 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::InlineAsmOptions; +use rustc_hir::{Expr, ExprKind, InlineAsm, InlineAsmOperand}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks if any pointer is being passed to an asm! block with `nomem` option. + /// + /// ### Why is this bad? + /// `nomem` forbids any reads or writes to memory and passing a pointer suggests + /// that either of those will happen. + /// + /// ### Example + /// ```no_run + /// fn f(p: *mut u32) { + /// unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nomem, nostack)); } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn f(p: *mut u32) { + /// unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nostack)); } + /// } + /// ``` + #[clippy::version = "1.81.0"] + pub POINTERS_IN_NOMEM_ASM_BLOCK, + suspicious, + "pointers in nomem asm block" +} + +declare_lint_pass!(PointersInNomemAsmBlock => [POINTERS_IN_NOMEM_ASM_BLOCK]); + +impl<'tcx> LateLintPass<'tcx> for PointersInNomemAsmBlock { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::InlineAsm(asm) = &expr.kind { + check_asm(cx, asm); + } + } +} + +fn check_asm(cx: &LateContext<'_>, asm: &InlineAsm<'_>) { + if !asm.options.contains(InlineAsmOptions::NOMEM) { + return; + } + + let spans = asm + .operands + .iter() + .filter(|(op, _span)| has_in_operand_pointer(cx, op)) + .map(|(_op, span)| *span) + .collect::>(); + + if spans.is_empty() { + return; + } + + span_lint_and_then( + cx, + POINTERS_IN_NOMEM_ASM_BLOCK, + spans, + "passing pointers to nomem asm block", + additional_notes, + ); +} + +fn has_in_operand_pointer(cx: &LateContext<'_>, asm_op: &InlineAsmOperand<'_>) -> bool { + let asm_in_expr = match asm_op { + InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::Label { .. } => return false, + InlineAsmOperand::SplitInOut { in_expr, .. } => in_expr, + InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => expr, + }; + + // This checks for raw ptrs, refs and function pointers - the last one + // also technically counts as reading memory. + cx.typeck_results().expr_ty(asm_in_expr).is_any_ptr() +} + +fn additional_notes(diag: &mut rustc_errors::Diag<'_, ()>) { + diag.note("`nomem` means that no memory write or read happens inside the asm! block"); + diag.note("if this is intentional and no pointers are read or written to, consider allowing the lint"); +} diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 125f694996c1c..807636bb642b2 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -1,13 +1,11 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; use hir::LifetimeName; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::def_id::DefId; use rustc_hir::hir_id::{HirId, HirIdMap}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{ self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, Safety, TraitFn, TraitItem, TraitItemKind, TyKind, @@ -19,7 +17,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -34,7 +32,7 @@ declare_clippy_lint! { /// with the appropriate `.to_owned()`/`to_string()` calls. /// /// ### Why is this bad? - /// Requiring the argument to be of the specific size + /// Requiring the argument to be of the specific type /// makes the function less useful for no benefit; slices in the form of `&[T]` /// or `&str` usually suffice and can be obtained from other types, too. /// @@ -323,7 +321,6 @@ struct PtrArg<'tcx> { idx: usize, emission_id: HirId, span: Span, - ty_did: DefId, ty_name: Symbol, method_renames: &'static [(&'static str, &'static str)], ref_prefix: RefPrefix, @@ -411,7 +408,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -514,7 +510,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( idx: i, emission_id, span: hir_ty.span, - ty_did: adt.did(), ty_name: name.ident.name, method_renames, ref_prefix: RefPrefix { lt: *lt, mutability }, @@ -610,65 +605,50 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ set_skip_flag(); } }, - Some((Node::Expr(e), child_id)) => match e.kind { - ExprKind::Call(f, expr_args) => { - let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); - if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| { - match *ty.skip_binder().peel_refs().kind() { - ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds), - ty::Param(_) => true, - ty::Adt(def, _) => def.did() == args.ty_did, - _ => false, - } - }) { - // Passed to a function taking the non-dereferenced type. - set_skip_flag(); - } - }, - ExprKind::MethodCall(name, self_arg, expr_args, _) => { - let i = iter::once(self_arg) - .chain(expr_args.iter()) - .position(|arg| arg.hir_id == child_id) - .unwrap_or(0); - if i == 0 { - // Check if the method can be renamed. - let name = name.ident.as_str(); - if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { - result.replacements.push(PtrArgReplacement { - expr_span: e.span, - self_span: self_arg.span, - replacement, - }); - return; - } + Some((Node::Expr(use_expr), child_id)) => { + if let ExprKind::Index(e, ..) = use_expr.kind + && e.hir_id == child_id + { + // Indexing works with both owned and its dereferenced type + return; + } + + if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind + && receiver.hir_id == child_id + { + let name = name.ident.as_str(); + + // Check if the method can be renamed. + if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { + result.replacements.push(PtrArgReplacement { + expr_span: use_expr.span, + self_span: receiver.span, + replacement, + }); + return; } - let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else { - set_skip_flag(); + // Some methods exist on both `[T]` and `Vec`, such as `len`, where the receiver type + // doesn't coerce to a slice and our adjusted type check below isn't enough, + // but it would still be valid to call with a slice + if is_allowed_vec_method(self.cx, use_expr) { return; - }; - - match *self.cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i] - .peel_refs() - .kind() - { - ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => { - set_skip_flag(); - }, - ty::Param(_) => { - set_skip_flag(); - }, - // If the types match check for methods which exist on both types. e.g. `Vec::len` and - // `slice::len` - ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => { - set_skip_flag(); - }, - _ => (), } - }, - // Indexing is fine for currently supported types. - ExprKind::Index(e, _, _) if e.hir_id == child_id => (), - _ => set_skip_flag(), + } + + let deref_ty = args.deref_ty.ty(self.cx); + let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs(); + if adjusted_ty == deref_ty { + return; + } + + if let ty::Dynamic(preds, ..) = adjusted_ty.kind() + && matches_preds(self.cx, deref_ty, preds) + { + return; + } + + set_skip_flag(); }, _ => set_skip_flag(), } diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs index 77b707567e4b4..db03657c9af43 100644 --- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs +++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs @@ -1,5 +1,5 @@ -use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_config::Conf; +use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_path_lang_item; diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index e1e3ded2c795d..aa9a9001afb7b 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -1,8 +1,8 @@ use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; +use clippy_config::Conf; use clippy_config::msrvs::Msrv; use clippy_config::types::MatchLintBehaviour; -use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; @@ -12,8 +12,8 @@ use clippy_utils::{ span_contains_comment, }; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::Res; use rustc_hir::{ BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 81189fe517c00..21cd33672624f 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local}; use rustc_ast::ast::RangeLimits; @@ -11,8 +11,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs index d0b45b59526fc..e877f5d6ed432 100644 --- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 7f4735c6a889b..6bd68dd4109d4 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::get_enclosing_block; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 4e24ddad83a56..b9e0106fc86b3 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; +use clippy_utils::fn_has_unsatisfiable_preds; +use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::fn_has_unsatisfiable_preds; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{def_id, Body, FnDecl, LangItem}; +use rustc_hir::{Body, FnDecl, LangItem, def_id}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; macro_rules! unwrap_or_continue { ($x:expr) => { @@ -349,14 +349,10 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, local_use_locs: _, local_consume_or_mutate_locs: clone_consume_or_mutate_locs, }, - )) = visit_local_usage( - &[cloned, clone], - mir, - mir::Location { - block: bb, - statement_index: mir.basic_blocks[bb].statements.len(), - }, - ) + )) = visit_local_usage(&[cloned, clone], mir, mir::Location { + block: bb, + statement_index: mir.basic_blocks[bb].statements.len(), + }) .map(|mut vec| (vec.remove(0), vec.remove(0))) { CloneUsage { diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index bad9b979203f9..6930a01d48be4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_hir::{ - intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, + ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, intravisit as hir_visit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 3bdf13dbbea65..6a1d40334e755 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 0e637538615e1..d0dbff081f905 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index d94ca5bc7ec2c..4f46ca3c71505 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -9,8 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index d6e741dd974b7..b27bb2e78afed 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 2b4ef21fc48e1..4bff37216eda8 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index f6ef02b7c2330..12cbdb854eff1 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{def_path_def_ids, path_def_id, paths}; +use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; @@ -75,11 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for Regex { // We don't use `match_def_path` here because that relies on matching the exact path, which changed // between regex 1.8 and 1.9 // - // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform - // the operation once and store the results - let mut resolve = |path, kind| { - for id in def_path_def_ids(cx.tcx, path) { - self.definitions.insert(id, kind); + // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only + // perform the operation once and store the results + let regex_crates = find_crates(cx.tcx, sym!(regex)); + let mut resolve = |path: &[&str], kind: RegexKind| { + for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) { + if let Some(id) = res.opt_def_id() { + self.definitions.insert(id, kind); + } } }; diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs index 08de10f69b059..f54cafffb83c9 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index caf3fb8707da3..6157adad059cd 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::{is_from_proc_macro, path_to_local_id}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index 5962e8be9594b..42d9cf2c88c16 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -7,7 +7,7 @@ use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 5ce091b7a7a30..3754fdddedfd1 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr, for_each_unconsumed_temporary}; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -9,8 +9,8 @@ use clippy_utils::{ use core::ops::ControlFlow; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; -use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::ResultErr; +use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, @@ -21,7 +21,7 @@ use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Pos, Span}; +use rustc_span::{BytePos, Pos, Span, sym}; use std::borrow::Cow; use std::fmt::Display; @@ -389,10 +389,24 @@ fn check_final_expr<'tcx>( } }; - let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); - if borrows { - return; + if let Some(inner) = inner { + if for_each_unconsumed_temporary(cx, inner, |temporary_ty| { + if temporary_ty.has_significant_drop(cx.tcx, cx.param_env) + && temporary_ty + .walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_break() + { + return; + } } + if ret_span.from_expansion() { return; } diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 508f3ae6def02..8d31641d4836c 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -5,8 +5,8 @@ use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocKind; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { @@ -62,13 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind { if !map.contains_key(res) { - map.insert( - *res, - ExistingName { - impl_methods: BTreeMap::new(), - trait_methods: BTreeMap::new(), - }, - ); + map.insert(*res, ExistingName { + impl_methods: BTreeMap::new(), + trait_methods: BTreeMap::new(), + }); } let existing_name = map.get_mut(res).unwrap(); diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs index e6fe76493974a..1185d67b1258b 100644 --- a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs +++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while}; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -42,7 +42,7 @@ declare_clippy_lint! { /// println!("inserted {value:?}"); /// } /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub SET_CONTAINS_OR_INSERT, nursery, "call to `::contains` followed by `::insert`" diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index 979d6dc77aede..d1114cb29f7a3 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -4,13 +4,13 @@ use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{self as hir, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use std::borrow::Cow; use std::collections::hash_map::Entry; diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index acf44a9bb5ab4..c986c3e8aa6e8 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 04c16281ec4be..5129bbf26655e 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -2,11 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, - path_to_local_id, SpanlessEq, + SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, }; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 44283a49e84b9..8dd9985879323 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_attr::{StabilityLevel, StableSince}; @@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 7e211d64da141..ba2ddac2ec339 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -1,13 +1,13 @@ use std::ops::ControlFlow; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::path_to_local_id; use clippy_utils::source::{snippet, str_literal_to_char_literal}; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use itertools::Itertools; use rustc_ast::{BinOpKind, LitKind}; use rustc_errors::Applicability; @@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ```no_run /// "Hello World!".trim_end_matches(['.', ',', '!', '?']); /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub MANUAL_PATTERN_CHAR_COMPARISON, style, "manual char comparison in string patterns" diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 6ca4ca000e9b4..1fb82b66ab85f 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{ - get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls, - peel_blocks, SpanlessEq, + SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, + method_calls, peel_blocks, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 1c1de805db0c6..be32dc0aab0b6 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use clippy_utils::ast_utils::{IdentIter, eq_id, is_useless_with_eq_exprs}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; @@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs index 744d6392e065c..e9779d437d432 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; +use clippy_utils::{BINOP_TRAITS, OP_ASSIGN_TRAITS, binop_traits, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 197011cde3a1a..e05fa4095b8e3 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core}; use itertools::Itertools; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use crate::FxHashSet; use rustc_errors::Applicability; @@ -17,7 +17,7 @@ use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs index 20e9608a15dc8..8c5cf93ab6e80 100644 --- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs index 25d0a16e2ab45..3cd4fefffadf3 100644 --- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs @@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index dafe9e38818f5..4f96a566b63c2 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -56,11 +56,13 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { && let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id) && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id() - && match_def_path( - cx, - to_digits_def_id, - &["core", "char", "methods", "", "to_digit"], - ) + && match_def_path(cx, to_digits_def_id, &[ + "core", + "char", + "methods", + "", + "to_digit", + ]) { Some((false, char_arg, radix_arg)) } else { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 2e87d36df3121..00277593622aa 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; -use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index da7906b118353..25fec9f688ca3 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -19,8 +19,8 @@ mod useless_transmute; mod utils; mod wrong_transmute; -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::is_in_const_context; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -527,24 +527,44 @@ declare_clippy_lint! { /// Checks if transmute calls have all generics specified. /// /// ### Why is this bad? - /// If not set, some unexpected output type could be retrieved instead of the expected one, - /// potentially leading to invalid code. + /// If not, one or more unexpected types could be used during `transmute()`, potentially leading + /// to Undefined Behavior or other problems. + /// + /// This is particularly dangerous in case a seemingly innocent/unrelated change causes type + /// inference to result in a different type. For example, if `transmute()` is the tail + /// expression of an `if`-branch, and the `else`-branch type changes, the compiler may silently + /// infer a different type to be returned by `transmute()`. That is because the compiler is + /// free to change the inference of a type as long as that inference is technically correct, + /// regardless of the programmer's unknown expectation. /// - /// This is particularly dangerous in case a seemingly innocent/unrelated change can cause type - /// inference to start inferring a different type. E.g. the transmute is the tail expression of - /// an `if` branch, and a different branches type changes, causing the transmute to silently - /// have a different type, instead of a proper error. + /// Both type-parameters, the input- and the output-type, to any `transmute()` should + /// be given explicitly: Setting the input-type explicitly avoids confusion about what the + /// argument's type actually is. Setting the output-type explicitly avoids type-inference + /// to infer a technically correct yet unexpected type. /// /// ### Example /// ```no_run /// # unsafe { + /// // Avoid "naked" calls to `transmute()`! /// let x: i32 = std::mem::transmute([1u16, 2u16]); + /// + /// // `first_answers` is intended to transmute a slice of bool to a slice of u8. + /// // But the programmer forgot to index the first element of the outer slice, + /// // so we are actually transmuting from "pointers to slices" instead of + /// // transmuting from "a slice of bool", causing a nonsensical result. + /// let the_answers: &[&[bool]] = &[&[true, false, true]]; + /// let first_answers: &[u8] = std::mem::transmute(the_answers); /// # } /// ``` /// Use instead: /// ```no_run /// # unsafe { /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + /// + /// // The explicit type parameters on `transmute()` makes the intention clear, + /// // and cause a type-error if the actual types don't match our expectation. + /// let the_answers: &[&[bool]] = &[&[true, false, true]]; + /// let first_answers: &[u8] = std::mem::transmute::<&[bool], &[u8]>(the_answers[0]); /// # } /// ``` #[clippy::version = "1.79.0"] diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index ba8c7d6bfcb40..fca332dba401a 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; use rustc_hir_typeck::cast::check_cast; use rustc_lint::LateContext; -use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; +use rustc_middle::ty::cast::CastKind; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs index 35e9383076606..f46e95b0b8329 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,5 +1,5 @@ -use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; +use super::utils::is_layout_incompatible; use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index 1d0de9327546f..3da8a449a7c58 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{is_from_proc_macro, path_to_local}; diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs index 9ac73394548c7..24fe4e08a5b44 100644 --- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs +++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs @@ -3,7 +3,7 @@ use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::BOX_COLLECTION; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 3a14927802b48..363aea8be72e9 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -18,8 +18,8 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does @@ -261,8 +261,59 @@ declare_clippy_lint! { /// ### Example /// ```no_run /// # use std::rc::Rc; - /// struct Foo { - /// inner: Rc>>>, + /// struct PointMatrixContainer { + /// matrix: Rc>>>, + /// } + /// + /// fn main() { + /// let point_matrix: Vec>> = vec![ + /// vec![ + /// Box::new((1, 2, 3, 4)), + /// Box::new((5, 6, 7, 8)), + /// ], + /// vec![ + /// Box::new((9, 10, 11, 12)), + /// ], + /// ]; + /// + /// let shared_point_matrix: Rc>>> = Rc::new(point_matrix); + /// + /// let container = PointMatrixContainer { + /// matrix: shared_point_matrix, + /// }; + /// + /// // ... + /// } + /// ``` + /// Use instead: + /// ### Example + /// ```no_run + /// # use std::rc::Rc; + /// type PointMatrix = Vec>>; + /// type SharedPointMatrix = Rc; + /// + /// struct PointMatrixContainer { + /// matrix: SharedPointMatrix, + /// } + /// + /// fn main() { + /// let point_matrix: PointMatrix = vec![ + /// vec![ + /// Box::new((1, 2, 3, 4)), + /// Box::new((5, 6, 7, 8)), + /// ], + /// vec![ + /// Box::new((9, 10, 11, 12)), + /// ], + /// ]; + /// + /// let shared_point_matrix: SharedPointMatrix = Rc::new(point_matrix); + /// + /// let container = PointMatrixContainer { + /// matrix: shared_point_matrix, + /// }; + /// + /// // ... /// } /// ``` #[clippy::version = "pre 1.29.0"] @@ -335,30 +386,22 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(def_id); - self.check_fn_decl( - cx, - decl, - CheckTyContext { - is_in_trait_impl, - is_exported, - in_body: matches!(fn_kind, FnKind::Closure), - ..CheckTyContext::default() - }, - ); + self.check_fn_decl(cx, decl, CheckTyContext { + is_in_trait_impl, + is_exported, + in_body: matches!(fn_kind, FnKind::Closure), + ..CheckTyContext::default() + }); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); match item.kind { - ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty( - cx, - ty, - CheckTyContext { - is_exported, - ..CheckTyContext::default() - }, - ), + ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(cx, ty, CheckTyContext { + is_exported, + ..CheckTyContext::default() + }), // functions, enums, structs, impls and traits are covered _ => (), } @@ -376,14 +419,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { false }; - self.check_ty( - cx, - ty, - CheckTyContext { - is_in_trait_impl, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, ty, CheckTyContext { + is_in_trait_impl, + ..CheckTyContext::default() + }); }, // Methods are covered by check_fn. // Type aliases are ignored because oftentimes it's impossible to @@ -399,14 +438,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(field.def_id); - self.check_ty( - cx, - field.ty, - CheckTyContext { - is_exported, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, field.ty, CheckTyContext { + is_exported, + ..CheckTyContext::default() + }); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) { @@ -434,14 +469,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if let Some(ty) = local.ty { - self.check_ty( - cx, - ty, - CheckTyContext { - in_body: true, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, ty, CheckTyContext { + in_body: true, + ..CheckTyContext::default() + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 0801eace4fcfd..1a656088b1747 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -9,7 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::TypeVisitableExt; use rustc_span::symbol::sym; -use super::{utils, REDUNDANT_ALLOCATION}; +use super::{REDUNDANT_ALLOCATION, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: &QPath<'tcx>, def_id: DefId) -> bool { let mut applicability = Applicability::MaybeIncorrect; diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs index 7fcfd5c8f350d..0b64fddb447b5 100644 --- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty}; use rustc_hir::{GenericParamKind, TyKind}; use rustc_lint::LateContext; use rustc_target::spec::abi::Abi; diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 29996a6f783e1..230239335c65f 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg, LangItem, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::LateContext; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::symbol::sym; use super::VEC_BOX; diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index 42100e1d755c7..3fc08e8192d4c 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_body, walk_expr, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -13,8 +13,8 @@ use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::{sym, Span}; +use rustc_span::symbol::{Ident, kw}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; use std::ops::ControlFlow; @@ -257,13 +257,10 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>, } if matches!( ty.kind, - TyKind::Path(QPath::Resolved( - _, - hir::Path { - res: Res::SelfTyAlias { .. }, - .. - }, - )) + TyKind::Path(QPath::Resolved(_, hir::Path { + res: Res::SelfTyAlias { .. }, + .. + },)) ) { return true; } diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index f51c5f74d9930..44eb0a6c593da 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -4,12 +4,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs index 88039372ebd2c..cfa565cf80379 100644 --- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs +++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs @@ -5,8 +5,8 @@ use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 9ffcfcc0f50cb..93ed15777e015 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index a8cc2f9796339..87478a120dd0b 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index 80b661a757c21..bf2d75ea1a963 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -4,7 +4,7 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, i use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_body, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_body}; use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::{in_external_macro, is_from_async_await}; diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index 978d49f09c3a8..41b2ca5d268c2 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt}; +use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; -use super::{utils, UNIT_ARG}; +use super::{UNIT_ARG, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 080efe983c2a8..937e35dea96d9 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -4,15 +4,15 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty}; use rustc_errors::Applicability; -use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 98f0be3135dba..104be63bb1579 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -1,14 +1,14 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::over; +use rustc_ast::PatKind::*; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::PatKind::*; -use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -16,7 +16,7 @@ use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; use std::cell::Cell; use std::mem; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index 309eaedac8d29..e70d2a2dafeea 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 738fba54fa83f..a1f08cf6623bc 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; use rustc_span::Span; +use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index af7abd009d250..d2a21b11ef47d 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -5,7 +5,7 @@ use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index 86a811e17ca93..71aa57e0a14c2 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs new file mode 100644 index 0000000000000..9fd6ebccd02f4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs @@ -0,0 +1,94 @@ +use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext as _}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Visibility; +use rustc_session::impl_lint_pass; +use rustc_span::symbol::kw; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `use Trait` where the Trait is only used for its methods and not referenced by a path directly. + /// + /// ### Why is this bad? + /// Traits imported that aren't used directly can be imported anonymously with `use Trait as _`. + /// It is more explicit, avoids polluting the current scope with unused names and can be useful to show which imports are required for traits. + /// + /// ### Example + /// ```no_run + /// use std::fmt::Write; + /// + /// fn main() { + /// let mut s = String::new(); + /// let _ = write!(s, "hello, world!"); + /// println!("{s}"); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// use std::fmt::Write as _; + /// + /// fn main() { + /// let mut s = String::new(); + /// let _ = write!(s, "hello, world!"); + /// println!("{s}"); + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub UNUSED_TRAIT_NAMES, + restriction, + "use items that import a trait but only use it anonymously" +} + +pub struct UnusedTraitNames { + msrv: Msrv, +} + +impl UnusedTraitNames { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]); + +impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS) + && !in_external_macro(cx.sess(), item.span) + && let ItemKind::Use(path, UseKind::Single) = item.kind + // Ignore imports that already use Underscore + && item.ident.name != kw::Underscore + // Only check traits + && let Some(Res::Def(DefKind::Trait, _)) = path.res.first() + && cx.tcx.maybe_unused_trait_imports(()).contains(&item.owner_id.def_id) + // Only check this import if it is visible to its module only (no pub, pub(crate), ...) + && let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id) + && cx.tcx.visibility(item.owner_id.def_id) == Visibility::Restricted(module.to_def_id()) + && let Some(last_segment) = path.segments.last() + && let Some(snip) = snippet_opt(cx, last_segment.ident.span) + && !is_from_proc_macro(cx, &last_segment.ident) + { + let complete_span = last_segment.ident.span.to(item.ident.span); + span_lint_and_sugg( + cx, + UNUSED_TRAIT_NAMES, + complete_span, + "importing trait that is only used anonymously", + "use", + format!("{snip} as _"), + Applicability::MachineApplicable, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 65f431d338bdb..d5309aade7aac 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{position_before_rarrow, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; use rustc_ast::visit::FnKind; -use rustc_ast::{ast, ClosureBinder}; +use rustc_ast::{ClosureBinder, ast}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 0b4ea0752b6ba..596f0fd9c8b02 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{higher, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; @@ -13,7 +13,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index f77badd97b7a3..9b9a2ffbbc807 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 5da48f4f7fbd7..e340b419bd07b 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::ty::same_type_and_consts; @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty}; use rustc_hir::{ self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 2f7d54e73ed79..29a7949b34358 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; declare_clippy_lint! { @@ -217,12 +217,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(.., args, _) => { cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| { - return ( + ( did, args, cx.typeck_results().node_args(parent.hir_id), MethodOrFunction::Method, - ); + ) }) }, _ => None, diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 0cce45290cfe7..31f9d84f5e466 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -1,6 +1,6 @@ use clippy_utils::{get_attr, higher}; -use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; +use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index f50ce6c99deac..8f314ce7a60ce 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -3,10 +3,10 @@ use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{hygiene, Span}; +use rustc_span::{Span, hygiene}; use std::iter::once; use std::mem; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index f752968267553..d8f101a8614d8 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 0ffcb433481e4..d444ad45087cf 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -2,11 +2,11 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::def_path_res; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Item; +use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::FloatTy; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 20526113d69e3..7c45a5b2f0971 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -12,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use {rustc_ast as ast, rustc_hir as hir}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 41183700f09e8..76b0a52621be4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -8,12 +8,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use std::str; diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index d3e49bff422ca..ce4f41e854d5e 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; use std::ops::ControlFlow; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanRangeExt; @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; -use rustc_span::{sym, DesugaringKind, Span}; +use rustc_span::{DesugaringKind, Span, sym}; #[expect(clippy::module_name_repetitions)] pub struct UselessVec { diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index a599415a2dd57..91dff5a95236e 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, path_to_local_id}; diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 7a85196cecaaa..2e5fc5834e24f 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -5,8 +5,8 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 7d9e58ad2f8d5..405310512dff3 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, BytePos}; +use rustc_span::{BytePos, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index ec5a5896fb2bf..1dd46ed5a8915 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_test; -use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; -use clippy_utils::source::{expand_past_previous_comma, SpanRangeExt}; +use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; +use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs new file mode 100644 index 0000000000000..ba2a80ee66b05 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs @@ -0,0 +1,334 @@ +use ControlFlow::{Break, Continue}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{fn_def_id, get_enclosing_block, match_any_def_paths, match_def_path, path_to_local_id, paths}; +use rustc_ast::Mutability; +use rustc_errors::Applicability; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; +use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::sym; +use std::ops::ControlFlow; + +declare_clippy_lint! { + /// ### What it does + /// Looks for code that spawns a process but never calls `wait()` on the child. + /// + /// ### Why is this bad? + /// As explained in the [standard library documentation](https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning), + /// calling `wait()` is necessary on Unix platforms to properly release all OS resources associated with the process. + /// Not doing so will effectively leak process IDs and/or other limited global resources, + /// which can eventually lead to resource exhaustion, so it's recommended to call `wait()` in long-running applications. + /// Such processes are called "zombie processes". + /// + /// ### Example + /// ```rust + /// use std::process::Command; + /// + /// let _child = Command::new("ls").spawn().expect("failed to execute child"); + /// ``` + /// Use instead: + /// ```rust + /// use std::process::Command; + /// + /// let mut child = Command::new("ls").spawn().expect("failed to execute child"); + /// child.wait().expect("failed to wait on child"); + /// ``` + #[clippy::version = "1.74.0"] + pub ZOMBIE_PROCESSES, + suspicious, + "not waiting on a spawned child process" +} +declare_lint_pass!(ZombieProcesses => [ZOMBIE_PROCESSES]); + +impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind + && let Some(child_adt) = cx.typeck_results().expr_ty(expr).ty_adt_def() + && match_def_path(cx, child_adt.did(), &paths::CHILD) + { + match cx.tcx.parent_hir_node(expr.hir_id) { + Node::LetStmt(local) + if let PatKind::Binding(_, local_id, ..) = local.pat.kind + && let Some(enclosing_block) = get_enclosing_block(cx, expr.hir_id) => + { + let mut vis = WaitFinder::WalkUpTo(cx, local_id); + + // If it does have a `wait()` call, we're done. Don't lint. + if let Break(BreakReason::WaitFound) = walk_block(&mut vis, enclosing_block) { + return; + } + + // Don't emit a suggestion since the binding is used later + check(cx, expr, false); + }, + Node::LetStmt(&LetStmt { pat, .. }) if let PatKind::Wild = pat.kind => { + // `let _ = child;`, also dropped immediately without `wait()`ing + check(cx, expr, true); + }, + Node::Stmt(&Stmt { + kind: StmtKind::Semi(_), + .. + }) => { + // Immediately dropped. E.g. `std::process::Command::new("echo").spawn().unwrap();` + check(cx, expr, true); + }, + _ => {}, + } + } + } +} + +enum BreakReason { + WaitFound, + EarlyReturn, +} + +/// A visitor responsible for finding a `wait()` call on a local variable. +/// +/// Conditional `wait()` calls are assumed to not call wait: +/// ```ignore +/// let mut c = Command::new("").spawn().unwrap(); +/// if true { +/// c.wait(); +/// } +/// ``` +/// +/// Note that this visitor does NOT explicitly look for `wait()` calls directly, but rather does the +/// inverse -- checking if all uses of the local are either: +/// - a field access (`child.{stderr,stdin,stdout}`) +/// - calling `id` or `kill` +/// - no use at all (e.g. `let _x = child;`) +/// - taking a shared reference (`&`), `wait()` can't go through that +/// +/// None of these are sufficient to prevent zombie processes. +/// Doing it like this means more FNs, but FNs are better than FPs. +/// +/// `return` expressions, conditional or not, short-circuit the visitor because +/// if a `wait()` call hadn't been found at that point, it might never reach one at a later point: +/// ```ignore +/// let mut c = Command::new("").spawn().unwrap(); +/// if true { +/// return; // Break(BreakReason::EarlyReturn) +/// } +/// c.wait(); // this might not be reachable +/// ``` +enum WaitFinder<'a, 'tcx> { + WalkUpTo(&'a LateContext<'tcx>, HirId), + Found(&'a LateContext<'tcx>, HirId), +} + +impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { + type Result = ControlFlow; + + fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { + if let Self::WalkUpTo(cx, local_id) = *self + && let PatKind::Binding(_, pat_id, ..) = l.pat.kind + && local_id == pat_id + { + *self = Self::Found(cx, local_id); + } + + walk_local(self, l) + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + let Self::Found(cx, local_id) = *self else { + return walk_expr(self, ex); + }; + + if path_to_local_id(ex, local_id) { + match cx.tcx.parent_hir_node(ex.hir_id) { + Node::Stmt(Stmt { + kind: StmtKind::Semi(_), + .. + }) => {}, + Node::Expr(expr) if let ExprKind::Field(..) = expr.kind => {}, + Node::Expr(expr) if let ExprKind::AddrOf(_, Mutability::Not, _) = expr.kind => {}, + Node::Expr(expr) + if let Some(fn_did) = fn_def_id(cx, expr) + && match_any_def_paths(cx, fn_did, &[&paths::CHILD_ID, &paths::CHILD_KILL]).is_some() => {}, + + // Conservatively assume that all other kinds of nodes call `.wait()` somehow. + _ => return Break(BreakReason::WaitFound), + } + } else { + match ex.kind { + ExprKind::Ret(..) => return Break(BreakReason::EarlyReturn), + ExprKind::If(cond, then, None) => { + walk_expr(self, cond)?; + + // A `wait()` call in an if expression with no else is not enough: + // + // let c = spawn(); + // if true { + // c.wait(); + // } + // + // This might not call wait(). However, early returns are propagated, + // because they might lead to a later wait() not being called. + if let Break(BreakReason::EarlyReturn) = walk_expr(self, then) { + return Break(BreakReason::EarlyReturn); + } + + return Continue(()); + }, + + ExprKind::If(cond, then, Some(else_)) => { + walk_expr(self, cond)?; + + #[expect(clippy::unnested_or_patterns)] + match (walk_expr(self, then), walk_expr(self, else_)) { + (Continue(()), Continue(())) + + // `wait()` in one branch but nothing in the other does not count + | (Continue(()), Break(BreakReason::WaitFound)) + | (Break(BreakReason::WaitFound), Continue(())) => {}, + + // `wait()` in both branches is ok + (Break(BreakReason::WaitFound), Break(BreakReason::WaitFound)) => { + return Break(BreakReason::WaitFound); + }, + + // Propagate early returns in either branch + (Break(BreakReason::EarlyReturn), _) | (_, Break(BreakReason::EarlyReturn)) => { + return Break(BreakReason::EarlyReturn); + }, + } + + return Continue(()); + }, + _ => {}, + } + } + + walk_expr(self, ex) + } +} + +/// This function has shared logic between the different kinds of nodes that can trigger the lint. +/// +/// In particular, `let = ;` requires some custom additional logic +/// such as checking that the binding is not used in certain ways, which isn't necessary for +/// `let _ = ;`. +/// +/// This checks if the program doesn't unconditionally exit after the spawn expression. +fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, emit_suggestion: bool) { + let Some(block) = get_enclosing_block(cx, spawn_expr.hir_id) else { + return; + }; + + let mut vis = ExitPointFinder { + cx, + state: ExitPointState::WalkUpTo(spawn_expr.hir_id), + }; + if let Break(ExitCallFound) = vis.visit_block(block) { + // Visitor found an unconditional `exit()` call, so don't lint. + return; + } + + span_lint_and_then( + cx, + ZOMBIE_PROCESSES, + spawn_expr.span, + "spawned process is never `wait()`ed on", + |diag| { + if emit_suggestion { + diag.span_suggestion( + spawn_expr.span.shrink_to_hi(), + "try", + ".wait()", + Applicability::MaybeIncorrect, + ); + } else { + diag.note("consider calling `.wait()`"); + } + + diag.note("not doing so might leave behind zombie processes") + .note("see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning"); + }, + ); +} + +/// Checks if the given expression exits the process. +fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + fn_def_id(cx, expr).is_some_and(|fn_did| { + cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || match_def_path(cx, fn_did, &paths::ABORT) + }) +} + +#[derive(Debug)] +enum ExitPointState { + /// Still walking up to the expression that initiated the visitor. + WalkUpTo(HirId), + /// We're inside of a control flow construct (e.g. `if`, `match`, `loop`) + /// Within this, we shouldn't accept any `exit()` calls in here, but we can leave all of these + /// constructs later and still continue looking for an `exit()` call afterwards. Example: + /// ```ignore + /// Command::new("").spawn().unwrap(); + /// + /// if true { // depth=1 + /// if true { // depth=2 + /// match () { // depth=3 + /// () => loop { // depth=4 + /// + /// std::process::exit(); + /// ^^^^^^^^^^^^^^^^^^^^^ conditional exit call, ignored + /// + /// } // depth=3 + /// } // depth=2 + /// } // depth=1 + /// } // depth=0 + /// + /// std::process::exit(); + /// ^^^^^^^^^^^^^^^^^^^^^ this exit call is accepted because we're now unconditionally calling it + /// ``` + /// We can only get into this state from `NoExit`. + InControlFlow { depth: u32 }, + /// No exit call found yet, but looking for one. + NoExit, +} + +fn expr_enters_control_flow(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Loop(..)) +} + +struct ExitPointFinder<'a, 'tcx> { + state: ExitPointState, + cx: &'a LateContext<'tcx>, +} + +struct ExitCallFound; + +impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> { + type Result = ControlFlow; + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + match self.state { + ExitPointState::WalkUpTo(id) if expr.hir_id == id => { + self.state = ExitPointState::NoExit; + walk_expr(self, expr) + }, + ExitPointState::NoExit if expr_enters_control_flow(expr) => { + self.state = ExitPointState::InControlFlow { depth: 1 }; + walk_expr(self, expr)?; + if let ExitPointState::InControlFlow { .. } = self.state { + self.state = ExitPointState::NoExit; + } + Continue(()) + }, + ExitPointState::NoExit if is_exit_expression(self.cx, expr) => Break(ExitCallFound), + ExitPointState::InControlFlow { ref mut depth } if expr_enters_control_flow(expr) => { + *depth += 1; + walk_expr(self, expr)?; + match self.state { + ExitPointState::InControlFlow { depth: 1 } => self.state = ExitPointState::NoExit, + ExitPointState::InControlFlow { ref mut depth } => *depth -= 1, + _ => {}, + } + Continue(()) + }, + _ => Continue(()), + } + } +} diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 629ce9d04d432..fe30b10c435ed 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.82" +version = "0.1.83" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index de8bbb619f8e4..49323492e124d 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -242,13 +242,16 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { } fn eq_coroutine_kind(a: Option, b: Option) -> bool { - match (a, b) { + matches!( + (a, b), (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. })) - | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) - | (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) - | (None, None) => true, - _ => false, - } + | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) + | ( + Some(CoroutineKind::AsyncGen { .. }), + Some(CoroutineKind::AsyncGen { .. }) + ) + | (None, None) + ) } pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs index eefcbabd835d2..032cd3ed7399f 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs @@ -1,5 +1,5 @@ use core::iter::FusedIterator; -use rustc_ast::visit::{walk_attribute, walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_attribute, walk_expr}; use rustc_ast::{Attribute, Expr}; use rustc_span::symbol::Ident; diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 42c8b218d14e8..edc9c6ccdff84 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -4,7 +4,7 @@ use rustc_lexer::TokenKind; use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::str::FromStr; use crate::source::SpanRangeExt; @@ -183,15 +183,15 @@ pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { let mut iter = tokenize_with_text(src); // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { + while iter.any(|(t, ..)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, ..)| { matches!( t, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } ) }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + if matches!(iter.next(), Some((TokenKind::OpenBracket, ..))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg", _))) { return true; } diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 2bd6837d973bb..9143d292f670f 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -12,9 +12,9 @@ //! code was written, and check if the span contains that text. Note this will only work correctly //! if the span is not from a `macro_rules` based macro. +use rustc_ast::AttrStyle; use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy}; use rustc_ast::token::CommentKind; -use rustc_ast::AttrStyle; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, @@ -24,7 +24,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 760d5bc95f7fb..bf47cf6d372d2 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1,24 +1,24 @@ #![allow(clippy::float_cmp)] use crate::macros::HirNode; -use crate::source::{walk_span_to_context, SpanRangeExt}; +use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; -use rustc_apfloat::ieee::{Half, Quad}; use rustc_apfloat::Float; +use rustc_apfloat::ieee::{Half, Quad}; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::{alloc_range, Scalar}; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Scalar, alloc_range}; use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; use rustc_target::abi::Size; use std::cell::Cell; use std::cmp::Ordering; @@ -581,7 +581,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { - use self::Constant::{Int, F32, F64}; + use self::Constant::{F32, F64, Int}; match *o { Int(value) => { let ty::Int(ity) = *ty.kind() else { return None }; diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index a6dd12a28c5bc..9420d84b9591d 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -14,12 +14,12 @@ use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use std::{cmp, ops}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index e09cc9edf3ac3..3175a9a1dd31f 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -3,14 +3,14 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::consts::{ConstEvalCtxt, Constant}; -use crate::ty::is_type_diagnostic_item; use crate::is_expn_of; +use crate::ty::is_type_diagnostic_item; use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, symbol, Span}; +use rustc_span::{Span, sym, symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f61ef9ac1b05e..76900379ac787 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,20 +1,20 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt}; +use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; -use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; +use rustc_hir::def::Res; use rustc_hir::{ ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, }; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext, sym}; use std::hash::{Hash, Hasher}; use std::ops::Range; @@ -1194,8 +1194,8 @@ fn eq_span_tokens( && let Some(rsrc) = right.get_source_range(cx) && let Some(rsrc) = rsrc.as_str() { - let pred = |t: &(_, _)| pred(t.0); - let map = |(_, x)| x; + let pred = |&(token, ..): &(TokenKind, _, _)| pred(token); + let map = |(_, source, _)| source; let ltok = tokenize_with_text(lsrc).filter(pred).map(map); let rtok = tokenize_with_text(rsrc).filter(pred).map(map); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index aed0bc565d8e9..6dbc3334157e3 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ pub mod visitors; pub use self::attrs::*; pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ - both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash, + HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, }; use core::mem; @@ -94,20 +94,20 @@ use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalModDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, - ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, - ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, - Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, - TraitRef, TyKind, UnOp, + self as hir, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, + TyKind, UnOp, def, }; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::Const; @@ -120,12 +120,12 @@ use rustc_middle::ty::{ }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{InnerSpan, Span, sym}; use rustc_target::abi::Integer; use visitors::Visitable; -use crate::consts::{mir_to_const, ConstEvalCtxt, Constant}; +use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; @@ -263,9 +263,13 @@ pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> } } - /// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`. -pub fn is_enum_variant_ctor(cx: &LateContext<'_>, enum_item: Symbol, variant_name: Symbol, ctor_call_id: DefId) -> bool { +pub fn is_enum_variant_ctor( + cx: &LateContext<'_>, + enum_item: Symbol, + variant_name: Symbol, + ctor_call_id: DefId, +) -> bool { let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else { return false; }; @@ -664,6 +668,17 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, name: Symbol) -> Vec { + tcx.crates(()) + .iter() + .copied() + .filter(move |&num| tcx.crate_name(num) == name) + .map(CrateNum::as_def_id) + .map(|id| Res::Def(tcx.def_kind(id), id)) + .collect() +} + /// Resolves a def path like `std::vec::Vec`. /// /// Can return multiple resolutions when there are multiple versions of the same crate, e.g. @@ -674,15 +689,7 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, path: &[&str]) -> Vec { - fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator + '_ { - tcx.crates(()) - .iter() - .copied() - .filter(move |&num| tcx.crate_name(num) == name) - .map(CrateNum::as_def_id) - } - - let (base, mut path) = match *path { + let (base, path) = match *path { [primitive] => { return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)]; }, @@ -698,18 +705,25 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { None }; - let starts = find_primitive_impls(tcx, base) - .chain(find_crates(tcx, base_sym)) + let crates = find_primitive_impls(tcx, base) .chain(local_crate) - .map(|id| Res::Def(tcx.def_kind(id), id)); + .map(|id| Res::Def(tcx.def_kind(id), id)) + .chain(find_crates(tcx, base_sym)) + .collect(); - let mut resolutions: Vec = starts.collect(); + def_path_res_with_base(tcx, crates, path) +} +/// Resolves a def path like `vec::Vec` with the base `std`. +/// +/// This is lighter than [`def_path_res`], and should be called with [`find_crates`] looking up +/// items from the same crate repeatedly, although should still be used sparingly. +pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec, mut path: &[&str]) -> Vec { while let [segment, rest @ ..] = path { path = rest; let segment = Symbol::intern(segment); - resolutions = resolutions + base = base .into_iter() .filter_map(|res| res.opt_def_id()) .flat_map(|def_id| { @@ -727,7 +741,7 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { .collect(); } - resolutions + base } /// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`]. @@ -2940,13 +2954,14 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU } /// Tokenizes the input while keeping the text associated with each token. -pub fn tokenize_with_text(s: &str) -> impl Iterator { +pub fn tokenize_with_text(s: &str) -> impl Iterator { let mut pos = 0; tokenize(s).map(move |t| { let end = pos + t.len; let range = pos as usize..end as usize; + let inner = InnerSpan::new(range.start, range.end); pos = end; - (t.kind, s.get(range).unwrap_or_default()) + (t.kind, s.get(range).unwrap_or_default(), inner) }) } @@ -2970,8 +2985,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); let res = tokenize_with_text(&snippet) - .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) - .map(|(_, s)| s) + .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s, _)| s) .join("\n"); res } @@ -2991,7 +3006,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// pat: Some(a) /// else_body: return None /// ``` - +/// /// And for this example: /// ```ignore /// let Some(FooBar { a, b }) = ex else { return None }; @@ -3001,7 +3016,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// pat: Some(FooBar { a, b }) /// else_body: return None /// ``` - +/// /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because /// the question mark operator is applicable here. Callers have to check whether we are in a /// constant or not. diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 1d7479bff82d9..9c4d19ac1f1dd 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::visitors::{for_each_expr_without_closures, Descend}; +use crate::visitors::{Descend, for_each_expr_without_closures}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -10,7 +10,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; +use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs index 654fb564848e2..59bb5e35cda66 100644 --- a/src/tools/clippy/clippy_utils/src/mir/mod.rs +++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs @@ -2,7 +2,7 @@ use rustc_hir::{Expr, HirId}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, BasicBlock, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK, + BasicBlock, Body, InlineAsmOperand, Local, Location, Place, START_BLOCK, StatementKind, TerminatorKind, traversal, }; use rustc_middle::ty::TyCtxt; @@ -112,14 +112,10 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool { /// Convenience wrapper around `visit_local_usage`. pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option { - visit_local_usage( - &[local], - mir, - Location { - block: START_BLOCK, - statement_index: 0, - }, - ) + visit_local_usage(&[local], mir, Location { + block: START_BLOCK, + statement_index: 0, + }) .map(|mut vec| { let LocalUsage { local_use_locs, .. } = vec.remove(0); let mut locations = local_use_locs diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index a30edc48fff26..11a98b02f337a 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -29,7 +29,11 @@ pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. -// ... none currently! +pub const ABORT: [&str; 3] = ["std", "process", "abort"]; +pub const CHILD: [&str; 3] = ["std", "process", "Child"]; +pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"]; +pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"]; +pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; // Paths in clippy itself pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index 991ea428dc33b..273c1b0defab0 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -1,5 +1,5 @@ use crate::source::snippet; -use crate::visitors::{for_each_expr_without_closures, Descend}; +use crate::visitors::{Descend, for_each_expr_without_closures}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index ce1895b7fb19b..7a6107cfe539e 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -18,8 +18,8 @@ use rustc_middle::mir::{ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 482e1e0147b18..4ad7575e7201f 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -9,10 +9,10 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{EarlyContext, LateContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::source_map::{original_sp, SourceMap}; +use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, - DUMMY_SP, + BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, + hygiene, }; use std::borrow::Cow; use std::fmt; @@ -666,39 +666,6 @@ pub fn walk_span_to_context(span: Span, outer: SyntaxContext) -> Option { (outer_span.ctxt() == outer).then_some(outer_span) } -/// Removes block comments from the given `Vec` of lines. -/// -/// # Examples -/// -/// ```rust,ignore -/// without_block_comments(vec!["/*", "foo", "*/"]); -/// // => vec![] -/// -/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); -/// // => vec!["bar"] -/// ``` -pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { - let mut without = vec![]; - - let mut nest_level = 0; - - for line in lines { - if line.contains("/*") { - nest_level += 1; - continue; - } else if line.contains("*/") { - nest_level -= 1; - continue; - } - - if nest_level == 0 { - without.push(line); - } - } - - without -} - /// Trims the whitespace from the start and the end of the span. pub fn trim_span(sm: &SourceMap, span: Span) -> Span { let data = span.data(); @@ -758,15 +725,12 @@ pub fn str_literal_to_char_literal( &snip[1..(snip.len() - 1)] }; - let hint = format!( - "'{}'", - match ch { - "'" => "\\'", - r"\" => "\\\\", - "\\\"" => "\"", // no need to escape `"` in `'"'` - _ => ch, - } - ); + let hint = format!("'{}'", match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + }); Some(hint) } else { @@ -776,7 +740,7 @@ pub fn str_literal_to_char_literal( #[cfg(test)] mod test { - use super::{reindent_multiline, without_block_comments}; + use super::reindent_multiline; #[test] fn test_reindent_multiline_single_line() { @@ -844,29 +808,4 @@ mod test { z }".into(), true, Some(8))); } - - #[test] - fn test_without_block_comments_lines_without_block_comments() { - let result = without_block_comments(vec!["/*", "", "*/"]); - println!("result: {result:?}"); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); - assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); - - let result = without_block_comments(vec!["/* rust", "", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* one-line comment */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["foo", "bar", "baz"]); - assert_eq!(result, vec!["foo", "bar", "baz"]); - } } diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs index 421b25a77fe8b..1588ee452daea 100644 --- a/src/tools/clippy/clippy_utils/src/str_utils.rs +++ b/src/tools/clippy/clippy_utils/src/str_utils.rs @@ -370,9 +370,11 @@ mod test { assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); assert_eq!(camel_case_split("Abc"), vec!["Abc"]); assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]); - assert_eq!( - camel_case_split("\u{f6}\u{f6}AabABcd"), - vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"] - ); + assert_eq!(camel_case_split("\u{f6}\u{f6}AabABcd"), vec![ + "\u{f6}\u{f6}", + "Aab", + "A", + "Bcd" + ]); } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 0f86d89c980d7..3255c51d009ca 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -180,8 +180,10 @@ impl<'a> Sugg<'a> { ) -> Self { use rustc_ast::ast::RangeLimits; + let mut snippet = |span: Span| snippet_with_context(cx, span, ctxt, default, app).0; + match expr.kind { - _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::AddrOf(..) | ast::ExprKind::Closure { .. } | ast::ExprKind::If(..) @@ -224,46 +226,38 @@ impl<'a> Sugg<'a> { | ast::ExprKind::While(..) | ast::ExprKind::Await(..) | ast::ExprKind::Err(_) - | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + | ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, - lhs.as_ref().map_or("".into(), |lhs| { - snippet_with_context(cx, lhs.span, ctxt, default, app).0 - }), - rhs.as_ref().map_or("".into(), |rhs| { - snippet_with_context(cx, rhs.span, ctxt, default, app).0 - }), + lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), + rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( AssocOp::DotDotEq, - lhs.as_ref().map_or("".into(), |lhs| { - snippet_with_context(cx, lhs.span, ctxt, default, app).0 - }), - rhs.as_ref().map_or("".into(), |rhs| { - snippet_with_context(cx, rhs.span, ctxt, default, app).0 - }), + lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), + rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp( AssocOp::Assign, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( astbinop2assignop(op), - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( AssocOp::from_ast_binop(op.node), - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::Cast(ref lhs, ref ty) | //FIXME(chenyukang), remove this after type ascription is removed from AST ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( AssocOp::As, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, ty.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(ty.span), ), } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 22aaaa1b73419..4e3a61a1aa5f5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -12,8 +12,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ @@ -22,7 +22,7 @@ use rustc_middle::ty::{ TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; @@ -606,10 +606,13 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), // Unions are always fine right now. // This includes MaybeUninit, the main way people use uninitialized memory. - // For ADTs, we could look at all fields just like for tuples, but that's potentially - // exponential, so let's avoid doing that for now. Code doing that is sketchy enough to - // just use an `#[allow()]`. - ty::Adt(adt, _) => adt.is_union(), + ty::Adt(adt, _) if adt.is_union() => true, + // Types (e.g. `UnsafeCell>`) that recursively contain only types that can be uninit + // can themselves be uninit too. + // This purposefully ignores enums as they may have a discriminant that can't be uninit. + ty::Adt(adt, args) if adt.is_struct() => adt + .all_fields() + .all(|field| is_uninit_value_valid_for_ty(cx, field.ty(cx.tcx, args))), // For the rest, conservatively assume that they cannot be uninit. _ => false, } diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 875ddec259ee8..e612e9c6cb606 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -14,14 +14,14 @@ use crate::def_path_res; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_qpath, walk_ty}; use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; use rustc_span::{Span, Symbol}; mod certainty; -use certainty::{join, meet, Certainty, Meet}; +use certainty::{Certainty, Meet, join, meet}; pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { expr_type_certainty(cx, expr).is_certain() diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index fbf3d95365acb..1230b60c3a6b7 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -1,4 +1,4 @@ -use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable}; +use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; use hir::def::Res; diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index e5b6d3965e930..6d9a85a1181c4 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -1,10 +1,10 @@ use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; -use rustc_ast::visit::{try_visit, VisitorResult}; +use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; +use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr}; use rustc_hir::{ AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath, Safety, Stmt, UnOp, UnsafeSource, diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index 31270241b0b2e..67a1f7cc72c54 100644 --- a/src/tools/clippy/declare_clippy_lint/Cargo.toml +++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.82" +version = "0.1.83" edition = "2021" publish = false diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs index 6aa24329b0659..fefc1a0a6c402 100644 --- a/src/tools/clippy/declare_clippy_lint/src/lib.rs +++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs @@ -5,7 +5,7 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token}; +use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token, parse_macro_input}; fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> Option { if let Meta::NameValue(name_value) = &attr.meta { @@ -140,15 +140,12 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let mut category = category.to_string(); - let level = format_ident!( - "{}", - match category.as_str() { - "correctness" => "Deny", - "style" | "suspicious" | "complexity" | "perf" => "Warn", - "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", - _ => panic!("unknown category {category}"), - }, - ); + let level = format_ident!("{}", match category.as_str() { + "correctness" => "Deny", + "style" | "suspicious" | "complexity" | "perf" => "Warn", + "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", + _ => panic!("unknown category {category}"), + },); let info_name = format_ident!("{name}_INFO"); diff --git a/src/tools/clippy/lintcheck/src/driver.rs b/src/tools/clippy/lintcheck/src/driver.rs index 2fda2b00f873b..87ab14ba0cf83 100644 --- a/src/tools/clippy/lintcheck/src/driver.rs +++ b/src/tools/clippy/lintcheck/src/driver.rs @@ -1,4 +1,4 @@ -use crate::recursive::{deserialize_line, serialize_line, DriverInfo}; +use crate::recursive::{DriverInfo, deserialize_line, serialize_line}; use std::io::{self, BufReader, Write}; use std::net::TcpStream; diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs index 6a662970ae84d..57073f523648e 100644 --- a/src/tools/clippy/lintcheck/src/recursive.rs +++ b/src/tools/clippy/lintcheck/src/recursive.rs @@ -3,8 +3,8 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::input::RecursiveOptions; use crate::ClippyWarning; +use crate::input::RecursiveOptions; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 0be2e81810ebe..b431599c224ef 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-23" +channel = "nightly-2024-09-22" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 0ac3f35b4465a..324f754e61556 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -15,9 +15,9 @@ extern crate rustc_session; extern crate rustc_span; use rustc_interface::interface; +use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; use rustc_session::parse::ParseSess; -use rustc_session::EarlyDiagCtxt; use rustc_span::symbol::Symbol; use std::env; @@ -268,8 +268,6 @@ pub fn main() { }, _ => Some(s.to_string()), }) - // FIXME: remove this line in 1.79 to only keep `--cfg clippy`. - .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) .chain(vec!["--cfg".into(), "clippy".into()]) .collect::>(); diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 9754254cdd0df..af2aa51925777 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -2,26 +2,25 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] -use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use cargo_metadata::Message; +use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; +use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; -use clippy_lints::LintInfo; use serde::{Deserialize, Serialize}; use test_utils::IS_RUSTC_TEST_SUITE; -use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::custom_flags::Flag; +use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; -use ui_test::test_result::TestRun; -use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; +use ui_test::{Args, CommandBuilder, Config, Match, OutputConflictHandling, status_emitter}; use std::collections::{BTreeMap, HashMap}; use std::env::{self, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fmt::Write; use std::path::{Path, PathBuf}; -use std::sync::mpsc::{channel, Sender}; +use std::sync::mpsc::{Sender, channel}; use std::{fs, iter, thread}; // Test dependencies may need an `extern crate` here to ensure that they show up @@ -469,15 +468,14 @@ fn applicability_ord(applicability: &Applicability) -> u8 { impl Flag for DiagnosticCollector { fn post_test_action( &self, - _config: &ui_test::per_test_config::TestConfig<'_>, - _cmd: &mut std::process::Command, + _config: &ui_test::per_test_config::TestConfig, output: &std::process::Output, - _build_manager: &ui_test::build_manager::BuildManager<'_>, - ) -> Result, ui_test::Errored> { + _build_manager: &ui_test::build_manager::BuildManager, + ) -> Result<(), ui_test::Errored> { if !output.stderr.is_empty() { self.sender.send(output.stderr.clone()).unwrap(); } - Ok(Vec::new()) + Ok(()) } fn clone_inner(&self) -> Box { diff --git a/src/tools/clippy/tests/config-metadata.rs b/src/tools/clippy/tests/config-metadata.rs index 3e3711873baa5..628dfc8f758ac 100644 --- a/src/tools/clippy/tests/config-metadata.rs +++ b/src/tools/clippy/tests/config-metadata.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -use clippy_config::{get_configuration_metadata, ClippyConfiguration}; +use clippy_config::{ClippyConfiguration, get_configuration_metadata}; use itertools::Itertools; use regex::Regex; use std::borrow::Cow; diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs index 8d10d5e7161a6..858be389a9e6e 100644 --- a/src/tools/clippy/tests/dogfood.rs +++ b/src/tools/clippy/tests/dogfood.rs @@ -6,11 +6,9 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use itertools::Itertools; -use std::fs::File; use std::io::{self, IsTerminal}; use std::path::PathBuf; use std::process::Command; -use std::time::SystemTime; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::Args; @@ -28,11 +26,7 @@ fn main() { println!("dogfood: test"); } } else if !args.skip.iter().any(|arg| arg == "dogfood") { - if args.filters.iter().any(|arg| arg == "collect_metadata") { - collect_metadata(); - } else { - dogfood(); - } + dogfood(); } } @@ -61,47 +55,6 @@ fn dogfood() { ); } -fn collect_metadata() { - assert!(cfg!(feature = "internal")); - - // Setup for validation - let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json"); - let start_time = SystemTime::now(); - - // Run collection as is - std::env::set_var("ENABLE_METADATA_COLLECTION", "1"); - assert!(run_clippy_for_package( - "clippy_lints", - &["-A", "unfulfilled_lint_expectations"] - )); - - // Check if cargo caching got in the way - if let Ok(file) = File::open(metadata_output_path) { - if let Ok(metadata) = file.metadata() { - if let Ok(last_modification) = metadata.modified() { - if last_modification > start_time { - // The output file has been modified. Most likely by a hungry - // metadata collection monster. So We'll return. - return; - } - } - } - } - - // Force cargo to invalidate the caches - filetime::set_file_mtime( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"), - filetime::FileTime::now(), - ) - .unwrap(); - - // Running the collection again - assert!(run_clippy_for_package( - "clippy_lints", - &["-A", "unfulfilled_lint_expectations"] - )); -} - #[must_use] fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed index 3908411da827a..0a9948428341d 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed @@ -13,7 +13,7 @@ extern crate rustc_span; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; #[allow(unused)] use clippy_utils::{ - is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, path_res, }; @@ -22,8 +22,8 @@ use rustc_hir::LangItem; #[allow(unused)] use rustc_span::sym; -use rustc_hir::def_id::DefId; use rustc_hir::Expr; +use rustc_hir::def_id::DefId; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs index 632e26215a4db..ba68de6c6d016 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs @@ -13,7 +13,7 @@ extern crate rustc_span; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; #[allow(unused)] use clippy_utils::{ - is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, path_res, }; @@ -22,8 +22,8 @@ use rustc_hir::LangItem; #[allow(unused)] use rustc_span::sym; -use rustc_hir::def_id::DefId; use rustc_hir::Expr; +use rustc_hir::def_id::DefId; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs index a2e2b46c42693..61ae8de8e3357 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_names)] +#![warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs index a2e2b46c42693..61ae8de8e3357 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_names)] +#![warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index 5f4f007cf5c7f..a6072111dc061 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -2,7 +2,7 @@ use std::alloc as colla; use std::option::Option as Maybe; -use std::process::{exit as goodbye, Child as Kid}; +use std::process::{Child as Kid, exit as goodbye}; use std::thread::sleep as thread_sleep; #[rustfmt::skip] use std::{ diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index f60058c862888..c2b61aab5b3c4 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -2,7 +2,7 @@ use std::alloc as colla; use std::option::Option as Maybe; -use std::process::{exit as wrong_exit, Child as Kid}; +use std::process::{Child as Kid, exit as wrong_exit}; use std::thread::sleep; #[rustfmt::skip] use std::{ diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index f66938c83fbf8..d3bb07ec47fd3 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -1,8 +1,8 @@ error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:5:20 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:5:34 | -LL | use std::process::{exit as wrong_exit, Child as Kid}; - | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` +LL | use std::process::{Child as Kid, exit as wrong_exit}; + | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` | = note: `-D clippy::missing-enforced-import-renames` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_enforced_import_renames)]` diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.rs b/src/tools/clippy/tests/ui-toml/panic/panic.rs index 618a37ddfc555..b6264c950e450 100644 --- a/src/tools/clippy/tests/ui-toml/panic/panic.rs +++ b/src/tools/clippy/tests/ui-toml/panic/panic.rs @@ -1,5 +1,6 @@ //@compile-flags: --test #![warn(clippy::panic)] +use std::panic::panic_any; fn main() { enum Enam { @@ -12,6 +13,10 @@ fn main() { } } +fn issue_13292() { + panic_any("should lint") +} + #[test] fn lonely_test() { enum Enam { diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.stderr b/src/tools/clippy/tests/ui-toml/panic/panic.stderr index bf7503e086c9d..a034207d919fe 100644 --- a/src/tools/clippy/tests/ui-toml/panic/panic.stderr +++ b/src/tools/clippy/tests/ui-toml/panic/panic.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> tests/ui-toml/panic/panic.rs:11:14 + --> tests/ui-toml/panic/panic.rs:12:14 | LL | _ => panic!(""), | ^^^^^^^^^^ @@ -7,5 +7,11 @@ LL | _ => panic!(""), = note: `-D clippy::panic` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::panic)]` -error: aborting due to 1 previous error +error: `panic_any` should not be present in production code + --> tests/ui-toml/panic/panic.rs:17:5 + | +LL | panic_any("should lint") + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed index 49ee3ee17c70f..058dbb77a3205 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.fixed +++ b/src/tools/clippy/tests/ui/allow_attributes.fixed @@ -58,3 +58,10 @@ fn msrv_1_80() { #[allow(unused)] let x = 1; } + +#[deny(clippy::allow_attributes)] +fn deny_allow_attributes() -> Option { + let allow = None; + allow?; + Some(42) +} diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs index 854acf8348dcb..6d94ce50e4c37 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.rs +++ b/src/tools/clippy/tests/ui/allow_attributes.rs @@ -58,3 +58,10 @@ fn msrv_1_80() { #[allow(unused)] let x = 1; } + +#[deny(clippy::allow_attributes)] +fn deny_allow_attributes() -> Option { + let allow = None; + allow?; + Some(42) +} diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs index 86f6b2c5742a9..334e7ddd9d233 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs @@ -15,7 +15,6 @@ use proc_macros::{external, with_span}; #[warn(deref_nullptr)] #[deny(deref_nullptr)] #[forbid(deref_nullptr)] - fn main() { external! { #[allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr index 9bc3ca0f2afd3..86d7845df0416 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr @@ -36,7 +36,7 @@ LL | #[expect(dead_code)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:47:5 + --> tests/ui/allow_attributes_without_reason.rs:46:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | #[allow(unused)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:47:5 + --> tests/ui/allow_attributes_without_reason.rs:46:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index 0838d064a5fa1..3f20407308516 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -2,7 +2,6 @@ #![feature(f128)] #![feature(f16)] - #![allow( clippy::assign_op_pattern, clippy::erasing_op, diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 78914667bf305..78b1aca4b8a47 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:167:13 + --> tests/ui/arithmetic_side_effects.rs:166:13 | LL | let _ = 1f16 + 1f16; | ^^^^^^^^^^^ @@ -8,733 +8,733 @@ LL | let _ = 1f16 + 1f16; = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:170:13 + --> tests/ui/arithmetic_side_effects.rs:169:13 | LL | let _ = 1f128 + 1f128; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:308:5 + --> tests/ui/arithmetic_side_effects.rs:307:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:309:5 + --> tests/ui/arithmetic_side_effects.rs:308:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:310:5 + --> tests/ui/arithmetic_side_effects.rs:309:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:311:5 + --> tests/ui/arithmetic_side_effects.rs:310:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:313:5 + --> tests/ui/arithmetic_side_effects.rs:312:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:315:5 + --> tests/ui/arithmetic_side_effects.rs:314:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:317:5 + --> tests/ui/arithmetic_side_effects.rs:316:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:319:5 + --> tests/ui/arithmetic_side_effects.rs:318:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:321:5 + --> tests/ui/arithmetic_side_effects.rs:320:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:323:5 + --> tests/ui/arithmetic_side_effects.rs:322:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:325:5 + --> tests/ui/arithmetic_side_effects.rs:324:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:327:5 + --> tests/ui/arithmetic_side_effects.rs:326:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:329:5 + --> tests/ui/arithmetic_side_effects.rs:328:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:331:5 + --> tests/ui/arithmetic_side_effects.rs:330:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:333:5 + --> tests/ui/arithmetic_side_effects.rs:332:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:335:5 + --> tests/ui/arithmetic_side_effects.rs:334:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:337:5 + --> tests/ui/arithmetic_side_effects.rs:336:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:339:5 + --> tests/ui/arithmetic_side_effects.rs:338:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:341:5 + --> tests/ui/arithmetic_side_effects.rs:340:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:343:5 + --> tests/ui/arithmetic_side_effects.rs:342:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:345:5 + --> tests/ui/arithmetic_side_effects.rs:344:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:347:5 + --> tests/ui/arithmetic_side_effects.rs:346:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:349:5 + --> tests/ui/arithmetic_side_effects.rs:348:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:351:5 + --> tests/ui/arithmetic_side_effects.rs:350:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:352:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:353:5 + --> tests/ui/arithmetic_side_effects.rs:352:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:355:5 + --> tests/ui/arithmetic_side_effects.rs:354:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:10 + --> tests/ui/arithmetic_side_effects.rs:357:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:359:10 + --> tests/ui/arithmetic_side_effects.rs:358:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:10 + --> tests/ui/arithmetic_side_effects.rs:359:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:361:10 + --> tests/ui/arithmetic_side_effects.rs:360:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:10 + --> tests/ui/arithmetic_side_effects.rs:361:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:363:10 + --> tests/ui/arithmetic_side_effects.rs:362:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:10 + --> tests/ui/arithmetic_side_effects.rs:363:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:365:10 + --> tests/ui/arithmetic_side_effects.rs:364:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:10 + --> tests/ui/arithmetic_side_effects.rs:365:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:367:10 + --> tests/ui/arithmetic_side_effects.rs:366:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:10 + --> tests/ui/arithmetic_side_effects.rs:367:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:369:10 + --> tests/ui/arithmetic_side_effects.rs:368:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:10 + --> tests/ui/arithmetic_side_effects.rs:369:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:371:10 + --> tests/ui/arithmetic_side_effects.rs:370:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:10 + --> tests/ui/arithmetic_side_effects.rs:371:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:373:10 + --> tests/ui/arithmetic_side_effects.rs:372:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:10 + --> tests/ui/arithmetic_side_effects.rs:373:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:375:10 + --> tests/ui/arithmetic_side_effects.rs:374:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:10 + --> tests/ui/arithmetic_side_effects.rs:375:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:377:15 + --> tests/ui/arithmetic_side_effects.rs:376:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:15 + --> tests/ui/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:379:15 + --> tests/ui/arithmetic_side_effects.rs:378:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:15 + --> tests/ui/arithmetic_side_effects.rs:379:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:381:15 + --> tests/ui/arithmetic_side_effects.rs:380:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:15 + --> tests/ui/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:383:15 + --> tests/ui/arithmetic_side_effects.rs:382:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:15 + --> tests/ui/arithmetic_side_effects.rs:383:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:385:15 + --> tests/ui/arithmetic_side_effects.rs:384:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:15 + --> tests/ui/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:387:15 + --> tests/ui/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:15 + --> tests/ui/arithmetic_side_effects.rs:387:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:389:15 + --> tests/ui/arithmetic_side_effects.rs:388:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:15 + --> tests/ui/arithmetic_side_effects.rs:389:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:391:15 + --> tests/ui/arithmetic_side_effects.rs:390:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:15 + --> tests/ui/arithmetic_side_effects.rs:391:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:393:15 + --> tests/ui/arithmetic_side_effects.rs:392:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:15 + --> tests/ui/arithmetic_side_effects.rs:393:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:395:15 + --> tests/ui/arithmetic_side_effects.rs:394:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:396:15 + --> tests/ui/arithmetic_side_effects.rs:395:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:397:15 + --> tests/ui/arithmetic_side_effects.rs:396:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:15 + --> tests/ui/arithmetic_side_effects.rs:397:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:399:15 + --> tests/ui/arithmetic_side_effects.rs:398:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:402:23 + --> tests/ui/arithmetic_side_effects.rs:401:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:403:21 + --> tests/ui/arithmetic_side_effects.rs:402:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:21 + --> tests/ui/arithmetic_side_effects.rs:403:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:405:28 + --> tests/ui/arithmetic_side_effects.rs:404:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:407:23 + --> tests/ui/arithmetic_side_effects.rs:406:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:408:21 + --> tests/ui/arithmetic_side_effects.rs:407:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:409:21 + --> tests/ui/arithmetic_side_effects.rs:408:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:410:28 + --> tests/ui/arithmetic_side_effects.rs:409:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:413:10 + --> tests/ui/arithmetic_side_effects.rs:412:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:414:10 + --> tests/ui/arithmetic_side_effects.rs:413:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:415:15 + --> tests/ui/arithmetic_side_effects.rs:414:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:416:15 + --> tests/ui/arithmetic_side_effects.rs:415:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:425:5 + --> tests/ui/arithmetic_side_effects.rs:424:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:426:5 + --> tests/ui/arithmetic_side_effects.rs:425:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:427:5 + --> tests/ui/arithmetic_side_effects.rs:426:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:428:5 + --> tests/ui/arithmetic_side_effects.rs:427:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:429:5 + --> tests/ui/arithmetic_side_effects.rs:428:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:440:5 + --> tests/ui/arithmetic_side_effects.rs:439:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:441:5 + --> tests/ui/arithmetic_side_effects.rs:440:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:442:5 + --> tests/ui/arithmetic_side_effects.rs:441:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:444:5 + --> tests/ui/arithmetic_side_effects.rs:443:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:446:5 + --> tests/ui/arithmetic_side_effects.rs:445:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:447:5 + --> tests/ui/arithmetic_side_effects.rs:446:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:449:5 + --> tests/ui/arithmetic_side_effects.rs:448:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:451:5 + --> tests/ui/arithmetic_side_effects.rs:450:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:452:5 + --> tests/ui/arithmetic_side_effects.rs:451:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:462:5 + --> tests/ui/arithmetic_side_effects.rs:461:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:516:9 + --> tests/ui/arithmetic_side_effects.rs:515:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:520:9 + --> tests/ui/arithmetic_side_effects.rs:519:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:531:5 + --> tests/ui/arithmetic_side_effects.rs:530:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:535:5 + --> tests/ui/arithmetic_side_effects.rs:534:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs b/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs index 33cea4806814b..a7d29cc239e53 100644 --- a/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs +++ b/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs @@ -1,5 +1,4 @@ -//@ignore-target-i686 -//@ignore-target-x86 +//@ignore-target: i686 x86 //@needs-asm-support #[warn(clippy::inline_asm_x86_intel_syntax)] diff --git a/src/tools/clippy/tests/ui/asm_syntax_x86.rs b/src/tools/clippy/tests/ui/asm_syntax_x86.rs index 835943b43894c..5ceaceb7527b3 100644 --- a/src/tools/clippy/tests/ui/asm_syntax_x86.rs +++ b/src/tools/clippy/tests/ui/asm_syntax_x86.rs @@ -1,6 +1,4 @@ -//@revisions: i686 x86_64 -//@[i686] only-target-i686 -//@[x86_64] only-target-x86_64 +//@only-target: i686 x86_64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/src/tools/clippy/tests/ui/asm_syntax_x86.stderr b/src/tools/clippy/tests/ui/asm_syntax_x86.stderr new file mode 100644 index 0000000000000..1911ef66e2391 --- /dev/null +++ b/src/tools/clippy/tests/ui/asm_syntax_x86.stderr @@ -0,0 +1,70 @@ +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:8:9 + | +LL | asm!(""); + | ^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]` + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:10:9 + | +LL | asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:12:9 + | +LL | asm!("", options(nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:18:5 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:20:5 + | +LL | global_asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:33:9 + | +LL | asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]` + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:35:9 + | +LL | asm!("", options(nostack, att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:41:5 + | +LL | global_asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/auxiliary/external_item.rs b/src/tools/clippy/tests/ui/auxiliary/external_item.rs new file mode 100644 index 0000000000000..ca4bc369e4494 --- /dev/null +++ b/src/tools/clippy/tests/ui/auxiliary/external_item.rs @@ -0,0 +1,7 @@ +pub struct _ExternalStruct {} + +impl _ExternalStruct { + pub fn _foo(self) {} +} + +pub fn _exernal_foo() {} diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs index f6fdebaf25274..e72d6b6ceadfd 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs @@ -11,8 +11,8 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, - PatType, Signature, TraitItem, Type, Visibility, + FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, + Type, Visibility, parse_macro_input, parse_quote, }; #[proc_macro_attribute] diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index 4c3df47226909..bd90042c1da82 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -5,7 +5,7 @@ extern crate proc_macro; -use proc_macro::{quote, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, quote}; #[proc_macro_derive(DeriveSomething)] pub fn derive(_: TokenStream) -> TokenStream { diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index 79e8eff3aa101..3d6f164d35833 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,5 +1,5 @@ extern crate proc_macro; -use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree, token_stream}; fn read_ident(iter: &mut token_stream::IntoIter) -> Ident { match iter.next() { diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs index ed7412f7c4076..1a2a4ec231143 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs @@ -5,9 +5,9 @@ extern crate proc_macro; use core::mem; -use proc_macro::token_stream::IntoIter; use proc_macro::Delimiter::{self, Brace, Parenthesis}; use proc_macro::Spacing::{self, Alone, Joint}; +use proc_macro::token_stream::IntoIter; use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; use syn::spanned::Spanned; diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs index 452d1b198133e..de220505c3e08 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs @@ -5,8 +5,8 @@ use std::borrow::Cow; use std::cell::{Cell, UnsafeCell}; use std::fmt::Display; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Once; +use std::sync::atomic::{AtomicUsize, Ordering}; const ATOMIC: AtomicUsize = AtomicUsize::new(5); const CELL: Cell = Cell::new(6); diff --git a/src/tools/clippy/tests/ui/cast_alignment.rs b/src/tools/clippy/tests/ui/cast_alignment.rs index 98ef5e36f9488..72f5d4268cc1b 100644 --- a/src/tools/clippy/tests/ui/cast_alignment.rs +++ b/src/tools/clippy/tests/ui/cast_alignment.rs @@ -2,16 +2,16 @@ #![feature(rustc_private)] #![feature(core_intrinsics)] -extern crate libc; - -#[warn(clippy::cast_ptr_alignment)] -#[allow( +#![warn(clippy::cast_ptr_alignment)] +#![allow( clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless, clippy::borrow_as_ptr )] +extern crate libc; + fn main() { /* These should be warned against */ diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs index ec45d635c1727..913aab7274716 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs @@ -1,5 +1,5 @@ -#[allow(clippy::unnecessary_operation)] -#[allow(clippy::implicit_clone)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::implicit_clone)] fn main() { let x = &Baz; diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed index 3b410b2f17b80..c2d76146c641d 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed @@ -1,9 +1,7 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] +#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] #[rustfmt::skip] -#[warn(clippy::collapsible_if)] -#[warn(clippy::collapsible_else_if)] - fn main() { let x = "hello"; let y = "world"; @@ -76,7 +74,6 @@ fn main() { } #[rustfmt::skip] -#[allow(dead_code)] fn issue_7318() { if true { println!("I've been resolved!") }else if false {} diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs index 772ef6f9fc606..3579e46cd4479 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs @@ -1,9 +1,7 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] +#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] #[rustfmt::skip] -#[warn(clippy::collapsible_if)] -#[warn(clippy::collapsible_else_if)] - fn main() { let x = "hello"; let y = "world"; @@ -90,7 +88,6 @@ fn main() { } #[rustfmt::skip] -#[allow(dead_code)] fn issue_7318() { if true { println!("I've been resolved!") }else{ diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.stderr b/src/tools/clippy/tests/ui/collapsible_else_if.stderr index dc19d90b4d132..395c2dcf68dc0 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_else_if.stderr @@ -1,5 +1,5 @@ error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:13:12 + --> tests/ui/collapsible_else_if.rs:11:12 | LL | } else { | ____________^ @@ -19,7 +19,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:21:12 + --> tests/ui/collapsible_else_if.rs:19:12 | LL | } else { | ____________^ @@ -37,7 +37,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:29:12 + --> tests/ui/collapsible_else_if.rs:27:12 | LL | } else { | ____________^ @@ -60,7 +60,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:40:12 + --> tests/ui/collapsible_else_if.rs:38:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:51:12 + --> tests/ui/collapsible_else_if.rs:49:12 | LL | } else { | ____________^ @@ -106,7 +106,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:62:12 + --> tests/ui/collapsible_else_if.rs:60:12 | LL | } else { | ____________^ @@ -129,7 +129,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:73:12 + --> tests/ui/collapsible_else_if.rs:71:12 | LL | } else { | ____________^ @@ -152,7 +152,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:96:10 + --> tests/ui/collapsible_else_if.rs:93:10 | LL | }else{ | __________^ diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed index e102b13a76185..a2a3dd9086d4c 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed +++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed @@ -33,4 +33,12 @@ fn main() { if let [0] = &*s && s == [0] {} + + // Also lint the `PartialEq` methods + let s = String::new(); + let _ = s.is_empty(); + let _ = !s.is_empty(); + let v = vec![0]; + let _ = v.is_empty(); + let _ = !v.is_empty(); } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs index 69a6c967d3821..7c5689a4bbec9 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.rs +++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs @@ -33,4 +33,12 @@ fn main() { if let [0] = &*s && s == [0] {} + + // Also lint the `PartialEq` methods + let s = String::new(); + let _ = s.eq(""); + let _ = s.ne(""); + let v = vec![0]; + let _ = v.eq(&[]); + let _ = v.ne(&[]); } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr index 6b027459ed347..2ee0efc7dbb19 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr +++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr @@ -55,5 +55,29 @@ error: comparison to empty slice LL | && s == [] | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` -error: aborting due to 9 previous errors +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:39:13 + | +LL | let _ = s.eq(""); + | ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:40:13 + | +LL | let _ = s.ne(""); + | ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:42:13 + | +LL | let _ = v.eq(&[]); + | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:43:13 + | +LL | let _ = v.ne(&[]); + | ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs index 948deba3ea6e3..fec16671eeb32 100644 --- a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs +++ b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/1698 +// Test for https://github.com/rust-lang/rust-clippy/issues/1698 pub trait Trait { const CONSTANT: u8; diff --git a/src/tools/clippy/tests/ui/crashes/cc_seme.rs b/src/tools/clippy/tests/ui/crashes/cc_seme.rs index 98588be9cf829..98897d6d7aaf9 100644 --- a/src/tools/clippy/tests/ui/crashes/cc_seme.rs +++ b/src/tools/clippy/tests/ui/crashes/cc_seme.rs @@ -1,6 +1,4 @@ -#[allow(dead_code)] - -/// Test for https://github.com/rust-lang/rust-clippy/issues/478 +// Test for https://github.com/rust-lang/rust-clippy/issues/478 enum Baz { One, diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.rs b/src/tools/clippy/tests/ui/crashes/ice-11230.rs index 5761882273e00..94044e9435ed4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11230.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/11230 +// Test for https://github.com/rust-lang/rust-clippy/issues/11230 fn main() { const A: &[for<'a> fn(&'a ())] = &[]; diff --git a/src/tools/clippy/tests/ui/crashes/ice-1588.rs b/src/tools/clippy/tests/ui/crashes/ice-1588.rs index b0a3d11bce463..9ec093721c17e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1588.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1588.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1588 +// Test for https://github.com/rust-lang/rust-clippy/issues/1588 fn main() { match 1 { diff --git a/src/tools/clippy/tests/ui/crashes/ice-1969.rs b/src/tools/clippy/tests/ui/crashes/ice-1969.rs index 96a8fe6c24d56..eb901c7672948 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1969.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1969.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1969 +// Test for https://github.com/rust-lang/rust-clippy/issues/1969 fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-2499.rs b/src/tools/clippy/tests/ui/crashes/ice-2499.rs index 45b3b1869dde6..732f331ad145e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2499.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2499.rs @@ -1,8 +1,8 @@ #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] -/// Should not trigger an ICE in `SpanlessHash` / `consts::constant` -/// -/// Issue: https://github.com/rust-lang/rust-clippy/issues/2499 +// Should not trigger an ICE in `SpanlessHash` / `consts::constant` +// +// Issue: https://github.com/rust-lang/rust-clippy/issues/2499 fn f(s: &[u8]) -> bool { let t = s[0] as char; diff --git a/src/tools/clippy/tests/ui/crashes/ice-2594.rs b/src/tools/clippy/tests/ui/crashes/ice-2594.rs index 3f3986b6fc692..dddf860bd1785 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2594.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2594.rs @@ -3,7 +3,6 @@ /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` /// /// Issue: https://github.com/rust-lang/rust-clippy/issues/2594 - fn spanless_hash_ice() { let txt = "something"; let empty_header: [u8; 1] = [1; 1]; diff --git a/src/tools/clippy/tests/ui/crashes/ice-2727.rs b/src/tools/clippy/tests/ui/crashes/ice-2727.rs index 56024abc8f58d..59fb9b04b86d0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2727.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2727.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/2727 +// Test for https://github.com/rust-lang/rust-clippy/issues/2727 pub fn f(new: fn()) { new(); diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs index 61ef24804986e..5f7d91abf9959 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs @@ -5,10 +5,10 @@ dead_code )] -/// This should not compile-fail with: -/// -/// error[E0277]: the trait bound `T: Foo` is not satisfied -// See rust-lang/rust-clippy#2760. +// This should not compile-fail with: +// +// error[E0277]: the trait bound `T: Foo` is not satisfied +// See https://github.com/rust-lang/rust-clippy/issues/2760 trait Foo { type Bar; diff --git a/src/tools/clippy/tests/ui/crashes/ice-2862.rs b/src/tools/clippy/tests/ui/crashes/ice-2862.rs index 8326e3663b054..2573b571f55cd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2862.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2862.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/2862 +// Test for https://github.com/rust-lang/rust-clippy/issues/2862 pub trait FooMap { fn map B>(&self, f: F) -> B; diff --git a/src/tools/clippy/tests/ui/crashes/ice-2865.rs b/src/tools/clippy/tests/ui/crashes/ice-2865.rs index c629813960162..28363707acca7 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2865.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2865.rs @@ -1,6 +1,6 @@ #![allow(dead_code, clippy::extra_unused_lifetimes)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2865 +// Test for https://github.com/rust-lang/rust-clippy/issues/2865 struct Ice { size: String, diff --git a/src/tools/clippy/tests/ui/crashes/ice-3151.rs b/src/tools/clippy/tests/ui/crashes/ice-3151.rs index 268ba86fc7aa8..f88a26cb48592 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3151.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3151.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/3151 +// Test for https://github.com/rust-lang/rust-clippy/issues/3151 #[derive(Clone)] pub struct HashMap { diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs index 21cd9d337cdd0..ccd617e305dae 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs @@ -2,7 +2,7 @@ #![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)] #![allow(unused)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/3462 +// Test for https://github.com/rust-lang/rust-clippy/issues/3462 enum Foo { Bar, diff --git a/src/tools/clippy/tests/ui/crashes/ice-3747.rs b/src/tools/clippy/tests/ui/crashes/ice-3747.rs index cdf018cbc88d8..44b1d7ed1b2e8 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3747.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3747.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/3747 +// Test for https://github.com/rust-lang/rust-clippy/issues/3747 macro_rules! a { ( $pub:tt $($attr:tt)* ) => { diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.rs b/src/tools/clippy/tests/ui/crashes/ice-3969.rs index d5676cbd91d19..ac09ce08753af 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3969.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.rs @@ -1,7 +1,7 @@ // https://github.com/rust-lang/rust-clippy/issues/3969 // used to crash: error: internal compiler error: // src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs +// std::iter::Iterator>::Item` test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs // Check that tautalogically false bounds are accepted, and are used // in type inference. @@ -18,7 +18,7 @@ struct Dst { struct TwoStrs(str, str) where str: Sized; -//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetim +//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetime //~| NOTE: `-D trivial-bounds` implied by `-D warnings` fn unsized_local() diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.rs b/src/tools/clippy/tests/ui/crashes/ice-6251.rs index a81137a646558..73e919b6dd2eb 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6251.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6251.rs @@ -1,5 +1,5 @@ // originally from glacier/fixed/77329.rs -// assertion failed: `(left == right) ; different DefIds +// assertion failed: `(left == right)` ; different DefIds //@no-rustfix fn bug() -> impl Iterator { std::iter::empty() diff --git a/src/tools/clippy/tests/ui/crashes/ice-700.rs b/src/tools/clippy/tests/ui/crashes/ice-700.rs index 0cbceedbd6bdb..5e004b94330ea 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-700.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-700.rs @@ -1,6 +1,6 @@ #![deny(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/700 +// Test for https://github.com/rust-lang/rust-clippy/issues/700 fn core() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs index a2683b3ce3402..ccf6d7ff94f23 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple -//@ignore-target-windows +//@ignore-target: apple windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs index 30e4b11ec0bd4..c0671eaff1450 100644 --- a/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs +++ b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs @@ -1,6 +1,6 @@ #![deny(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1336 +// Test for https://github.com/rust-lang/rust-clippy/issues/1336 #[allow(dead_code)] struct Foo; diff --git a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs index 2f913292995ea..a900fe5e6bc66 100644 --- a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs @@ -1,7 +1,7 @@ #![allow(clippy::comparison_chain)] #![deny(clippy::if_same_then_else)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2426 +// Test for https://github.com/rust-lang/rust-clippy/issues/2426 fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/inherent_impl.rs b/src/tools/clippy/tests/ui/crashes/inherent_impl.rs index aeb27b5ba8c2f..800a5a383f626 100644 --- a/src/tools/clippy/tests/ui/crashes/inherent_impl.rs +++ b/src/tools/clippy/tests/ui/crashes/inherent_impl.rs @@ -1,6 +1,6 @@ #![deny(clippy::multiple_inherent_impl)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/4578 +// Test for https://github.com/rust-lang/rust-clippy/issues/4578 macro_rules! impl_foo { ($struct:ident) => { diff --git a/src/tools/clippy/tests/ui/crashes/issue-825.rs b/src/tools/clippy/tests/ui/crashes/issue-825.rs index 05696e3d7d56f..e8b455a0ec67b 100644 --- a/src/tools/clippy/tests/ui/crashes/issue-825.rs +++ b/src/tools/clippy/tests/ui/crashes/issue-825.rs @@ -1,6 +1,6 @@ #![allow(warnings)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/825 +// Test for https://github.com/rust-lang/rust-clippy/issues/825 // this should compile in a reasonable amount of time fn rust_type_id(name: &str) { diff --git a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs index 94c939665e616..626179c001557 100644 --- a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs +++ b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs @@ -1,6 +1,6 @@ #![deny(clippy::match_same_arms)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2427 +// Test for https://github.com/rust-lang/rust-clippy/issues/2427 const PRICE_OF_SWEETS: u32 = 5; const PRICE_OF_KINDNESS: u32 = 0; diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr index 90076d4338a47..2847957000692 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr +++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr @@ -4,7 +4,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test(x: Foo<'_>) {} | ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/crashes/needless_pass_by_value-w-late-bound.rs:5:1 | LL | struct Foo<'a>(&'a [(); 100]); diff --git a/src/tools/clippy/tests/ui/crashes/returns.rs b/src/tools/clippy/tests/ui/crashes/returns.rs index 8021ed4607dde..91cdb5306c895 100644 --- a/src/tools/clippy/tests/ui/crashes/returns.rs +++ b/src/tools/clippy/tests/ui/crashes/returns.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/1346 +// Test for https://github.com/rust-lang/rust-clippy/issues/1346 #[deny(warnings)] fn cfg_return() -> i32 { diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs index aa76688d80101..5d853d97bc35b 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple +//@ignore-target: apple #![feature(rustc_attrs)] diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs index 32eba9695920c..9e5b2a4890348 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple +//@ignore-target: apple #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs index 9dafad8b784b9..0dccf18c49303 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::Display; use std::ptr; -use std::sync::atomic::AtomicUsize; use std::sync::Once; +use std::sync::atomic::AtomicUsize; const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR: interior mutable const CELL: Cell = Cell::new(6); //~ ERROR: interior mutable diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index 190d636ebf34a..c9650312db878 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple +//@ignore-target: apple #![feature(no_core, lang_items, start)] #![no_core] diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs index e0acf050949a1..1abba60fd34a8 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.rs +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs @@ -67,3 +67,9 @@ fn foobar() { }; } } + +#[allow(unused)] +fn ignore_todo() { + let x: u32 = todo!(); + println!("{x}"); +} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed deleted file mode 100644 index 1aaa26afe7f26..0000000000000 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed +++ /dev/null @@ -1,47 +0,0 @@ -// https://github.com/rust-lang/rust-clippy/issues/12917 -#![warn(clippy::doc_lazy_continuation)] - -/// This is a constant. -/// -/// The meaning of which should not be explained. -pub const A: i32 = 42; - -/// This is another constant, no longer used. -/// -/// This block of documentation has a long -/// explanation and derivation to explain -/// why it is what it is, and how it's used. -/// -/// It is left here for historical reasons, and -/// for reference. -/// -/// Reasons it's great: -/// - First reason -/// - Second reason -/// -//pub const B: i32 = 1337; - -/// This is yet another constant. -/// -/// This has a similar fate as `B`. -/// -/// Reasons it's useful: -/// 1. First reason -/// 2. Second reason -/// -//pub const C: i32 = 8008; - -/// This is still in use. -pub const D: i32 = 20; - -/// > blockquote code path -/// - -/// bottom text -pub const E: i32 = 20; - -/// > blockquote code path -/// -#[repr(C)] -/// bottom text -pub struct Foo(i32); diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs deleted file mode 100644 index e1ab8fc838926..0000000000000 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs +++ /dev/null @@ -1,43 +0,0 @@ -// https://github.com/rust-lang/rust-clippy/issues/12917 -#![warn(clippy::doc_lazy_continuation)] - -/// This is a constant. -/// -/// The meaning of which should not be explained. -pub const A: i32 = 42; - -/// This is another constant, no longer used. -/// -/// This block of documentation has a long -/// explanation and derivation to explain -/// why it is what it is, and how it's used. -/// -/// It is left here for historical reasons, and -/// for reference. -/// -/// Reasons it's great: -/// - First reason -/// - Second reason -//pub const B: i32 = 1337; - -/// This is yet another constant. -/// -/// This has a similar fate as `B`. -/// -/// Reasons it's useful: -/// 1. First reason -/// 2. Second reason -//pub const C: i32 = 8008; - -/// This is still in use. -pub const D: i32 = 20; - -/// > blockquote code path - -/// bottom text -pub const E: i32 = 20; - -/// > blockquote code path -#[repr(C)] -/// bottom text -pub struct Foo(i32); diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr deleted file mode 100644 index 854906a747418..0000000000000 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error: doc list item without indentation - --> tests/ui/doc/doc_lazy_blank_line.rs:23:5 - | -LL | /// This is yet another constant. - | ^ - | - = help: if this is intended to be part of the list, indent 3 spaces - = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// - Second reason -LL + /// - | - -error: doc list item without indentation - --> tests/ui/doc/doc_lazy_blank_line.rs:32:5 - | -LL | /// This is still in use. - | ^ - | - = help: if this is intended to be part of the list, indent 4 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// 2. Second reason -LL + /// - | - -error: doc quote line without `>` marker - --> tests/ui/doc/doc_lazy_blank_line.rs:37:5 - | -LL | /// bottom text - | ^ - | - = help: if this not intended to be a quote at all, escape it with `\>` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// > blockquote code path -LL + /// - | - -error: doc quote line without `>` marker - --> tests/ui/doc/doc_lazy_blank_line.rs:42:5 - | -LL | /// bottom text - | ^ - | - = help: if this not intended to be a quote at all, escape it with `\>` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// > blockquote code path -LL + /// - | - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed index ea59ae4c01c96..da537518a2b53 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed @@ -7,9 +7,8 @@ fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -/// //~^ ERROR: doc list item without indentation -/// because they don't have the +/// because they don't have the //~^ ERROR: doc list item without indentation fn two() {} @@ -20,9 +19,8 @@ fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -/// //~^ ERROR: doc list item without indentation -/// because they don't have the +/// because they don't have the //~^ ERROR: doc list item without indentation fn four() {} @@ -33,9 +31,8 @@ fn five() {} /// - - first line /// this will warn on the lazy continuation -/// //~^ ERROR: doc list item without indentation -/// and so should this +/// and so should this //~^ ERROR: doc list item without indentation fn six() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr index 52aa74df8948c..b38f43b7555f1 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr @@ -30,12 +30,11 @@ error: doc list item without indentation LL | /// because they don't have the | ^ | - = help: if this is intended to be part of the list, indent 3 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// lazy list continuations don't make warnings with this lint -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// because they don't have the + | +++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:16:5 @@ -67,12 +66,11 @@ error: doc list item without indentation LL | /// because they don't have the | ^ | - = help: if this is intended to be part of the list, indent 4 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// lazy list continuations don't make warnings with this lint -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// because they don't have the + | ++++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:28:5 @@ -104,12 +102,11 @@ error: doc list item without indentation LL | /// and so should this | ^^^^ | - = help: if this is intended to be part of the list, indent 2 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// this will warn on the lazy continuation -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// and so should this + | ++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:56:5 diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs index 118f6e4a34c0a..a725538436cb1 100644 --- a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs +++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs @@ -1,5 +1,4 @@ #![warn(clippy::duplicate_underscore_argument)] -#[allow(dead_code, unused)] fn join_the_dark_side(darth: i32, _darth: i32) {} //~^ ERROR: `darth` already exists, having another argument having almost the same name ma diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr b/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr index 40a24b823d115..74979b157882a 100644 --- a/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr +++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr @@ -1,5 +1,5 @@ error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult - --> tests/ui/duplicate_underscore_argument.rs:4:23 + --> tests/ui/duplicate_underscore_argument.rs:3:23 | LL | fn join_the_dark_side(darth: i32, _darth: i32) {} | ^^^^^ diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs index 97cf4a69682d7..874f5d22075c1 100644 --- a/src/tools/clippy/tests/ui/duplicated_attributes.rs +++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs @@ -27,4 +27,8 @@ trait Abc {} #[proc_macro_attr::duplicated_attr()] // Should not warn! fn babar() {} +#[allow(missing_docs, reason = "library for internal use only")] +#[allow(exported_private_dependencies, reason = "library for internal use only")] +fn duplicate_reason() {} + fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed new file mode 100644 index 0000000000000..fd6a94b6a80c8 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed @@ -0,0 +1,135 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +/// Meant to be an +/// inner doc comment +/// for the crate +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + /// Meant to be an + /// inner doc comment + /// for the module + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning +/** This is also a doc comment and is part of the warning + */ +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + /// docs for `old_code` + // fn old_code() {} + fn new_code() {} + + //~vv empty_line_after_doc_comments + /// Docs + /// for OldA + // struct OldA; + /// Docs + /// for OldB + // struct OldB; + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /** + * Meant to be inner doc comment + */ + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /** + * Docs for `old_code` + */ + /* fn old_code() {} */ + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + /// Docs for `old_code2` + /* fn old_code2() {} */ + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed new file mode 100644 index 0000000000000..7a57dcd92332b --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed @@ -0,0 +1,144 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +//! Meant to be an +//! inner doc comment +//! for the crate + +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + //! Meant to be an + //! inner doc comment + //! for the module + + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + /// + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning +/** This is also a doc comment and is part of the warning + */ +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + // /// docs for `old_code` + // fn old_code() {} + + fn new_code() {} + + //~vv empty_line_after_doc_comments + // /// Docs + // /// for OldA + // struct OldA; + + // /// Docs + // /// for OldB + // struct OldB; + + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /*! + * Meant to be inner doc comment + */ + + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /* + * Docs for `old_code` + */ + /* fn old_code() {} */ + + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + // /// Docs for `old_code2` + /* fn old_code2() {} */ + + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs new file mode 100644 index 0000000000000..1da761a5c3d52 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs @@ -0,0 +1,147 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +/// Meant to be an +/// inner doc comment +/// for the crate + +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + /// Meant to be an + /// inner doc comment + /// for the module + + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning + +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning + +/** This is also a doc comment and is part of the warning + */ + +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + /// docs for `old_code` + // fn old_code() {} + + fn new_code() {} + + //~vv empty_line_after_doc_comments + /// Docs + /// for OldA + // struct OldA; + + /// Docs + /// for OldB + // struct OldB; + + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /** + * Meant to be inner doc comment + */ + + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /** + * Docs for `old_code` + */ + /* fn old_code() {} */ + + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + /// Docs for `old_code2` + /* fn old_code2() {} */ + + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr new file mode 100644 index 0000000000000..c238b4c9a17f2 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr @@ -0,0 +1,176 @@ +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:6:1 + | +LL | / /// for the crate +LL | | + | |_ +LL | fn first_in_crate() {} + | ------------------- the comment documents this function + | + = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` + = help: if the empty line is unintentional remove it +help: if the comment should document the crate use an inner doc comment + | +LL ~ //! Meant to be an +LL ~ //! inner doc comment +LL ~ //! for the crate + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:14:5 + | +LL | / /// for the module +LL | | + | |_ +LL | fn first_in_module() {} + | -------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the comment should document the parent module use an inner doc comment + | +LL ~ //! Meant to be an +LL ~ //! inner doc comment +LL ~ //! for the module + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:27:5 + | +LL | / /// # Indented +LL | | + | |_ +LL | /// Blank line +LL | fn indented() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the documentation should include the empty line include it in the comment + | +LL | /// + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:34:1 + | +LL | / /// This should produce a warning +LL | | + | |_ +LL | fn with_doc_and_newline() {} + | ------------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:44:1 + | +LL | / /// This doc comment should produce a warning +LL | | +LL | | /** This is also a doc comment and is part of the warning +LL | | */ +LL | | + | |_ +... +LL | fn three_attributes() {} + | --------------------- the comment documents this function + | + = help: if the empty lines are unintentional remove them + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:56:5 + | +LL | / /// docs for `old_code` +LL | | // fn old_code() {} +LL | | + | |_ +LL | fn new_code() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code` comment it out + | +LL | // /// docs for `old_code` + | ++ + +error: empty lines after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:63:5 + | +LL | / /// for OldA +LL | | // struct OldA; +LL | | +LL | | /// Docs +LL | | /// for OldB +LL | | // struct OldB; +LL | | + | |_ +... +LL | struct Multiple; + | --------------- the comment documents this struct + | + = help: if the empty lines are unintentional remove them +help: if the doc comment should not document `Multiple` comment it out + | +LL ~ // /// Docs +LL ~ // /// for OldA +LL | // struct OldA; +LL | +LL ~ // /// Docs +LL ~ // /// for OldB + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:78:5 + | +LL | / /** +LL | | * Meant to be inner doc comment +LL | | */ +LL | | + | |_ +LL | fn first_in_module() {} + | -------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the comment should document the parent module use an inner doc comment + | +LL | /*! + | ~ + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:85:5 + | +LL | / /** +LL | | * Docs for `old_code` +LL | | */ +LL | | /* fn old_code() {} */ +LL | | + | |_ +... +LL | fn new_code() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code` comment it out + | +LL - /** +LL + /* + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:96:5 + | +LL | / /// Docs for `old_code2` +LL | | /* fn old_code2() {} */ +LL | | + | |_ +LL | /// Docs for `new_code2` +LL | fn new_code2() {} + | -------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code2` comment it out + | +LL | // /// Docs for `old_code2` + | ++ + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed new file mode 100644 index 0000000000000..36d80a2c95bf6 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed @@ -0,0 +1,108 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#[crate_type = "lib"] +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #[crate_type = "lib"] + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute +fn comment_before_empty_line() {} + +//~v empty_line_after_outer_attr +#[allow(unused)] +// This comment is isolated +pub fn isolated_comment() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed new file mode 100644 index 0000000000000..0e8e4129e858c --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed @@ -0,0 +1,111 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#![crate_type = "lib"] + +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #![crate_type = "lib"] + + + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute +fn comment_before_empty_line() {} + +//~v empty_line_after_outer_attr +#[allow(unused)] +// This comment is isolated +pub fn isolated_comment() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs new file mode 100644 index 0000000000000..1295088ac00ed --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs @@ -0,0 +1,119 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#[crate_type = "lib"] + +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] + +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] + +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #[crate_type = "lib"] + + + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] + +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] + +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] + +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute + +fn comment_before_empty_line() {} + +//~v empty_line_after_outer_attr +#[allow(unused)] + +// This comment is isolated + +pub fn isolated_comment() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr new file mode 100644 index 0000000000000..958b40424a928 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr @@ -0,0 +1,116 @@ +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:5:1 + | +LL | / #[crate_type = "lib"] +LL | | + | |_ +LL | fn first_in_crate() {} + | ------------------- the attribute applies to this function + | + = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` + = help: if the empty line is unintentional remove it +help: if the attribute should apply to the crate use an inner attribute + | +LL | #![crate_type = "lib"] + | + + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:13:1 + | +LL | / #[inline] +LL | | + | |_ +LL | /// some comment +LL | fn with_one_newline_and_comment() {} + | --------------------------------- the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:23:1 + | +LL | / #[inline] +LL | | + | |_ +LL | fn with_one_newline() {} + | --------------------- the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:30:5 + | +LL | / #[crate_type = "lib"] +LL | | +LL | | + | |_ +LL | fn with_two_newlines() {} + | ---------------------- the attribute applies to this function + | + = help: if the empty lines are unintentional remove them +help: if the attribute should apply to the parent module use an inner attribute + | +LL | #![crate_type = "lib"] + | + + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:37:1 + | +LL | / #[doc = "doc attributes should be considered attributes"] +LL | | + | |_ +LL | enum Baz { + | -------- the attribute applies to this enum + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:45:1 + | +LL | / #[repr(C)] +LL | | + | |_ +LL | struct Foo { + | ---------- the attribute applies to this struct + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:53:1 + | +LL | / #[allow(dead_code)] +LL | | + | |_ +LL | mod foo {} + | ------- the attribute applies to this module + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:58:1 + | +LL | / #[inline] +LL | | // Still lint cases where the empty line does not immediately follow the attribute +LL | | + | |_ +LL | fn comment_before_empty_line() {} + | ------------------------------ the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:64:1 + | +LL | / #[allow(unused)] +LL | | +LL | | // This comment is isolated +LL | | + | |_ +LL | pub fn isolated_comment() {} + | ------------------------- the attribute applies to this function + | + = help: if the empty lines are unintentional remove them + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs deleted file mode 100644 index dd78491749c77..0000000000000 --- a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs +++ /dev/null @@ -1,132 +0,0 @@ -//@aux-build:proc_macro_attr.rs -#![warn(clippy::empty_line_after_doc_comments)] -#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] -#![feature(custom_inner_attributes)] -#![rustfmt::skip] - -#[macro_use] -extern crate proc_macro_attr; - -mod some_mod { - //! This doc comment should *NOT* produce a warning - - mod some_inner_mod { - fn some_noop() {} - } -} - -/// This should produce a warning - -fn with_doc_and_newline() { assert!(true)} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -/// some comment -fn with_one_newline_and_comment() { assert!(true) } - -// This should *NOT* produce a warning -#[crate_type = "lib"] -/// some comment -fn with_no_newline_and_comment() { assert!(true) } - - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -fn with_one_newline() { assert!(true) } - -// This should *NOT* produce a warning -#[crate_type = "lib"] - - -fn with_two_newlines() { assert!(true) } - - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -enum Baz { - One, - Two -} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -struct Foo { - one: isize, - two: isize -} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -mod foo { -} - -/// This doc comment should produce a warning - -/** This is also a doc comment and should produce a warning - */ - -// This should *NOT* produce a warning -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[allow(missing_docs)] -fn three_attributes() { assert!(true) } - -// This should *NOT* produce a warning -#[doc = " -Returns the escaped value of the textual representation of - -"] -pub fn function() -> bool { - true -} - -// This should *NOT* produce a warning -#[derive(Clone, Copy)] -pub enum FooFighter { - Bar1, - - Bar2, - - Bar3, - - Bar4 -} - -// This should *NOT* produce a warning because the empty line is inside a block comment -#[crate_type = "lib"] -/* - -*/ -pub struct S; - -// This should *NOT* produce a warning -#[crate_type = "lib"] -/* test */ -pub struct T; - -// This should *NOT* produce a warning -// See https://github.com/rust-lang/rust-clippy/issues/5567 -#[fake_async_trait] -pub trait Bazz { - fn foo() -> Vec { - let _i = ""; - - - - vec![] - } -} - -#[derive(Clone, Copy)] -#[dummy(string = "first line - -second line -")] -pub struct Args; - -fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr deleted file mode 100644 index 889ccf6ba19dd..0000000000000 --- a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:18:1 - | -LL | / /// This should produce a warning -LL | | -LL | | fn with_doc_and_newline() { assert!(true)} - | |_ - | - = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` - -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:68:1 - | -LL | / /// This doc comment should produce a warning -LL | | -LL | | /** This is also a doc comment and should produce a warning -LL | | */ -... | -LL | | #[allow(missing_docs)] -LL | | fn three_attributes() { assert!(true) } - | |_ - -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:70:1 - | -LL | / /** This is also a doc comment and should produce a warning -LL | | */ -LL | | -LL | | // This should *NOT* produce a warning -... | -LL | | #[allow(missing_docs)] -LL | | fn three_attributes() { assert!(true) } - | |_ - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs deleted file mode 100644 index f147cf2cd5d1e..0000000000000 --- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs +++ /dev/null @@ -1,120 +0,0 @@ -//@aux-build:proc_macro_attr.rs -#![warn(clippy::empty_line_after_outer_attr)] -#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] -#![feature(custom_inner_attributes)] -#![rustfmt::skip] - -#[macro_use] -extern crate proc_macro_attr; - -// This should produce a warning -#[crate_type = "lib"] - -/// some comment -fn with_one_newline_and_comment() { assert!(true) } - -// This should not produce a warning -#[crate_type = "lib"] -/// some comment -fn with_no_newline_and_comment() { assert!(true) } - - -// This should produce a warning -#[crate_type = "lib"] - -fn with_one_newline() { assert!(true) } - -// This should produce a warning, too -#[crate_type = "lib"] - - -fn with_two_newlines() { assert!(true) } - - -// This should produce a warning -#[crate_type = "lib"] - -enum Baz { - One, - Two -} - -// This should produce a warning -#[crate_type = "lib"] - -struct Foo { - one: isize, - two: isize -} - -// This should produce a warning -#[crate_type = "lib"] - -mod foo { -} - -/// This doc comment should not produce a warning - -/** This is also a doc comment and should not produce a warning - */ - -// This should not produce a warning -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[allow(missing_docs)] -fn three_attributes() { assert!(true) } - -// This should not produce a warning -#[doc = " -Returns the escaped value of the textual representation of - -"] -pub fn function() -> bool { - true -} - -// This should not produce a warning -#[derive(Clone, Copy)] -pub enum FooFighter { - Bar1, - - Bar2, - - Bar3, - - Bar4 -} - -// This should not produce a warning because the empty line is inside a block comment -#[crate_type = "lib"] -/* - -*/ -pub struct S; - -// This should not produce a warning -#[crate_type = "lib"] -/* test */ -pub struct T; - -// This should not produce a warning -// See https://github.com/rust-lang/rust-clippy/issues/5567 -#[fake_async_trait] -pub trait Bazz { - fn foo() -> Vec { - let _i = ""; - - - - vec![] - } -} - -#[derive(Clone, Copy)] -#[dummy(string = "first line - -second line -")] -pub struct Args; - -fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr deleted file mode 100644 index b43e6e30da220..0000000000000 --- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr +++ /dev/null @@ -1,54 +0,0 @@ -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:11:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | /// some comment -LL | | fn with_one_newline_and_comment() { assert!(true) } - | |_ - | - = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:23:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | fn with_one_newline() { assert!(true) } - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:28:1 - | -LL | / #[crate_type = "lib"] -... | -LL | | fn with_two_newlines() { assert!(true) } - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:35:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | enum Baz { - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:43:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | struct Foo { - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:51:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | mod foo { - | |_ - -error: aborting due to 6 previous errors - diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs index 5fe32351ed450..1bb895bda75d7 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple +//@ignore-target: apple #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs index c50404c5047bb..37849179d6a0b 100644 --- a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs +++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/src/tools/clippy/tests/ui/exit1.rs b/src/tools/clippy/tests/ui/exit1.rs index a89f6dd4ca0eb..36b3c42fd9958 100644 --- a/src/tools/clippy/tests/ui/exit1.rs +++ b/src/tools/clippy/tests/ui/exit1.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn not_main() { if true { diff --git a/src/tools/clippy/tests/ui/exit2.rs b/src/tools/clippy/tests/ui/exit2.rs index d5ff93fb9ccb8..9bbb7b073a4b0 100644 --- a/src/tools/clippy/tests/ui/exit2.rs +++ b/src/tools/clippy/tests/ui/exit2.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn also_not_main() { std::process::exit(3); diff --git a/src/tools/clippy/tests/ui/exit3.rs b/src/tools/clippy/tests/ui/exit3.rs index 9dc0e1015a4f7..cab908aafd33d 100644 --- a/src/tools/clippy/tests/ui/exit3.rs +++ b/src/tools/clippy/tests/ui/exit3.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn main() { if true { diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed index 6ac3c43ad2982..8f800c71941a1 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.fixed +++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed @@ -5,8 +5,6 @@ clippy::unnecessary_literal_unwrap )] -/// Checks implementation of the `EXPECT_FUN_CALL` lint - macro_rules! one { () => { 1 diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs index 22ea2db504fa4..b5cfafb2993e5 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.rs +++ b/src/tools/clippy/tests/ui/expect_fun_call.rs @@ -5,8 +5,6 @@ clippy::unnecessary_literal_unwrap )] -/// Checks implementation of the `EXPECT_FUN_CALL` lint - macro_rules! one { () => { 1 diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr index b41904d04fa4c..bae853ac5c19a 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.stderr +++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:37:26 + --> tests/ui/expect_fun_call.rs:35:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -8,85 +8,85 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = help: to override `-D warnings` add `#[allow(clippy::expect_fun_call)]` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:40:26 + --> tests/ui/expect_fun_call.rs:38:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:43:37 + --> tests/ui/expect_fun_call.rs:41:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:53:25 + --> tests/ui/expect_fun_call.rs:51:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:56:25 + --> tests/ui/expect_fun_call.rs:54:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:68:17 + --> tests/ui/expect_fun_call.rs:66:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:89:21 + --> tests/ui/expect_fun_call.rs:87:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:90:21 + --> tests/ui/expect_fun_call.rs:88:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:91:21 + --> tests/ui/expect_fun_call.rs:89:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:93:21 + --> tests/ui/expect_fun_call.rs:91:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:94:21 + --> tests/ui/expect_fun_call.rs:92:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:98:16 + --> tests/ui/expect_fun_call.rs:96:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:104:17 + --> tests/ui/expect_fun_call.rs:102:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:108:20 + --> tests/ui/expect_fun_call.rs:106:20 | LL | format_capture.expect(&format!("{error_code}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:111:30 + --> tests/ui/expect_fun_call.rs:109:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs index 620cffb4f04da..2a432751952d0 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs @@ -192,8 +192,8 @@ struct WrapperMulti { } mod issue6312 { - use std::sync::atomic::AtomicBool; use std::sync::Arc; + use std::sync::atomic::AtomicBool; // do not lint: type implements `Drop` but not all fields are `Copy` #[derive(Clone, Default)] diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs index 47c113d61c041..8ea75fae89b65 100644 --- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs +++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs @@ -4,7 +4,7 @@ #![no_std] // The following should not lint, as the suggested methods `{f16,f32,f64,f128}.mul_add()` -// and ``{f16,f32,f64,f128}::abs()` are not available in no_std +// and `{f16,f32,f64,f128}::abs()` are not available in no_std pub fn mul_add() { let a: f64 = 1234.567; diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index 4d812f6bf1dce..20d1e3d905042 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed @@ -8,7 +8,7 @@ clippy::uninlined_format_args )] -use std::io::{stdout, Write}; +use std::io::{Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index d242623feb62a..18ab223db78a1 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs @@ -8,7 +8,7 @@ clippy::uninlined_format_args )] -use std::io::{stdout, Write}; +use std::io::{Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.rs b/src/tools/clippy/tests/ui/format_args_unfixable.rs index b7492e38b256b..f04715f4f0182 100644 --- a/src/tools/clippy/tests/ui/format_args_unfixable.rs +++ b/src/tools/clippy/tests/ui/format_args_unfixable.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] -use std::io::{stdout, Error, ErrorKind, Write}; +use std::io::{Error, ErrorKind, Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed index ad13372a68b7e..1f47dddcbc40a 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed @@ -113,6 +113,10 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { Ok(()) } +fn issue13407(s: &str) -> Option { + (s == "1").then(|| true) +} + const fn issue12103(x: u32) -> Option { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs index 73edbb7da2a87..499f008fb876d 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs @@ -131,6 +131,10 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { Ok(()) } +fn issue13407(s: &str) -> Option { + if s == "1" { Some(true) } else { None } +} + const fn issue12103(x: u32) -> Option { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr index aed01e026cbe7..e7bc66b3ee881 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr @@ -52,5 +52,11 @@ LL | | None LL | | }; | |_____^ help: try: `foo().then(|| { println!("true!"); 150 })` -error: aborting due to 5 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:135:5 + | +LL | if s == "1" { Some(true) } else { None } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(s == "1").then(|| true)` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed index 118f0b4889529..fde4043730986 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed @@ -21,15 +21,12 @@ fn main() { let _ = foo().map_err(|()| todo!()); //~^ ERROR: matching over `()` is more explicit - println!( - "{:?}", - match foo() { - Ok(()) => {}, - //~^ ERROR: matching over `()` is more explicit - Err(()) => {}, - //~^ ERROR: matching over `()` is more explicit - } - ); + println!("{:?}", match foo() { + Ok(()) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(()) => {}, + //~^ ERROR: matching over `()` is more explicit + }); } // ignored_unit_patterns in derive macro should be ok diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs index 92feb9e6c2814..528844d76e051 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs @@ -21,15 +21,12 @@ fn main() { let _ = foo().map_err(|_| todo!()); //~^ ERROR: matching over `()` is more explicit - println!( - "{:?}", - match foo() { - Ok(_) => {}, - //~^ ERROR: matching over `()` is more explicit - Err(_) => {}, - //~^ ERROR: matching over `()` is more explicit - } - ); + println!("{:?}", match foo() { + Ok(_) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(_) => {}, + //~^ ERROR: matching over `()` is more explicit + }); } // ignored_unit_patterns in derive macro should be ok diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr index 00a254e39192c..54ff4454d6bdf 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr @@ -26,31 +26,31 @@ LL | let _ = foo().map_err(|_| todo!()); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:27:16 + --> tests/ui/ignored_unit_patterns.rs:25:12 | -LL | Ok(_) => {}, - | ^ help: use `()` instead of `_`: `()` +LL | Ok(_) => {}, + | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:29:17 + --> tests/ui/ignored_unit_patterns.rs:27:13 | -LL | Err(_) => {}, - | ^ help: use `()` instead of `_`: `()` +LL | Err(_) => {}, + | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:41:9 + --> tests/ui/ignored_unit_patterns.rs:38:9 | LL | let _ = foo().unwrap(); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:50:13 + --> tests/ui/ignored_unit_patterns.rs:47:13 | LL | (1, _) => unimplemented!(), | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:57:13 + --> tests/ui/ignored_unit_patterns.rs:54:13 | LL | for (x, _) in v { | ^ help: use `()` instead of `_`: `()` diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed index 27f679797dd9e..81cc149491442 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed @@ -184,18 +184,18 @@ fn main() { let mut m = Mock; let mut u_32 = 3000; let a = 200; - let mut _b = 8; + let mut b = 8; if m != 0 { m -= 1; } if a > 0 { - _b -= 1; + b -= 1; } if 0 > a { - _b -= 1; + b -= 1; } if u_32 > 0 { @@ -214,4 +214,11 @@ fn main() { } else if u_32 > 0 { u_32 -= 1; } + + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; } diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs index 5d7b95d2c652f..f73396ebd27e2 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs @@ -230,18 +230,18 @@ fn main() { let mut m = Mock; let mut u_32 = 3000; let a = 200; - let mut _b = 8; + let mut b = 8; if m != 0 { m -= 1; } if a > 0 { - _b -= 1; + b -= 1; } if 0 > a { - _b -= 1; + b -= 1; } if u_32 > 0 { @@ -260,4 +260,11 @@ fn main() { } else if u_32 > 0 { u_32 -= 1; } + + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; } diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs index 8ef1f554bc35d..c23df223d5088 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.rs +++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs @@ -2,8 +2,8 @@ #![feature(custom_inner_attributes)] #![clippy::msrv = "1.3.0"] -use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::collections::hash_map::Entry; use std::future::Future; use std::thread::sleep; use std::time::Duration; diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed index a6ef8f8c119a5..3a2294ef4c59b 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed @@ -22,8 +22,8 @@ macro_rules! b { }; } -use std::u32::MAX; use std::u8::MIN; +use std::u32::MAX; use std::{f64, u32}; #[warn(clippy::legacy_numeric_constants)] @@ -99,8 +99,8 @@ fn allow() { ::std::primitive::u8::MIN; ::std::u8::MIN; ::std::primitive::u8::min_value(); - use std::u64; use std::u8::MIN; + use std::u64; } #[warn(clippy::legacy_numeric_constants)] diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs index cd633545372cd..6cb3e694ea145 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs @@ -22,8 +22,8 @@ macro_rules! b { }; } -use std::u32::MAX; use std::u8::MIN; +use std::u32::MAX; use std::{f64, u32}; #[warn(clippy::legacy_numeric_constants)] @@ -99,8 +99,8 @@ fn allow() { ::std::primitive::u8::MIN; ::std::u8::MIN; ::std::primitive::u8::min_value(); - use std::u64; use std::u8::MIN; + use std::u64; } #[warn(clippy::legacy_numeric_constants)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 38ed5a957e73e..28844fab74793 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -2,7 +2,7 @@ //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index ae6cc16ed2769..5381f29598987 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -2,7 +2,7 @@ //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs index df6d5b9fbabf2..60cce1d24a289 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs @@ -1,7 +1,7 @@ //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs new file mode 100644 index 0000000000000..e97e3bdfef769 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs @@ -0,0 +1,35 @@ +//@no-rustfix +#![warn(clippy::implicit_saturating_sub)] +#![allow(arithmetic_overflow)] + +fn main() { + let a = 12u32; + let b = 13u32; + + let result = if a > b { b - a } else { 0 }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b < a { b - a } else { 0 }; + //~^ ERROR: inverted arithmetic check before subtraction + + let result = if a > b { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if a >= b { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b < a { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b <= a { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + + let af = 12f32; + let bf = 13f32; + // Should not lint! + let result = if bf < af { 0. } else { af - bf }; + + // Should not lint! + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; +} diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr new file mode 100644 index 0000000000000..4121aa7464f05 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr @@ -0,0 +1,75 @@ +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:9:23 + | +LL | let result = if a > b { b - a } else { 0 }; + | ^ ----- help: try replacing it with: `a - b` + | +note: this subtraction underflows when `b < a` + --> tests/ui/manual_arithmetic_check-2.rs:9:29 + | +LL | let result = if a > b { b - a } else { 0 }; + | ^^^^^ + = note: `#[deny(clippy::inverted_saturating_sub)]` on by default + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:11:23 + | +LL | let result = if b < a { b - a } else { 0 }; + | ^ ----- help: try replacing it with: `a - b` + | +note: this subtraction underflows when `b < a` + --> tests/ui/manual_arithmetic_check-2.rs:11:29 + | +LL | let result = if b < a { b - a } else { 0 }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:14:23 + | +LL | let result = if a > b { 0 } else { a - b }; + | ^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:14:40 + | +LL | let result = if a > b { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:16:23 + | +LL | let result = if a >= b { 0 } else { a - b }; + | ^^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:16:41 + | +LL | let result = if a >= b { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:18:23 + | +LL | let result = if b < a { 0 } else { a - b }; + | ^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:18:40 + | +LL | let result = if b < a { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:20:23 + | +LL | let result = if b <= a { 0 } else { a - b }; + | ^^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:20:41 + | +LL | let result = if b <= a { 0 } else { a - b }; + | ^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed b/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed new file mode 100644 index 0000000000000..29ecbb9ad2adb --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed @@ -0,0 +1,24 @@ +#![warn(clippy::implicit_saturating_sub, clippy::inverted_saturating_sub)] +#![allow(clippy::if_same_then_else)] + +fn main() { + let a = 12u32; + let b = 13u32; + let c = 8u32; + + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + + // Should not warn! + let result = if a > b { a - b } else { a - c }; + + // Just to check it won't break clippy. + let result = if b > a { 0 } else { 0 }; +} diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check.rs b/src/tools/clippy/tests/ui/manual_arithmetic_check.rs new file mode 100644 index 0000000000000..69554c6b61caa --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check.rs @@ -0,0 +1,24 @@ +#![warn(clippy::implicit_saturating_sub, clippy::inverted_saturating_sub)] +#![allow(clippy::if_same_then_else)] + +fn main() { + let a = 12u32; + let b = 13u32; + let c = 8u32; + + let result = if a > b { a - b } else { 0 }; + //~^ ERROR: manual arithmetic check found + let result = if b < a { a - b } else { 0 }; + //~^ ERROR: manual arithmetic check found + + let result = if a < b { 0 } else { a - b }; + //~^ ERROR: manual arithmetic check found + let result = if b > a { 0 } else { a - b }; + //~^ ERROR: manual arithmetic check found + + // Should not warn! + let result = if a > b { a - b } else { a - c }; + + // Just to check it won't break clippy. + let result = if b > a { 0 } else { 0 }; +} diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr b/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr new file mode 100644 index 0000000000000..b0cf73cd9151d --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr @@ -0,0 +1,29 @@ +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:9:18 + | +LL | let result = if a > b { a - b } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + | + = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:11:18 + | +LL | let result = if b < a { a - b } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:14:18 + | +LL | let result = if a < b { 0 } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:16:18 + | +LL | let result = if b > a { 0 } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed new file mode 100644 index 0000000000000..e7801f7376aaf --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed @@ -0,0 +1,30 @@ +#![warn(clippy::manual_div_ceil)] + +fn main() { + let x = 7_u32; + let y = 4_u32; + let z = 11_u32; + + // Lint + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + + let _ = 7_u32.div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + let _ = (7_i32 as u32).div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + + // No lint + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; + + let x_i = 7_i32; + let y_i = 4_i32; + let z_i = 11_i32; + + // No lint because `int_roundings` feature is not enabled. + let _ = (z as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (4 - 1)) / 4; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs new file mode 100644 index 0000000000000..2de74c7eaa881 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs @@ -0,0 +1,30 @@ +#![warn(clippy::manual_div_ceil)] + +fn main() { + let x = 7_u32; + let y = 4_u32; + let z = 11_u32; + + // Lint + let _ = (x + (y - 1)) / y; //~ ERROR: manually reimplementing `div_ceil` + let _ = ((y - 1) + x) / y; //~ ERROR: manually reimplementing `div_ceil` + let _ = (x + y - 1) / y; //~ ERROR: manually reimplementing `div_ceil` + + let _ = (7_u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + let _ = (7_i32 as u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + + // No lint + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; + + let x_i = 7_i32; + let y_i = 4_i32; + let z_i = 11_i32; + + // No lint because `int_roundings` feature is not enabled. + let _ = (z as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (4 - 1)) / 4; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr new file mode 100644 index 0000000000000..dc652dff405f2 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr @@ -0,0 +1,35 @@ +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:9:13 + | +LL | let _ = (x + (y - 1)) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + | + = note: `-D clippy::manual-div-ceil` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:10:13 + | +LL | let _ = ((y - 1) + x) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:11:13 + | +LL | let _ = (x + y - 1) / y; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:13:13 + | +LL | let _ = (7_u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:14:13 + | +LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed new file mode 100644 index 0000000000000..a1d678c66898c --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed @@ -0,0 +1,25 @@ +#![warn(clippy::manual_div_ceil)] +#![feature(int_roundings)] + +fn main() { + let x = 7_i32; + let y = 4_i32; + let z = 3_i32; + let z_u: u32 = 11; + + // Lint. + let _ = x.div_ceil(y); + let _ = x.div_ceil(y); + let _ = x.div_ceil(y); + + let _ = 7_i32.div_ceil(4); + let _ = (7_i32 as u32).div_ceil(4); + let _ = (7_u32 as i32).div_ceil(4); + let _ = z_u.div_ceil(4); + + // No lint. + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs new file mode 100644 index 0000000000000..58cb1dbe34d1c --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs @@ -0,0 +1,25 @@ +#![warn(clippy::manual_div_ceil)] +#![feature(int_roundings)] + +fn main() { + let x = 7_i32; + let y = 4_i32; + let z = 3_i32; + let z_u: u32 = 11; + + // Lint. + let _ = (x + (y - 1)) / y; + let _ = ((y - 1) + x) / y; + let _ = (x + y - 1) / y; + + let _ = (7_i32 + (4 - 1)) / 4; + let _ = (7_i32 as u32 + (4 - 1)) / 4; + let _ = (7_u32 as i32 + (4 - 1)) / 4; + let _ = (z_u + (4 - 1)) / 4; + + // No lint. + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr new file mode 100644 index 0000000000000..361ef9bd9f42a --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr @@ -0,0 +1,47 @@ +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:11:13 + | +LL | let _ = (x + (y - 1)) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + | + = note: `-D clippy::manual-div-ceil` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:12:13 + | +LL | let _ = ((y - 1) + x) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:13:13 + | +LL | let _ = (x + y - 1) / y; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:15:13 + | +LL | let _ = (7_i32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_i32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:16:13 + | +LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:17:13 + | +LL | let _ = (7_u32 as i32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_u32 as i32).div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:18:13 + | +LL | let _ = (z_u + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)` + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed b/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed new file mode 100644 index 0000000000000..dda5fe0ec3e77 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed @@ -0,0 +1,20 @@ +#![warn(clippy::manual_is_power_of_two)] + +fn main() { + let a = 16_u64; + + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + + // Test different orders of expression + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + + let b = 4_i64; + + // is_power_of_two only works for unsigned integers + let _ = b.count_ones() == 1; + let _ = b & (b - 1) == 0; +} diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.rs b/src/tools/clippy/tests/ui/manual_is_power_of_two.rs new file mode 100644 index 0000000000000..a1d3a95c4102b --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.rs @@ -0,0 +1,20 @@ +#![warn(clippy::manual_is_power_of_two)] + +fn main() { + let a = 16_u64; + + let _ = a.count_ones() == 1; + let _ = a & (a - 1) == 0; + + // Test different orders of expression + let _ = 1 == a.count_ones(); + let _ = (a - 1) & a == 0; + let _ = 0 == a & (a - 1); + let _ = 0 == (a - 1) & a; + + let b = 4_i64; + + // is_power_of_two only works for unsigned integers + let _ = b.count_ones() == 1; + let _ = b & (b - 1) == 0; +} diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr b/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr new file mode 100644 index 0000000000000..3cfc6297abf27 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr @@ -0,0 +1,41 @@ +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:6:13 + | +LL | let _ = a.count_ones() == 1; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + | + = note: `-D clippy::manual-is-power-of-two` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:7:13 + | +LL | let _ = a & (a - 1) == 0; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:10:13 + | +LL | let _ = 1 == a.count_ones(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:11:13 + | +LL | let _ = (a - 1) & a == 0; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:12:13 + | +LL | let _ = 0 == a & (a - 1); + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:13:13 + | +LL | let _ = 0 == (a - 1) & a; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs index 31c3cc8013722..ffe2bb9246737 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs @@ -1,8 +1,8 @@ #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix -enum E { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub enum E { + //~^ manual_non_exhaustive A, B, #[doc(hidden)] @@ -11,7 +11,7 @@ enum E { // if the user explicitly marks as nonexhaustive we shouldn't warn them #[non_exhaustive] -enum Ep { +pub enum Ep { A, B, #[doc(hidden)] @@ -19,14 +19,14 @@ enum Ep { } // marker variant does not have doc hidden attribute, should be ignored -enum NoDocHidden { +pub enum NoDocHidden { A, B, _C, } // name of variant with doc hidden does not start with underscore -enum NoUnderscore { +pub enum NoUnderscore { A, B, #[doc(hidden)] @@ -34,7 +34,7 @@ enum NoUnderscore { } // variant with doc hidden is not unit, should be ignored -enum NotUnit { +pub enum NotUnit { A, B, #[doc(hidden)] @@ -42,13 +42,13 @@ enum NotUnit { } // variant with doc hidden is the only one, should be ignored -enum OnlyMarker { +pub enum OnlyMarker { #[doc(hidden)] _A, } // variant with multiple markers, should be ignored -enum MultipleMarkers { +pub enum MultipleMarkers { A, #[doc(hidden)] _B, @@ -58,13 +58,13 @@ enum MultipleMarkers { // already non_exhaustive and no markers, should be ignored #[non_exhaustive] -enum NonExhaustive { +pub enum NonExhaustive { A, B, } // marked is used, don't lint -enum UsedHidden { +pub enum UsedHidden { #[doc(hidden)] _A, B, @@ -77,11 +77,9 @@ fn foo(x: &mut UsedHidden) { } #[expect(clippy::manual_non_exhaustive)] -enum ExpectLint { +pub enum ExpectLint { A, B, #[doc(hidden)] _C, } - -fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr index dc669568dd2d4..0a9ac157f8502 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr @@ -1,11 +1,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:4:1 | -LL | enum E { - | ^----- - | | - | _help: add the attribute: `#[non_exhaustive] enum E` - | | +LL | / pub enum E { LL | | LL | | A, LL | | B, @@ -21,15 +17,16 @@ LL | _C, | ^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` +help: use the `#[non_exhaustive]` attribute instead + | +LL + #[non_exhaustive] +LL | pub enum E { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:29:1 | -LL | enum NoUnderscore { - | ^---------------- - | | - | _help: add the attribute: `#[non_exhaustive] enum NoUnderscore` - | | +LL | / pub enum NoUnderscore { LL | | A, LL | | B, LL | | #[doc(hidden)] @@ -42,6 +39,11 @@ help: remove this variant | LL | C, | ^ +help: use the `#[non_exhaustive]` attribute instead + | +LL + #[non_exhaustive] +LL | pub enum NoUnderscore { + | error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.rs index 4b2803ccc4a79..31dd50281fa1d 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.rs +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.rs @@ -1,9 +1,9 @@ #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix -mod structs { - struct S { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub mod structs { + pub struct S { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, _c: (), @@ -11,68 +11,76 @@ mod structs { // user forgot to remove the private field #[non_exhaustive] - struct Sp { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern + pub struct Sp { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, _c: (), } // some other fields are private, should be ignored - struct PrivateFields { + pub struct PrivateFields { a: i32, pub b: i32, _c: (), } - // private field name does not start with underscore, should be ignored - struct NoUnderscore { + pub struct NoUnderscore { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, c: (), } // private field is not unit type, should be ignored - struct NotUnit { + pub struct NotUnit { pub a: i32, pub b: i32, _c: i32, } // private field is the only field, should be ignored - struct OnlyMarker { + pub struct OnlyMarker { _a: (), } // already non exhaustive and no private fields, should be ignored #[non_exhaustive] - struct NonExhaustive { + pub struct NonExhaustive { pub a: i32, pub b: i32, } } -mod tuple_structs { - struct T(pub i32, pub i32, ()); - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub mod tuple_structs { + pub struct T(pub i32, pub i32, ()); + //~^ manual_non_exhaustive // user forgot to remove the private field #[non_exhaustive] - struct Tp(pub i32, pub i32, ()); - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern + pub struct Tp(pub i32, pub i32, ()); + //~^ manual_non_exhaustive // some other fields are private, should be ignored - struct PrivateFields(pub i32, i32, ()); + pub struct PrivateFields(pub i32, i32, ()); // private field is not unit type, should be ignored - struct NotUnit(pub i32, pub i32, i32); + pub struct NotUnit(pub i32, pub i32, i32); // private field is the only field, should be ignored - struct OnlyMarker(()); + pub struct OnlyMarker(()); // already non exhaustive and no private fields, should be ignored #[non_exhaustive] - struct NonExhaustive(pub i32, pub i32); + pub struct NonExhaustive(pub i32, pub i32); } -fn main() {} +mod private { + // Don't lint structs that are not actually public as `#[non_exhaustive]` only applies to + // external crates. The manual pattern can still be used to get module local non exhaustiveness + pub struct NotPublic { + pub a: i32, + pub b: i32, + _c: (), + } +} diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr index 1cab812988a34..81de1e4f27190 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr @@ -1,11 +1,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:5:5 | -LL | struct S { - | ^------- - | | - | _____help: add the attribute: `#[non_exhaustive] struct S` - | | +LL | / pub struct S { LL | | LL | | pub a: i32, LL | | pub b: i32, @@ -20,11 +16,16 @@ LL | _c: (), | ^^^^^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct S { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:14:5 | -LL | / struct Sp { +LL | / pub struct Sp { LL | | LL | | pub a: i32, LL | | pub b: i32, @@ -32,6 +33,11 @@ LL | | _c: (), LL | | } | |_____^ | +note: the struct is already non-exhaustive + --> tests/ui/manual_non_exhaustive_struct.rs:13:5 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this field --> tests/ui/manual_non_exhaustive_struct.rs:18:9 | @@ -39,13 +45,10 @@ LL | _c: (), | ^^^^^^ error: this seems like a manual implementation of the non-exhaustive pattern - --> tests/ui/manual_non_exhaustive_struct.rs:29:5 + --> tests/ui/manual_non_exhaustive_struct.rs:28:5 | -LL | struct NoUnderscore { - | ^------------------ - | | - | _____help: add the attribute: `#[non_exhaustive] struct NoUnderscore` - | | +LL | / pub struct NoUnderscore { +LL | | LL | | pub a: i32, LL | | pub b: i32, LL | | c: (), @@ -57,32 +60,45 @@ help: remove this field | LL | c: (), | ^^^^^ +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct NoUnderscore { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:56:5 | -LL | struct T(pub i32, pub i32, ()); - | --------^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: add the attribute: `#[non_exhaustive] struct T` +LL | pub struct T(pub i32, pub i32, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove this field - --> tests/ui/manual_non_exhaustive_struct.rs:56:32 + --> tests/ui/manual_non_exhaustive_struct.rs:56:36 + | +LL | pub struct T(pub i32, pub i32, ()); + | ^^ +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct T(pub i32, pub i32, ()); | -LL | struct T(pub i32, pub i32, ()); - | ^^ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:61:5 | -LL | struct Tp(pub i32, pub i32, ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct Tp(pub i32, pub i32, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the struct is already non-exhaustive + --> tests/ui/manual_non_exhaustive_struct.rs:60:5 | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this field - --> tests/ui/manual_non_exhaustive_struct.rs:61:33 + --> tests/ui/manual_non_exhaustive_struct.rs:61:37 | -LL | struct Tp(pub i32, pub i32, ()); - | ^^ +LL | pub struct Tp(pub i32, pub i32, ()); + | ^^ error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.fixed b/src/tools/clippy/tests/ui/manual_range_patterns.fixed index f1b99637afdba..60467bf9e8848 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.fixed +++ b/src/tools/clippy/tests/ui/manual_range_patterns.fixed @@ -45,4 +45,12 @@ fn main() { }; } mac!(f); + + #[rustfmt::skip] + let _ = match f { + | 2..=15 => 4, + | 241..=254 => 5, + | 255 => 6, + | _ => 7, + }; } diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.rs b/src/tools/clippy/tests/ui/manual_range_patterns.rs index 869ffbe80b973..9cd803334499d 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.rs +++ b/src/tools/clippy/tests/ui/manual_range_patterns.rs @@ -45,4 +45,12 @@ fn main() { }; } mac!(f); + + #[rustfmt::skip] + let _ = match f { + | 2..=15 => 4, + | 241..=254 => 5, + | 255 => 6, + | _ => 7, + }; } diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed index 41a32df32ee40..528a65790c4c8 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed @@ -1,6 +1,6 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i128, i32, u128, u32}; +use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.saturating_add(1); diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs index 3a6b32d806904..55f3720dfcc06 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs @@ -1,6 +1,6 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i128, i32, u128, u32}; +use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs index 4457ae73da2f0..a056fdeaa5d0c 100644 --- a/src/tools/clippy/tests/ui/match_overlapping_arm.rs +++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs @@ -2,8 +2,6 @@ #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_if)] -/// Tests for match_overlapping_arm - fn overlapping() { const FOO: u64 = 2; diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr index 65092ffbb5558..a60a09a079907 100644 --- a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr +++ b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr @@ -1,11 +1,11 @@ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:11:9 + --> tests/ui/match_overlapping_arm.rs:9:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:13:9 + --> tests/ui/match_overlapping_arm.rs:11:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ @@ -13,85 +13,85 @@ LL | 0..=11 => println!("0..=11"), = help: to override `-D warnings` add `#[allow(clippy::match_overlapping_arm)]` error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:18:9 + --> tests/ui/match_overlapping_arm.rs:16:9 | LL | 0..=5 => println!("0..=5"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:21:9 + --> tests/ui/match_overlapping_arm.rs:19:9 | LL | FOO..=11 => println!("FOO..=11"), | ^^^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:56:9 + --> tests/ui/match_overlapping_arm.rs:54:9 | LL | 0..11 => println!("0..11"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:58:9 + --> tests/ui/match_overlapping_arm.rs:56:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:82:9 + --> tests/ui/match_overlapping_arm.rs:80:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:81:9 + --> tests/ui/match_overlapping_arm.rs:79:9 | LL | 5..14 => println!("5..14"), | ^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:88:9 + --> tests/ui/match_overlapping_arm.rs:86:9 | LL | 0..7 => println!("0..7"), | ^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:90:9 + --> tests/ui/match_overlapping_arm.rs:88:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:101:9 + --> tests/ui/match_overlapping_arm.rs:99:9 | LL | ..=23 => println!("..=23"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:103:9 + --> tests/ui/match_overlapping_arm.rs:101:9 | LL | ..26 => println!("..26"), | ^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:111:9 + --> tests/ui/match_overlapping_arm.rs:109:9 | LL | 21..=30 => (), | ^^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:113:9 + --> tests/ui/match_overlapping_arm.rs:111:9 | LL | 21..=40 => (), | ^^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:126:9 + --> tests/ui/match_overlapping_arm.rs:124:9 | LL | 0..=0x0000_0000_0000_00ff => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:128:9 + --> tests/ui/match_overlapping_arm.rs:126:9 | LL | 0..=0x0000_0000_0000_ffff => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.rs b/src/tools/clippy/tests/ui/mixed_attributes_style.rs index 1a646c2652236..93ab9392cf8bd 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style.rs +++ b/src/tools/clippy/tests/ui/mixed_attributes_style.rs @@ -82,7 +82,8 @@ mod issue_12530 { #![allow(dead_code)] } } - /// Nested mod //~ ERROR: item has both inner and outer attributes + /// Nested mod + //~^ ERROR: item has both inner and outer attributes #[allow(unused)] mod nest_mod_2 { #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr index a1d3fc430f6cf..abdc2df23cf12 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr +++ b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr @@ -46,13 +46,14 @@ error: item has both inner and outer attributes --> tests/ui/mixed_attributes_style.rs:85:5 | LL | / /// Nested mod +LL | | LL | | #[allow(unused)] LL | | mod nest_mod_2 { LL | | #![allow(unused)] | |_________________________^ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:90:9 + --> tests/ui/mixed_attributes_style.rs:91:9 | LL | / #[allow(dead_code)] LL | | mod inner_mod { diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index adb266ffbc8dd..2459af6068845 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -7,8 +7,8 @@ )] #![warn(clippy::must_use_candidate)] use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs index 49bb16af788f1..5f9b2449552a9 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.rs +++ b/src/tools/clippy/tests/ui/must_use_candidates.rs @@ -7,8 +7,8 @@ )] #![warn(clippy::must_use_candidate)] use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; diff --git a/src/tools/clippy/tests/ui/mut_key.rs b/src/tools/clippy/tests/ui/mut_key.rs index 81d8732b3b210..43ff705c47750 100644 --- a/src/tools/clippy/tests/ui/mut_key.rs +++ b/src/tools/clippy/tests/ui/mut_key.rs @@ -2,9 +2,9 @@ use std::cell::Cell; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::rc::Rc; +use std::sync::Arc; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::Relaxed; -use std::sync::Arc; struct Key(AtomicUsize); diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.rs b/src/tools/clippy/tests/ui/needless_pass_by_value.rs index 14cba5a7eb520..9408b8c948fed 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_value.rs @@ -84,7 +84,7 @@ trait Serialize {} impl<'a, T> Serialize for &'a T where T: Serialize {} impl Serialize for i32 {} -fn test_blanket_ref(_foo: T, _serializable: S) {} +fn test_blanket_ref(vals: T, serializable: S) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body fn issue_2114(s: String, t: String, u: Vec, v: Vec) { @@ -116,7 +116,7 @@ impl S { ) { } - fn baz(&self, _u: U, _s: Self) {} + fn baz(&self, uu: U, ss: Self) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body //~| ERROR: this argument is passed by value, but not consumed in the function body } @@ -162,13 +162,13 @@ fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { // The following 3 lines should not cause an ICE. See #2831 trait Bar<'a, A> {} impl<'b, T> Bar<'b, T> for T {} -fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body // Also this should not cause an ICE. See #2831 trait Club<'a, A> {} impl Club<'static, T> for T {} -fn more_fun(_item: impl Club<'static, i32>) {} +fn more_fun(items: impl Club<'static, i32>) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body fn is_sync(_: T) @@ -177,6 +177,10 @@ where { } +struct Obj(String); + +fn prefix_test(_unused_with_prefix: Obj) {} + fn main() { // This should not cause an ICE either // https://github.com/rust-lang/rust-clippy/issues/3144 diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr index 827a200ba6819..46ef8f3e8da43 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr @@ -46,7 +46,7 @@ LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:87:49 | -LL | fn test_blanket_ref(_foo: T, _serializable: S) {} +LL | fn test_blanket_ref(vals: T, serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body @@ -106,13 +106,13 @@ LL | t: String, error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:119:23 | -LL | fn baz(&self, _u: U, _s: Self) {} +LL | fn baz(&self, uu: U, ss: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:119:30 | -LL | fn baz(&self, _u: U, _s: Self) {} +LL | fn baz(&self, uu: U, ss: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body @@ -121,7 +121,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -133,7 +133,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -145,7 +145,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -157,7 +157,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -166,13 +166,13 @@ LL | struct CopyWrapper(u32); error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:165:40 | -LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +LL | fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:171:20 | -LL | fn more_fun(_item: impl Club<'static, i32>) {} +LL | fn more_fun(items: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index fc4129e1db84f..c5c570690b450 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -355,4 +355,8 @@ fn conjunctive_blocks() -> String { ({ "a".to_string() } + "b" + { "c" }) } +fn issue12907() -> String { + "".split("").next().unwrap().to_string() +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index 61c7a02008f08..738611391dfdf 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -365,4 +365,8 @@ fn conjunctive_blocks() -> String { return { "a".to_string() } + "b" + { "c" }; } +fn issue12907() -> String { + return "".split("").next().unwrap().to_string(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index ea9c230eafd22..da0fa220d8c4a 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -665,5 +665,17 @@ LL - return { "a".to_string() } + "b" + { "c" }; LL + ({ "a".to_string() } + "b" + { "c" }) | -error: aborting due to 53 previous errors +error: unneeded `return` statement + --> tests/ui/needless_return.rs:369:5 + | +LL | return "".split("").next().unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove `return` + | +LL - return "".split("").next().unwrap().to_string(); +LL + "".split("").next().unwrap().to_string() + | + +error: aborting due to 54 previous errors diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed index 237f5f5b97a4f..f68d5e30d27e7 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed @@ -1,4 +1,4 @@ -//@ignore-target-windows +//@ignore-target: windows #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs index c8da5dbcec282..647c3769d2c3f 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows +//@ignore-target: windows #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions.fixed b/src/tools/clippy/tests/ui/non_zero_suggestions.fixed new file mode 100644 index 0000000000000..e67c992fdde01 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_zero_suggestions.fixed @@ -0,0 +1,65 @@ +#![warn(clippy::non_zero_suggestions)] +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; + +fn main() { + /// Positive test cases (lint should trigger) + // U32 -> U64 + let x: u64 = 100; + let y = NonZeroU32::new(10).unwrap(); + let r1 = x / NonZeroU64::from(y); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let r2 = x % NonZeroU64::from(y); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + // U16 -> U32 + let a: u32 = 50; + let b = NonZeroU16::new(5).unwrap(); + let r3 = a / NonZeroU32::from(b); + //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + + let x = NonZeroU64::from(NonZeroU32::new(5).unwrap()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + /// Negative test cases (lint should not trigger) + // Left hand side expressions should not be triggered + let c: u32 = 50; + let d = NonZeroU16::new(5).unwrap(); + let r4 = u32::from(b.get()) / a; + + // Should not trigger for any other operand other than `/` and `%` + let r5 = a + u32::from(b.get()); + let r6 = a - u32::from(b.get()); + + // Same size types + let e: u32 = 200; + let f = NonZeroU32::new(20).unwrap(); + let r7 = e / f.get(); + + // Smaller to larger, but not NonZero + let g: u64 = 1000; + let h: u32 = 50; + let r8 = g / u64::from(h); + + // Using From correctly + let k: u64 = 300; + let l = NonZeroU32::new(15).unwrap(); + let r9 = k / NonZeroU64::from(l); +} + +// Additional function to test the lint in a different context +fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { + x / NonZeroU64::from(y) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +struct Calculator { + value: u64, +} + +impl Calculator { + fn divide(&self, divisor: NonZeroU32) -> u64 { + self.value / NonZeroU64::from(divisor) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + } +} diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions.rs b/src/tools/clippy/tests/ui/non_zero_suggestions.rs new file mode 100644 index 0000000000000..de82371a8f294 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_zero_suggestions.rs @@ -0,0 +1,65 @@ +#![warn(clippy::non_zero_suggestions)] +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; + +fn main() { + /// Positive test cases (lint should trigger) + // U32 -> U64 + let x: u64 = 100; + let y = NonZeroU32::new(10).unwrap(); + let r1 = x / u64::from(y.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let r2 = x % u64::from(y.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + // U16 -> U32 + let a: u32 = 50; + let b = NonZeroU16::new(5).unwrap(); + let r3 = a / u32::from(b.get()); + //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + + let x = u64::from(NonZeroU32::new(5).unwrap().get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + /// Negative test cases (lint should not trigger) + // Left hand side expressions should not be triggered + let c: u32 = 50; + let d = NonZeroU16::new(5).unwrap(); + let r4 = u32::from(b.get()) / a; + + // Should not trigger for any other operand other than `/` and `%` + let r5 = a + u32::from(b.get()); + let r6 = a - u32::from(b.get()); + + // Same size types + let e: u32 = 200; + let f = NonZeroU32::new(20).unwrap(); + let r7 = e / f.get(); + + // Smaller to larger, but not NonZero + let g: u64 = 1000; + let h: u32 = 50; + let r8 = g / u64::from(h); + + // Using From correctly + let k: u64 = 300; + let l = NonZeroU32::new(15).unwrap(); + let r9 = k / NonZeroU64::from(l); +} + +// Additional function to test the lint in a different context +fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { + x / u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +struct Calculator { + value: u64, +} + +impl Calculator { + fn divide(&self, divisor: NonZeroU32) -> u64 { + self.value / u64::from(divisor.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + } +} diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions.stderr b/src/tools/clippy/tests/ui/non_zero_suggestions.stderr new file mode 100644 index 0000000000000..7a57f7983be74 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_zero_suggestions.stderr @@ -0,0 +1,41 @@ +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:9:18 + | +LL | let r1 = x / u64::from(y.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + | + = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:12:18 + | +LL | let r2 = x % u64::from(y.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:18:18 + | +LL | let r3 = a / u32::from(b.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU32::from(b)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:21:13 + | +LL | let x = u64::from(NonZeroU32::new(5).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(5).unwrap())` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:52:9 + | +LL | x / u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:62:22 + | +LL | self.value / u64::from(divisor.get()) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(divisor)` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs new file mode 100644 index 0000000000000..193c710e589ff --- /dev/null +++ b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs @@ -0,0 +1,23 @@ +#![warn(clippy::non_zero_suggestions)] +//@no-rustfix +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; + +fn main() { + let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let n = NonZeroU32::new(20).unwrap(); + let y = u64::from(n.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + some_fn_that_only_takes_u64(y); + + let m = NonZeroU32::try_from(1).unwrap(); + let _z: NonZeroU64 = m.into(); +} + +fn return_non_zero(x: u64, y: NonZeroU32) -> u64 { + u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +fn some_fn_that_only_takes_u64(_: u64) {} diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr new file mode 100644 index 0000000000000..787179f2a2d64 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr @@ -0,0 +1,23 @@ +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:6:18 + | +LL | let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(5).unwrap())` + | + = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:10:13 + | +LL | let y = u64::from(n.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:19:5 + | +LL | u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.rs b/src/tools/clippy/tests/ui/panic_in_result_fn.rs index aaaf9a109acbb..e2375aa996f7d 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.rs @@ -71,6 +71,15 @@ fn function_result_with_custom_todo() -> Result // should not emit Ok(true) } +fn issue_13381() -> Result<(), String> { + const { + if N == 0 { + panic!(); + } + } + Ok(()) +} + fn main() -> Result<(), String> { todo!("finish main method"); Ok(()) diff --git a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs new file mode 100644 index 0000000000000..b5abcbb3474c2 --- /dev/null +++ b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs @@ -0,0 +1,33 @@ +//@ needs-asm-support +#![warn(clippy::pointers_in_nomem_asm_block)] +#![crate_type = "lib"] +#![no_std] + +use core::arch::asm; + +unsafe fn nomem_bad(p: &i32) { + asm!( + "asdf {p1}, {p2}, {p3}", + p1 = in(reg) p, + //~^ ERROR: passing pointers to nomem asm block + p2 = in(reg) p as *const _ as usize, + p3 = in(reg) p, + options(nomem, nostack, preserves_flags) + ); +} + +unsafe fn nomem_good(p: &i32) { + asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags)); + let p = p as *const i32 as usize; + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); +} + +unsafe fn nomem_bad2(p: &mut i32) { + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + //~^ ERROR: passing pointers to nomem asm block +} + +unsafe fn nomem_fn(p: extern "C" fn()) { + asm!("call {p}", p = in(reg) p, options(nomem)); + //~^ ERROR: passing pointers to nomem asm block +} diff --git a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr new file mode 100644 index 0000000000000..cabeb37344f2b --- /dev/null +++ b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr @@ -0,0 +1,34 @@ +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:11:9 + | +LL | p1 = in(reg) p, + | ^^^^^^^^^^^^^^ +... +LL | p3 = in(reg) p, + | ^^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + = note: `-D clippy::pointers-in-nomem-asm-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pointers_in_nomem_asm_block)]` + +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:26:22 + | +LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + | ^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:31:22 + | +LL | asm!("call {p}", p = in(reg) p, options(nomem)); + | ^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index e6ef626812128..e8b42d3b913b0 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -309,3 +309,25 @@ mod issue_11181 { extern "C" fn allowed(_v: &Vec) {} } } + +mod issue_13308 { + use std::ops::Deref; + + fn repro(source: &str, destination: &mut String) { + source.clone_into(destination); + } + fn repro2(source: &str, destination: &mut String) { + ToOwned::clone_into(source, destination); + } + + fn h1(_: &::Target) {} + fn h2(_: T, _: &T::Target) {} + + // Other cases that are still ok to lint and ideally shouldn't regress + fn good(v1: &String, v2: &String) { + //~^ ERROR: writing `&String` instead of `&str` + //~^^ ERROR: writing `&String` instead of `&str` + h1(v1); + h2(String::new(), v2); + } +} diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 4246453e64ca7..1a6b3aa1f8d41 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -221,5 +221,17 @@ error: using a reference to `Cow` is not recommended LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` -error: aborting due to 25 previous errors +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:327:17 + | +LL | fn good(v1: &String, v2: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:327:30 + | +LL | fn good(v1: &String, v2: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed index 21ac42196e1bb..9a5272c7adc36 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed @@ -68,3 +68,20 @@ fn _msrv_1_65() { let _ = ptr.cast_mut(); let _ = mut_ptr.cast_const(); } + +#[inline_macros] +fn null_pointers() { + use std::ptr; + let _ = std::ptr::null_mut::(); + let _ = std::ptr::null::(); + let _ = std::ptr::null_mut::(); + let _ = std::ptr::null::(); + + // Make sure the lint is triggered inside a macro + let _ = inline!(std::ptr::null_mut::()); + let _ = inline!(std::ptr::null_mut::()); + + // Do not lint inside macros from external crates + let _ = external!(ptr::null::() as *mut u32); + let _ = external!(ptr::null::().cast_mut()); +} diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs index 5ce590b2b7e47..43ab5f5ba7ccc 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs @@ -68,3 +68,20 @@ fn _msrv_1_65() { let _ = ptr as *mut u32; let _ = mut_ptr as *const u32; } + +#[inline_macros] +fn null_pointers() { + use std::ptr; + let _ = ptr::null::() as *mut String; + let _ = ptr::null_mut::() as *const u32; + let _ = ptr::null::().cast_mut(); + let _ = ptr::null_mut::().cast_const(); + + // Make sure the lint is triggered inside a macro + let _ = inline!(ptr::null::() as *mut u32); + let _ = inline!(ptr::null::().cast_mut()); + + // Do not lint inside macros from external crates + let _ = external!(ptr::null::() as *mut u32); + let _ = external!(ptr::null::().cast_mut()); +} diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr index 2c52ebd3464d6..a693793a4ae96 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr @@ -43,5 +43,45 @@ error: `as` casting between raw pointers while changing only its constness LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` -error: aborting due to 7 previous errors +error: `as` casting to make a const null pointer into a mutable null pointer + --> tests/ui/ptr_cast_constness.rs:75:13 + | +LL | let _ = ptr::null::() as *mut String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + +error: `as` casting to make a mutable null pointer into a const null pointer + --> tests/ui/ptr_cast_constness.rs:76:13 + | +LL | let _ = ptr::null_mut::() as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:77:13 + | +LL | let _ = ptr::null::().cast_mut(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:78:13 + | +LL | let _ = ptr::null_mut::().cast_const(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` + +error: `as` casting to make a const null pointer into a mutable null pointer + --> tests/ui/ptr_cast_constness.rs:81:21 + | +LL | let _ = inline!(ptr::null::() as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + | + = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:82:21 + | +LL | let _ = inline!(ptr::null::().cast_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + | + = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/result_large_err.rs b/src/tools/clippy/tests/ui/result_large_err.rs index b25348bf99617..9c39f023da2da 100644 --- a/src/tools/clippy/tests/ui/result_large_err.rs +++ b/src/tools/clippy/tests/ui/result_large_err.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #![warn(clippy::result_large_err)] #![allow(clippy::large_enum_variant)] diff --git a/src/tools/clippy/tests/ui/single_call_fn.rs b/src/tools/clippy/tests/ui/single_call_fn.rs index 55e7508a9573a..a0597664da55c 100644 --- a/src/tools/clippy/tests/ui/single_call_fn.rs +++ b/src/tools/clippy/tests/ui/single_call_fn.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 //@aux-build:proc_macros.rs #![allow(clippy::redundant_closure_call, unused)] #![warn(clippy::single_call_fn)] diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed index 5249c4408899a..4016b2699d6b4 100644 --- a/src/tools/clippy/tests/ui/single_match.fixed +++ b/src/tools/clippy/tests/ui/single_match.fixed @@ -39,8 +39,8 @@ enum Foo { Bar, Baz(u8), } -use std::borrow::Cow; use Foo::*; +use std::borrow::Cow; fn single_match_know_enum() { let x = Some(1u8); @@ -296,3 +296,27 @@ fn issue11365() { if let Some(A | B) = &Some(A) { println!() } } + +#[derive(Eq, PartialEq)] +pub struct Data([u8; 4]); + +const DATA: Data = Data([1, 2, 3, 4]); +const CONST_I32: i32 = 1; + +fn irrefutable_match() { + println!(); + + println!(); + + let i = 0; + { + let a = 1; + let b = 2; + } + + + + + + println!() +} diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs index 882098a56e780..75edaa606053d 100644 --- a/src/tools/clippy/tests/ui/single_match.rs +++ b/src/tools/clippy/tests/ui/single_match.rs @@ -51,8 +51,8 @@ enum Foo { Bar, Baz(u8), } -use std::borrow::Cow; use Foo::*; +use std::borrow::Cow; fn single_match_know_enum() { let x = Some(1u8); @@ -360,3 +360,45 @@ fn issue11365() { None | Some(_) => {}, } } + +#[derive(Eq, PartialEq)] +pub struct Data([u8; 4]); + +const DATA: Data = Data([1, 2, 3, 4]); +const CONST_I32: i32 = 1; + +fn irrefutable_match() { + match DATA { + DATA => println!(), + _ => {}, + } + + match CONST_I32 { + CONST_I32 => println!(), + _ => {}, + } + + let i = 0; + match i { + i => { + let a = 1; + let b = 2; + }, + _ => {}, + } + + match i { + i => {}, + _ => {}, + } + + match i { + i => (), + _ => (), + } + + match CONST_I32 { + CONST_I32 => println!(), + _ => {}, + } +} diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr index ceb2a193bf7b1..9240b09c50a9f 100644 --- a/src/tools/clippy/tests/ui/single_match.stderr +++ b/src/tools/clippy/tests/ui/single_match.stderr @@ -216,5 +216,70 @@ LL | | None | Some(_) => {}, LL | | } | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }` -error: aborting due to 20 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:371:5 + | +LL | / match DATA { +LL | | DATA => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!();` + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:376:5 + | +LL | / match CONST_I32 { +LL | | CONST_I32 => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!();` + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:382:5 + | +LL | / match i { +LL | | i => { +LL | | let a = 1; +LL | | let b = 2; +LL | | }, +LL | | _ => {}, +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let a = 1; +LL + let b = 2; +LL + } + | + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:390:5 + | +LL | / match i { +LL | | i => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: `match` expression can be removed + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:395:5 + | +LL | / match i { +LL | | i => (), +LL | | _ => (), +LL | | } + | |_____^ help: `match` expression can be removed + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:400:5 + | +LL | / match CONST_I32 { +LL | | CONST_I32 => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed index 163be16ad8be7..c2ca746976bd1 100644 --- a/src/tools/clippy/tests/ui/single_match_else.fixed +++ b/src/tools/clippy/tests/ui/single_match_else.fixed @@ -171,3 +171,7 @@ fn issue_10808(bar: Option) { }, } } + +fn irrefutable_match() -> Option<&'static ExprNode> { + Some(&NODE) +} diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs index 3f1fd2b31832f..2d9e877ee0fee 100644 --- a/src/tools/clippy/tests/ui/single_match_else.rs +++ b/src/tools/clippy/tests/ui/single_match_else.rs @@ -199,3 +199,13 @@ fn issue_10808(bar: Option) { }, } } + +fn irrefutable_match() -> Option<&'static ExprNode> { + match ExprNode::Butterflies { + ExprNode::Butterflies => Some(&NODE), + _ => { + let x = 5; + None + }, + } +} diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr index 61c348260d05e..a2801751a430a 100644 --- a/src/tools/clippy/tests/ui/single_match_else.stderr +++ b/src/tools/clippy/tests/ui/single_match_else.stderr @@ -197,5 +197,17 @@ LL + println!("None"); LL + } | -error: aborting due to 9 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match_else.rs:204:5 + | +LL | / match ExprNode::Butterflies { +LL | | ExprNode::Butterflies => Some(&NODE), +LL | | _ => { +LL | | let x = 5; +LL | | None +LL | | }, +LL | | } + | |_____^ help: try: `Some(&NODE)` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/string_slice.rs b/src/tools/clippy/tests/ui/string_slice.rs index 1d1911aaa1d91..dc519493a4dd3 100644 --- a/src/tools/clippy/tests/ui/string_slice.rs +++ b/src/tools/clippy/tests/ui/string_slice.rs @@ -1,7 +1,7 @@ -use std::borrow::Cow; +#![warn(clippy::string_slice)] +#![allow(clippy::no_effect)] -#[warn(clippy::string_slice)] -#[allow(clippy::no_effect)] +use std::borrow::Cow; fn main() { &"Ölkanne"[1..]; diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed b/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed index 5d7b1e0c17f25..704d6ea1bb837 100644 --- a/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed +++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed @@ -1,3 +1,4 @@ +#![allow(clippy::zombie_processes)] fn main() { // Things it should warn about: std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs index 8abd9803a0c6f..2a2a7557381c4 100644 --- a/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs +++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs @@ -1,3 +1,4 @@ +#![allow(clippy::zombie_processes)] fn main() { // Things it should warn about: std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr index d2517b66b5661..6fd07d07d7be6 100644 --- a/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr +++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr @@ -1,5 +1,5 @@ error: single argument that looks like it should be multiple arguments - --> tests/ui/suspicious_command_arg_space.rs:3:44 + --> tests/ui/suspicious_command_arg_space.rs:4:44 | LL | std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); | ^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap | ~~~~ ~~~~~~~~~~~~~~~ error: single argument that looks like it should be multiple arguments - --> tests/ui/suspicious_command_arg_space.rs:6:43 + --> tests/ui/suspicious_command_arg_space.rs:7:43 | LL | std::process::Command::new("cat").arg("--number file").spawn().unwrap(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.rs b/src/tools/clippy/tests/ui/suspicious_to_owned.rs index f32b07d45f635..794c2e7174afe 100644 --- a/src/tools/clippy/tests/ui/suspicious_to_owned.rs +++ b/src/tools/clippy/tests/ui/suspicious_to_owned.rs @@ -3,7 +3,7 @@ #![warn(clippy::implicit_clone)] #![allow(clippy::redundant_clone)] use std::borrow::Cow; -use std::ffi::{c_char, CStr}; +use std::ffi::{CStr, c_char}; fn main() { let moo = "Moooo"; diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed index 26cc5c27e88cc..3536c1746df36 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed @@ -1,5 +1,4 @@ #![warn(clippy::tabs_in_doc_comments)] -#[allow(dead_code)] /// /// Struct to hold two strings: diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs index 14b06966ecc1a..033a685066e1a 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs @@ -1,5 +1,4 @@ #![warn(clippy::tabs_in_doc_comments)] -#[allow(dead_code)] /// /// Struct to hold two strings: diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr index aef6c39145263..f8d30b728e58c 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr @@ -1,5 +1,5 @@ error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 + --> tests/ui/tabs_in_doc_comments.rs:5:5 | LL | /// - first one | ^^^^ help: consider using four spaces per tab @@ -8,43 +8,43 @@ LL | /// - first one = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:13 + --> tests/ui/tabs_in_doc_comments.rs:5:13 | LL | /// - first one | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:5 + --> tests/ui/tabs_in_doc_comments.rs:6:5 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:14 + --> tests/ui/tabs_in_doc_comments.rs:6:14 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 + --> tests/ui/tabs_in_doc_comments.rs:9:9 | LL | /// - First String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:11:9 + --> tests/ui/tabs_in_doc_comments.rs:10:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 + --> tests/ui/tabs_in_doc_comments.rs:13:9 | LL | /// - Second String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:15:9 + --> tests/ui/tabs_in_doc_comments.rs:14:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs index 1042249c5b7bd..7d0a37cde46db 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs @@ -2,6 +2,16 @@ #![warn(clippy::too_long_first_doc_paragraph)] +pub mod foo { + + // in foo.rs + //! A very short summary. + //! A much longer explanation that goes into a lot more detail about + //! how the thing works, possibly with doclinks and so one, + //! and probably spanning a many rows. Blablabla, it needs to be over + //! 200 characters so I needed to write something longeeeeeeer. +} + /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, /// gravida non lacinia at, rhoncus eu lacus. diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr index 7f48e5cf884e6..39926647f5437 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr @@ -1,16 +1,32 @@ error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:5:1 + --> tests/ui/too_long_first_doc_paragraph.rs:8:5 + | +LL | / //! A very short summary. +LL | | //! A much longer explanation that goes into a lot more detail about +LL | | //! how the thing works, possibly with doclinks and so one, +LL | | //! and probably spanning a many rows. Blablabla, it needs to be over +LL | | //! 200 characters so I needed to write something longeeeeeeer. + | |____^ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` +help: add an empty line + | +LL ~ //! A very short summary. +LL + //! +LL ~ //! A much longer explanation that goes into a lot more detail about + | + +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:15:1 | LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_ - | - = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:26:1 + --> tests/ui/too_long_first_doc_paragraph.rs:36:1 | LL | / /// Lorem LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia @@ -18,5 +34,5 @@ LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris a LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_32bit.rs b/src/tools/clippy/tests/ui/transmute_32bit.rs index 8e1316ca39d4f..e162bbb2d9296 100644 --- a/src/tools/clippy/tests/ui/transmute_32bit.rs +++ b/src/tools/clippy/tests/ui/transmute_32bit.rs @@ -1,4 +1,4 @@ -//@ignore-64bit +//@ignore-bitwidth: 64 #[warn(clippy::wrong_transmute)] fn main() { diff --git a/src/tools/clippy/tests/ui/transmute_64bit.rs b/src/tools/clippy/tests/ui/transmute_64bit.rs index 767cc503a39df..fd0ad74bcfa0a 100644 --- a/src/tools/clippy/tests/ui/transmute_64bit.rs +++ b/src/tools/clippy/tests/ui/transmute_64bit.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #[warn(clippy::wrong_transmute)] fn main() { diff --git a/src/tools/clippy/tests/ui/transmute_collection.rs b/src/tools/clippy/tests/ui/transmute_collection.rs index e30b34a5d7d6f..6748b66e0eb6c 100644 --- a/src/tools/clippy/tests/ui/transmute_collection.rs +++ b/src/tools/clippy/tests/ui/transmute_collection.rs @@ -2,7 +2,7 @@ #![allow(clippy::missing_transmute_annotations)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; -use std::mem::{transmute, MaybeUninit}; +use std::mem::{MaybeUninit, transmute}; fn main() { unsafe { diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs index dd4bac7f1ed72..5b16d71f1142a 100644 --- a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs +++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs @@ -8,7 +8,7 @@ use core::any::TypeId; use core::ffi::c_void; -use core::mem::{size_of, transmute, MaybeUninit}; +use core::mem::{MaybeUninit, size_of, transmute}; use core::ptr::NonNull; fn value() -> T { diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs index 0cc77a8775d57..464f88140bdba 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.rs +++ b/src/tools/clippy/tests/ui/uninit_vec.rs @@ -150,4 +150,36 @@ fn main() { vec.set_len(10); } } + + fn nested_union() { + let mut vec: Vec>> = Vec::with_capacity(1); + unsafe { + vec.set_len(1); + } + } + + struct Recursive(*const Recursive, MaybeUninit); + fn recursive_union() { + // Make sure we don't stack overflow on recursive types. + // The pointer acts as the base case because it can't be uninit regardless of its pointee. + + let mut vec: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { + vec.set_len(1); + } + } + + #[repr(u8)] + enum Enum { + Variant(T), + } + fn union_in_enum() { + // Enums can have a discriminant that can't be uninit, so this should still warn + let mut vec: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { + vec.set_len(1); + } + } } diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr index e8b77d653f089..e7c81cf792f23 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.stderr +++ b/src/tools/clippy/tests/ui/uninit_vec.stderr @@ -125,5 +125,27 @@ LL | vec.set_len(10); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 12 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:166:9 + | +LL | let mut vec: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:179:9 + | +LL | let mut vec: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed b/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed new file mode 100644 index 0000000000000..7202e1bbd179c --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_first_then_check)] +#![allow(clippy::useless_vec, clippy::const_is_empty)] + +fn main() { + let s = [1, 2, 3]; + let _: bool = !s.is_empty(); + let _: bool = s.is_empty(); + + let v = vec![1, 2, 3]; + let _: bool = !v.is_empty(); + + let n = [[1, 2, 3], [4, 5, 6]]; + let _: bool = !n[0].is_empty(); + let _: bool = n[0].is_empty(); + + struct Foo { + bar: &'static [i32], + } + let f = [Foo { bar: &[] }]; + let _: bool = !f[0].bar.is_empty(); + let _: bool = f[0].bar.is_empty(); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs b/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs new file mode 100644 index 0000000000000..762b959992883 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_first_then_check)] +#![allow(clippy::useless_vec, clippy::const_is_empty)] + +fn main() { + let s = [1, 2, 3]; + let _: bool = s.first().is_some(); + let _: bool = s.first().is_none(); + + let v = vec![1, 2, 3]; + let _: bool = v.first().is_some(); + + let n = [[1, 2, 3], [4, 5, 6]]; + let _: bool = n[0].first().is_some(); + let _: bool = n[0].first().is_none(); + + struct Foo { + bar: &'static [i32], + } + let f = [Foo { bar: &[] }]; + let _: bool = f[0].bar.first().is_some(); + let _: bool = f[0].bar.first().is_none(); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr b/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr new file mode 100644 index 0000000000000..bbaf7e68edabb --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr @@ -0,0 +1,47 @@ +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:6:19 + | +LL | let _: bool = s.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!s.is_empty()` + | + = note: `-D clippy::unnecessary-first-then-check` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_first_then_check)]` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:7:21 + | +LL | let _: bool = s.first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:10:19 + | +LL | let _: bool = v.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!v.is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:13:19 + | +LL | let _: bool = n[0].first().is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!n[0].is_empty()` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:14:24 + | +LL | let _: bool = n[0].first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:20:19 + | +LL | let _: bool = f[0].bar.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!f[0].bar.is_empty()` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:21:28 + | +LL | let _: bool = f[0].bar.first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed index 392f6dd1fee43..1f3e131516ce6 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed @@ -65,3 +65,32 @@ fn random_u32() -> u32 { // random number generator 0 } + +struct Issue13191 { + min: u16, + max: u16, +} + +impl Issue13191 { + fn new() -> Self { + Self { min: 0, max: 0 } + } + + fn min(mut self, value: u16) -> Self { + self.min = value; + self + } + + fn max(mut self, value: u16) -> Self { + self.max = value; + self + } +} + +fn issue_13191() { + // should not fixed + Issue13191::new().min(0); + + // should not fixed + Issue13191::new().max(0); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs index b03755e6d23d1..58356b9d49e77 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs @@ -65,3 +65,32 @@ fn random_u32() -> u32 { // random number generator 0 } + +struct Issue13191 { + min: u16, + max: u16, +} + +impl Issue13191 { + fn new() -> Self { + Self { min: 0, max: 0 } + } + + fn min(mut self, value: u16) -> Self { + self.min = value; + self + } + + fn max(mut self, value: u16) -> Self { + self.max = value; + self + } +} + +fn issue_13191() { + // should not fixed + Issue13191::new().min(0); + + // should not fixed + Issue13191::new().max(0); +} diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs index e0e0ded140fc0..e9e6c8312f5eb 100644 --- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs +++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs @@ -7,7 +7,7 @@ use std::cell::UnsafeCell as TotallySafeCell; //~| NOTE: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` use std::cell::UnsafeCell as TotallySafeCellAgain; -//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain +//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain` // Shouldn't error use std::cell::RefCell as ProbablyNotUnsafe; diff --git a/src/tools/clippy/tests/ui/unused_trait_names.fixed b/src/tools/clippy/tests/ui/unused_trait_names.fixed new file mode 100644 index 0000000000000..7dfd0db65aa1b --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_trait_names.fixed @@ -0,0 +1,286 @@ +//@aux-build:proc_macros.rs + +#![allow(unused)] +#![warn(clippy::unused_trait_names)] +#![feature(decl_macro)] + +extern crate proc_macros; + +fn main() {} + +fn bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn good() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn used_good() { + use std::any::Any; + + println!("{:?}", Any::type_id("foo")); + println!("{:?}", "foo".type_id()); +} + +fn multi_bad() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn multi_good() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn renamed_bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn multi_renamed_bad() { + use std::any::{Any as _, TypeId as MyTypeId}; + + println!("{:?}", "foo".type_id()); +} + +mod pub_good { + pub use std::any::Any; + + fn foo() { + println!("{:?}", "foo".type_id()); + } +} + +mod used_mod_good { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } +} + +mod mod_import_bad { + fn mod_import_bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); + } +} + +mod nested_mod_used_good1 { + use std::any::Any; + + mod foo { + fn foo() { + super::Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good2 { + use std::any::Any; + + mod foo { + use super::Any; + + fn foo() { + Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good3 { + use std::any::Any; + + mod foo { + use crate::nested_mod_used_good3::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +mod nested_mod_used_bad { + use std::any::Any as _; + + fn bar() { + println!("{:?}", "foo".type_id()); + } + + mod foo { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +// More complex example where `use std::any::Any;` should be anonymised but `use std::any::Any as +// MyAny;` should not as it is used by a sub module. Even though if you removed `use std::any::Any;` +// the code would still compile. +mod nested_mod_used_bad1 { + use std::any::Any as _; + + use std::any::Any as MyAny; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod foo { + use crate::nested_mod_used_bad1::MyAny; + + fn foo() { + println!("{:?}", MyAny::type_id("foo")); + } + } +} + +// Example of nested import with an unused import to try and trick it +mod nested_mod_used_good5 { + use std::any::Any; + + mod foo { + use std::any::Any; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod bar { + use crate::nested_mod_used_good5::foo::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } + } +} + +mod simple_trait { + pub trait MyTrait { + fn do_things(&self); + } + + pub struct MyStruct; + + impl MyTrait for MyStruct { + fn do_things(&self) {} + } +} + +// Underscore imports were stabilized in 1.33 +#[clippy::msrv = "1.32"] +fn msrv_1_32() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +#[clippy::msrv = "1.33"] +fn msrv_1_33() { + use simple_trait::{MyStruct, MyTrait as _}; + MyStruct.do_things(); +} + +mod lint_inside_macro_expansion_bad { + macro_rules! foo { + () => { + use std::any::Any as _; + fn bar() { + "bar".type_id(); + } + }; + } + + foo!(); +} + +mod macro_and_trait_same_name { + pub macro Foo() {} + pub trait Foo { + fn bar(&self); + } + impl Foo for () { + fn bar(&self) {} + } +} + +fn call_macro_and_trait_good() { + // importing trait and macro but only using macro by path won't allow us to change this to + // `use macro_and_trait_same_name::Foo as _;` + use macro_and_trait_same_name::Foo; + Foo!(); + ().bar(); +} + +proc_macros::external!( + fn ignore_inside_external_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +proc_macros::with_span!( + span + + fn ignore_inside_with_span_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +// This should warn the import is unused but should not trigger unused_trait_names +#[warn(unused)] +mod unused_import { + +} + +#[allow(clippy::unused_trait_names)] +fn allow_lint_fn() { + use std::any::Any; + + "foo".type_id(); +} + +#[allow(clippy::unused_trait_names)] +mod allow_lint_mod { + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +mod allow_lint_import { + #[allow(clippy::unused_trait_names)] + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +// Limitation: Suggests `use std::any::Any as _::{self};` which looks weird +// fn use_trait_self_good() { +// use std::any::Any::{self}; +// "foo".type_id(); +// } + +// Limitation: Suggests `use std::any::{Any as _, Any as _};` +// mod repeated_renamed { +// use std::any::{Any, Any as MyAny}; + +// fn foo() { +// "foo".type_id(); +// } +// } diff --git a/src/tools/clippy/tests/ui/unused_trait_names.rs b/src/tools/clippy/tests/ui/unused_trait_names.rs new file mode 100644 index 0000000000000..ce44eedbc79c2 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_trait_names.rs @@ -0,0 +1,286 @@ +//@aux-build:proc_macros.rs + +#![allow(unused)] +#![warn(clippy::unused_trait_names)] +#![feature(decl_macro)] + +extern crate proc_macros; + +fn main() {} + +fn bad() { + use std::any::Any; + + println!("{:?}", "foo".type_id()); +} + +fn good() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn used_good() { + use std::any::Any; + + println!("{:?}", Any::type_id("foo")); + println!("{:?}", "foo".type_id()); +} + +fn multi_bad() { + use std::any::{self, Any, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn multi_good() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn renamed_bad() { + use std::any::Any as MyAny; + + println!("{:?}", "foo".type_id()); +} + +fn multi_renamed_bad() { + use std::any::{Any as MyAny, TypeId as MyTypeId}; + + println!("{:?}", "foo".type_id()); +} + +mod pub_good { + pub use std::any::Any; + + fn foo() { + println!("{:?}", "foo".type_id()); + } +} + +mod used_mod_good { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } +} + +mod mod_import_bad { + fn mod_import_bad() { + use std::any::Any; + + println!("{:?}", "foo".type_id()); + } +} + +mod nested_mod_used_good1 { + use std::any::Any; + + mod foo { + fn foo() { + super::Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good2 { + use std::any::Any; + + mod foo { + use super::Any; + + fn foo() { + Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good3 { + use std::any::Any; + + mod foo { + use crate::nested_mod_used_good3::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +mod nested_mod_used_bad { + use std::any::Any; + + fn bar() { + println!("{:?}", "foo".type_id()); + } + + mod foo { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +// More complex example where `use std::any::Any;` should be anonymised but `use std::any::Any as +// MyAny;` should not as it is used by a sub module. Even though if you removed `use std::any::Any;` +// the code would still compile. +mod nested_mod_used_bad1 { + use std::any::Any; + + use std::any::Any as MyAny; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod foo { + use crate::nested_mod_used_bad1::MyAny; + + fn foo() { + println!("{:?}", MyAny::type_id("foo")); + } + } +} + +// Example of nested import with an unused import to try and trick it +mod nested_mod_used_good5 { + use std::any::Any; + + mod foo { + use std::any::Any; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod bar { + use crate::nested_mod_used_good5::foo::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } + } +} + +mod simple_trait { + pub trait MyTrait { + fn do_things(&self); + } + + pub struct MyStruct; + + impl MyTrait for MyStruct { + fn do_things(&self) {} + } +} + +// Underscore imports were stabilized in 1.33 +#[clippy::msrv = "1.32"] +fn msrv_1_32() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +#[clippy::msrv = "1.33"] +fn msrv_1_33() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +mod lint_inside_macro_expansion_bad { + macro_rules! foo { + () => { + use std::any::Any; + fn bar() { + "bar".type_id(); + } + }; + } + + foo!(); +} + +mod macro_and_trait_same_name { + pub macro Foo() {} + pub trait Foo { + fn bar(&self); + } + impl Foo for () { + fn bar(&self) {} + } +} + +fn call_macro_and_trait_good() { + // importing trait and macro but only using macro by path won't allow us to change this to + // `use macro_and_trait_same_name::Foo as _;` + use macro_and_trait_same_name::Foo; + Foo!(); + ().bar(); +} + +proc_macros::external!( + fn ignore_inside_external_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +proc_macros::with_span!( + span + + fn ignore_inside_with_span_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +// This should warn the import is unused but should not trigger unused_trait_names +#[warn(unused)] +mod unused_import { + use std::any::Any; +} + +#[allow(clippy::unused_trait_names)] +fn allow_lint_fn() { + use std::any::Any; + + "foo".type_id(); +} + +#[allow(clippy::unused_trait_names)] +mod allow_lint_mod { + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +mod allow_lint_import { + #[allow(clippy::unused_trait_names)] + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +// Limitation: Suggests `use std::any::Any as _::{self};` which looks weird +// fn use_trait_self_good() { +// use std::any::Any::{self}; +// "foo".type_id(); +// } + +// Limitation: Suggests `use std::any::{Any as _, Any as _};` +// mod repeated_renamed { +// use std::any::{Any, Any as MyAny}; + +// fn foo() { +// "foo".type_id(); +// } +// } diff --git a/src/tools/clippy/tests/ui/unused_trait_names.stderr b/src/tools/clippy/tests/ui/unused_trait_names.stderr new file mode 100644 index 0000000000000..f59d8f58a170a --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_trait_names.stderr @@ -0,0 +1,73 @@ +error: unused import: `std::any::Any` + --> tests/ui/unused_trait_names.rs:245:9 + | +LL | use std::any::Any; + | ^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:12:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + | + = note: `-D clippy::unused-trait-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_trait_names)]` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:31:26 + | +LL | use std::any::{self, Any, TypeId}; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:43:19 + | +LL | use std::any::Any as MyAny; + | ^^^^^^^^^^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:49:20 + | +LL | use std::any::{Any as MyAny, TypeId as MyTypeId}; + | ^^^^^^^^^^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:72:23 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:113:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:132:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:191:34 + | +LL | use simple_trait::{MyStruct, MyTrait}; + | ^^^^^^^ help: use: `MyTrait as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:198:27 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr index 556e1792b3e68..f9e8013d3ad57 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr +++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr @@ -1,10 +1,10 @@ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:23:5 | LL | _foo + 1 | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:22:22 | LL | fn prefix_underscore(_foo: u32) -> u32 { @@ -12,61 +12,61 @@ LL | fn prefix_underscore(_foo: u32) -> u32 { = note: `-D clippy::used-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::used_underscore_binding)]` -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:28:20 | LL | println!("{}", _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:29:16 | LL | assert_eq!(_foo, _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:29:22 | LL | assert_eq!(_foo, _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:42:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ | -note: `_underscore_field` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:36:5 | LL | _underscore_field: u32, | ^^^^^^^^^^^^^^^^^^^^^^ -error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:103:16 | LL | uses_i(_i); | ^^ | -note: `_i` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:102:13 | LL | let _i = 5; diff --git a/src/tools/clippy/tests/ui/used_underscore_items.rs b/src/tools/clippy/tests/ui/used_underscore_items.rs new file mode 100644 index 0000000000000..223016a5c9667 --- /dev/null +++ b/src/tools/clippy/tests/ui/used_underscore_items.rs @@ -0,0 +1,63 @@ +//@aux-build:external_item.rs +#![allow(unused)] +#![warn(clippy::used_underscore_items)] + +extern crate external_item; + +// should not lint macro +macro_rules! macro_wrap_func { + () => { + fn _marco_foo() {} + }; +} + +macro_wrap_func!(); + +struct _FooStruct {} + +impl _FooStruct { + fn _method_call(self) {} +} + +fn _foo1() {} + +fn _foo2() -> i32 { + 0 +} + +mod a { + pub mod b { + pub mod c { + pub fn _foo3() {} + + pub struct _FooStruct2 {} + + impl _FooStruct2 { + pub fn _method_call(self) {} + } + } + } +} + +fn main() { + _foo1(); + let _ = _foo2(); + a::b::c::_foo3(); + let _ = &_FooStruct {}; + let _ = _FooStruct {}; + + let foo_struct = _FooStruct {}; + foo_struct._method_call(); + + let foo_struct2 = a::b::c::_FooStruct2 {}; + foo_struct2._method_call(); +} + +// should not lint exteranl crate. +// user cannot control how others name their items +fn external_item_call() { + let foo_struct3 = external_item::_ExternalStruct {}; + foo_struct3._foo(); + + external_item::_exernal_foo(); +} diff --git a/src/tools/clippy/tests/ui/used_underscore_items.stderr b/src/tools/clippy/tests/ui/used_underscore_items.stderr new file mode 100644 index 0000000000000..93ac3a6fec6be --- /dev/null +++ b/src/tools/clippy/tests/ui/used_underscore_items.stderr @@ -0,0 +1,112 @@ +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:43:5 + | +LL | _foo1(); + | ^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:22:1 + | +LL | fn _foo1() {} + | ^^^^^^^^^^ + = note: `-D clippy::used-underscore-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::used_underscore_items)]` + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:44:13 + | +LL | let _ = _foo2(); + | ^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:24:1 + | +LL | fn _foo2() -> i32 { + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:45:5 + | +LL | a::b::c::_foo3(); + | ^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:31:13 + | +LL | pub fn _foo3() {} + | ^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:46:14 + | +LL | let _ = &_FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:47:13 + | +LL | let _ = _FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:49:22 + | +LL | let foo_struct = _FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:50:5 + | +LL | foo_struct._method_call(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:19:5 + | +LL | fn _method_call(self) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:52:23 + | +LL | let foo_struct2 = a::b::c::_FooStruct2 {}; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:33:13 + | +LL | pub struct _FooStruct2 {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:53:5 + | +LL | foo_struct2._method_call(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:36:17 + | +LL | pub fn _method_call(self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs new file mode 100644 index 0000000000000..a2abc7fc3a179 --- /dev/null +++ b/src/tools/clippy/tests/ui/zombie_processes.rs @@ -0,0 +1,138 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::if_same_then_else, clippy::ifs_same_cond)] + +use std::process::{Child, Command}; + +fn main() { + { + // Check that #[expect] works + #[expect(clippy::zombie_processes)] + let mut x = Command::new("").spawn().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + x.kill(); + x.id(); + } + { + let mut x = Command::new("").spawn().unwrap(); + x.wait().unwrap(); // OK + } + { + let x = Command::new("").spawn().unwrap(); + x.wait_with_output().unwrap(); // OK + } + { + let mut x = Command::new("").spawn().unwrap(); + x.try_wait().unwrap(); // OK + } + { + let mut x = Command::new("").spawn().unwrap(); + let mut r = &mut x; + r.wait().unwrap(); // OK, not calling `.wait()` directly on `x` but through `r` -> `x` + } + { + let mut x = Command::new("").spawn().unwrap(); + process_child(x); // OK, other function might call `.wait()` so assume it does + } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + let v = &x; + // (allow shared refs is fine because one cannot call `.wait()` through that) + } + + // https://github.com/rust-lang/rust-clippy/pull/11476#issuecomment-1718456033 + // Unconditionally exiting the process in various ways (should not lint) + { + let mut x = Command::new("").spawn().unwrap(); + std::process::exit(0); + } + { + let mut x = Command::new("").spawn().unwrap(); + std::process::abort(); // same as above, but abort instead of exit + } + { + let mut x = Command::new("").spawn().unwrap(); + if true { /* nothing */ } + std::process::abort(); // still unconditionally exits + } + + // Conditionally exiting + // It should assume that it might not exit and still lint + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + std::process::exit(0); + } + } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + while false {} + // Calling `exit()` after leaving a while loop should still be linted. + std::process::exit(0); + } + } + + { + let mut x = { Command::new("").spawn().unwrap() }; + x.wait().unwrap(); + } + + { + struct S { + c: Child, + } + + let mut s = S { + c: Command::new("").spawn().unwrap(), + }; + s.c.wait().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + return; + } + x.wait().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + x.wait().unwrap(); + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + if true { + x.wait().unwrap(); + } else if true { + x.wait().unwrap(); + } else { + x.wait().unwrap(); + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + if true { + x.wait().unwrap(); + return; + } + x.wait().unwrap(); + } +} + +fn process_child(c: Child) { + todo!() +} diff --git a/src/tools/clippy/tests/ui/zombie_processes.stderr b/src/tools/clippy/tests/ui/zombie_processes.stderr new file mode 100644 index 0000000000000..eec821a4c8f18 --- /dev/null +++ b/src/tools/clippy/tests/ui/zombie_processes.stderr @@ -0,0 +1,64 @@ +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:14:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider calling `.wait()` + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + = note: `-D clippy::zombie-processes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:41:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider calling `.wait()` + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:66:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider calling `.wait()` + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:73:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider calling `.wait()` + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:99:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider calling `.wait()` + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:108:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider calling `.wait()` + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed b/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed new file mode 100644 index 0000000000000..6045262f519a7 --- /dev/null +++ b/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed @@ -0,0 +1,26 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] + +use std::process::{Child, Command}; + +fn main() { + let _ = Command::new("").spawn().unwrap().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + Command::new("").spawn().unwrap().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait().unwrap(); // OK +} + +fn not_main() { + Command::new("").spawn().unwrap().wait(); +} + +fn spawn_proc() -> Child { + Command::new("").spawn().unwrap() +} + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/src/tools/clippy/tests/ui/zombie_processes_fixable.rs b/src/tools/clippy/tests/ui/zombie_processes_fixable.rs new file mode 100644 index 0000000000000..e1ecb771641e2 --- /dev/null +++ b/src/tools/clippy/tests/ui/zombie_processes_fixable.rs @@ -0,0 +1,26 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] + +use std::process::{Child, Command}; + +fn main() { + let _ = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait().unwrap(); // OK +} + +fn not_main() { + Command::new("").spawn().unwrap(); +} + +fn spawn_proc() -> Child { + Command::new("").spawn().unwrap() +} + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr b/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr new file mode 100644 index 0000000000000..e1c40472c325e --- /dev/null +++ b/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr @@ -0,0 +1,40 @@ +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:7:13 + | +LL | let _ = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` + | + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + = note: `-D clippy::zombie-processes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:9:5 + | +LL | Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` + | + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:11:5 + | +LL | spawn_proc(); + | ^^^^^^^^^^^^- help: try: `.wait()` + | + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:17:5 + | +LL | Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` + | + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 99b3560a06427..dcf00e4e384b0 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -20,7 +20,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ - "flip1995", "matthiaskrgr", "giraffate", ] diff --git a/src/tools/clippy/util/gh-pages/versions.html b/src/tools/clippy/util/gh-pages/versions.html index 31ce881932952..d38fe39a46403 100644 --- a/src/tools/clippy/util/gh-pages/versions.html +++ b/src/tools/clippy/util/gh-pages/versions.html @@ -1,4 +1,5 @@ + @@ -7,26 +8,15 @@ Clippy lints documentation - -
+
-
- - - -
- - - - - - - + .github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + @keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } + } + @media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + } + + diff --git a/src/tools/clippy/util/versions.py b/src/tools/clippy/util/versions.py index c041fc606a8f3..fee0d292df16f 100755 --- a/src/tools/clippy/util/versions.py +++ b/src/tools/clippy/util/versions.py @@ -1,22 +1,21 @@ #!/usr/bin/env python -import json -import logging as log +from string import Template +import argparse import os import sys -log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") - - def key(v): if v == "master": - return float("inf") - if v == "stable": return sys.maxsize - if v == "beta": + if v == "stable": return sys.maxsize - 1 + if v == "beta": + return sys.maxsize - 2 if v == "pre-1.29.0": return -1 + if not v.startswith("rust-"): + return None v = v.replace("rust-", "") @@ -26,26 +25,27 @@ def key(v): return s - def main(): - if len(sys.argv) < 2: - log.error("specify output directory") - return + parser = argparse.ArgumentParser() + parser.add_argument("input", help="path to the versions.html template", type=argparse.FileType("r")) + parser.add_argument("outdir", help="path to write the output HTML") + args = parser.parse_args() - outdir = sys.argv[1] versions = [ dir - for dir in os.listdir(outdir) - if not dir.startswith(".") - and not dir.startswith("v") - and os.path.isdir(os.path.join(outdir, dir)) + for dir in os.listdir(args.outdir) + if key(dir) is not None ] - versions.sort(key=key) + versions.sort(key=key, reverse=True) + links = [f'{version}' for version in versions] - with open(os.path.join(outdir, "versions.json"), "w") as fp: - json.dump(versions, fp, indent=2) - log.info("wrote JSON for great justice") + template = Template(args.input.read()) + html = template.substitute(list="\n".join(links)) + path = os.path.join(args.outdir, "index.html") + with open(path, "w") as out: + out.write(html) + print(f"wrote HTML to {path}") if __name__ == "__main__": main()