Merge commit '7901289135257ca0fbed3a5522526f95b0f5edba' into clippy-subtree-update

This commit is contained in:
Philipp Krones 2024-09-24 11:58:04 +02:00
parent 249210e8d8
commit b61fcbee76
566 changed files with 7442 additions and 2576 deletions

9
.github/deploy.sh vendored
View File

@ -25,16 +25,15 @@ if [[ $BETA = "true" ]]; then
fi fi
# Generate version index that is shown as root index page # Generate version index that is shown as root index page
cp util/gh-pages/versions.html out/index.html python3 ./util/versions.py ./util/gh-pages/versions.html out
echo "Making the versions.json file"
python3 ./util/versions.py out
# Now let's go have some fun with the cloned repo # Now let's go have some fun with the cloned repo
cd out cd out
git config user.name "GHA CI" git config user.name "GHA CI"
git config user.email "gha@ci.invalid" git config user.email "gha@ci.invalid"
git status
if [[ -n $TAG_NAME ]]; then if [[ -n $TAG_NAME ]]; then
# track files, so that the following check works # track files, so that the following check works
git add --intent-to-add "$TAG_NAME" git add --intent-to-add "$TAG_NAME"
@ -46,8 +45,6 @@ if [[ -n $TAG_NAME ]]; then
git add "$TAG_NAME" git add "$TAG_NAME"
# Update the symlink # Update the symlink
git add stable git add stable
# Update versions file
git add versions.json
git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}" git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}"
elif [[ $BETA = "true" ]]; then elif [[ $BETA = "true" ]]; then
if git diff --exit-code --quiet -- beta/; then if git diff --exit-code --quiet -- beta/; then

View File

@ -162,7 +162,7 @@ jobs:
find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
- name: Upload Binaries - name: Upload Binaries
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: binaries name: binaries
path: target/debug path: target/debug
@ -202,7 +202,7 @@ jobs:
# Download # Download
- name: Download target dir - name: Download target dir
uses: actions/download-artifact@v3 uses: actions/download-artifact@v4
with: with:
name: binaries name: binaries
path: target/debug path: target/debug

View File

@ -6,7 +6,61 @@ document.
## Unreleased / Beta / In Rust Nightly ## 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 ## 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_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_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 [`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 [`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 [`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 [`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_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_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_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`]: 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_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 [`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_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_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_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_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_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 [`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_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_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_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 [`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 [`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 [`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 [`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 [`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 [`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 [`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 [`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 [`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_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_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_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_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_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 [`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_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_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_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 [`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 [`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 [`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_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 [`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_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_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_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 [`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_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_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 [`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 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
<!-- end autogenerated links to lint list --> <!-- end autogenerated links to lint list -->
<!-- begin autogenerated links to configuration documentation --> <!-- begin autogenerated links to configuration documentation -->

View File

@ -1,6 +1,6 @@
[package] [package]
name = "clippy" name = "clippy"
version = "0.1.82" version = "0.1.83"
description = "A bunch of helpful lints to avoid common pitfalls in Rust" description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy" repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md" readme = "README.md"
@ -31,7 +31,7 @@ anstream = "0.6.0"
[dev-dependencies] [dev-dependencies]
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
ui_test = "0.25" ui_test = "0.26.4"
regex = "1.5.5" regex = "1.5.5"
serde = { version = "1.0.145", features = ["derive"] } serde = { version = "1.0.145", features = ["derive"] }
serde_json = "1.0.122" serde_json = "1.0.122"
@ -67,3 +67,10 @@ harness = false
[[test]] [[test]]
name = "dogfood" name = "dogfood"
harness = false harness = false
# quine-mc_cluskey makes up a significant part of the runtime in dogfood
# due to the number of conditions in the clippy_lints crate
# and enabling optimizations for that specific dependency helps a bit
# without increasing total build times.
[profile.dev.package.quine-mc_cluskey]
opt-level = 3

View File

@ -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) * [`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) * [`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) * [`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) * [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "clippy_config" name = "clippy_config"
version = "0.1.82" version = "0.1.83"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,6 +1,6 @@
use crate::ClippyConfiguration;
use crate::msrvs::Msrv; use crate::msrvs::Msrv;
use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename};
use crate::ClippyConfiguration;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::edit_distance::edit_distance; use rustc_span::edit_distance::edit_distance;
@ -563,6 +563,7 @@ define_Conf! {
uninlined_format_args, uninlined_format_args,
unnecessary_lazy_evaluations, unnecessary_lazy_evaluations,
unnested_or_patterns, unnested_or_patterns,
unused_trait_names,
use_self, use_self,
)] )]
msrv: Msrv = Msrv::empty(), msrv: Msrv = Msrv::empty(),
@ -864,7 +865,7 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) 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) let column_widths = (0..columns)
.map(|column| { .map(|column| {

View File

@ -26,5 +26,5 @@ mod metadata;
pub mod msrvs; pub mod msrvs;
pub mod types; 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; pub use metadata::ClippyConfiguration;

View File

@ -1,7 +1,7 @@
use rustc_ast::Attribute; use rustc_ast::Attribute;
use rustc_attr::parse_version; use rustc_attr::parse_version;
use rustc_session::{RustcVersion, Session}; use rustc_session::{RustcVersion, Session};
use rustc_span::{sym, Symbol}; use rustc_span::{Symbol, sym};
use serde::Deserialize; use serde::Deserialize;
use std::fmt; use std::fmt;
@ -23,6 +23,7 @@ msrv_aliases! {
1,80,0 { BOX_INTO_ITER} 1,80,0 { BOX_INTO_ITER}
1,77,0 { C_STR_LITERALS } 1,77,0 { C_STR_LITERALS }
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 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,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,68,0 { PATH_MAIN_SEPARATOR_STR }
@ -38,7 +39,7 @@ msrv_aliases! {
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
1,50,0 { BOOL_THEN, CLAMP } 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,46,0 { CONST_IF_MATCH }
1,45,0 { STR_STRIP_PREFIX } 1,45,0 { STR_STRIP_PREFIX }
1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS }
@ -50,6 +51,7 @@ msrv_aliases! {
1,36,0 { ITERATOR_COPIED } 1,36,0 { ITERATOR_COPIED }
1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
1,34,0 { TRY_FROM } 1,34,0 { TRY_FROM }
1,33,0 { UNDERSCORE_IMPORTS }
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
1,29,0 { ITER_FLATTEN } 1,29,0 { ITER_FLATTEN }
1,28,0 { FROM_BOOL } 1,28,0 { FROM_BOOL }

View File

@ -1,5 +1,5 @@
use serde::de::{self, Deserializer, Visitor}; use serde::de::{self, Deserializer, Visitor};
use serde::{ser, Deserialize, Serialize}; use serde::{Deserialize, Serialize, ser};
use std::fmt; use std::fmt;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]

View File

@ -1,6 +1,6 @@
use crate::clippy_project_root; use crate::clippy_project_root;
use itertools::Itertools; use itertools::Itertools;
use rustc_lexer::{tokenize, TokenKind}; use rustc_lexer::{TokenKind, tokenize};
use shell_escape::escape; use shell_escape::escape;
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::ops::ControlFlow; use std::ops::ControlFlow;

View File

@ -441,7 +441,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { 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; use rustc_lexer::TokenKind;
let lint_name_upper = lint.name.to_uppercase(); let lint_name_upper = lint.name.to_uppercase();

View File

@ -29,7 +29,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
} }
if let Some(url) = url.take() { if let Some(url) = url.take() {
thread::spawn(move || { thread::spawn(move || {
Command::new(PYTHON) let mut child = Command::new(PYTHON)
.arg("-m") .arg("-m")
.arg("http.server") .arg("http.server")
.arg(port.to_string()) .arg(port.to_string())
@ -40,6 +40,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
thread::sleep(Duration::from_millis(500)); thread::sleep(Duration::from_millis(500));
// Launch browser after first export.py has completed and http.server is up // Launch browser after first export.py has completed and http.server is up
let _result = opener::open(url); let _result = opener::open(url);
child.wait().unwrap();
}); });
} }
thread::sleep(Duration::from_millis(1000)); thread::sleep(Duration::from_millis(1000));

View File

@ -1,7 +1,7 @@
use crate::clippy_project_root; use crate::clippy_project_root;
use aho_corasick::AhoCorasickBuilder; use aho_corasick::AhoCorasickBuilder;
use itertools::Itertools; use itertools::Itertools;
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
@ -1048,23 +1048,17 @@ mod tests {
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
]; ];
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new(); let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
expected.insert( expected.insert("group1".to_string(), vec![
"group1".to_string(), Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
vec![ Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
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",
expected.insert( "\"abc\"",
"group2".to_string(), "module_name",
vec![Lint::new( Range::default(),
"should_assert_eq2", )]);
"group2",
"\"abc\"",
"module_name",
Range::default(),
)],
);
assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
} }
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "clippy_lints" name = "clippy_lints"
version = "0.1.82" version = "0.1.83"
description = "A bunch of helpful lints to avoid common pitfalls in Rust" description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy" repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md" readme = "README.md"

View File

@ -3,12 +3,12 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_from_proc_macro; use clippy_utils::is_from_proc_macro;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res}; 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_hir::{HirId, ItemKind, Node, Path};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
use rustc_span::Symbol; use rustc_span::Symbol;
use rustc_span::symbol::kw;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{trim_span, walk_span_to_context}; use clippy_utils::source::{trim_span, walk_span_to_context};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};

View File

@ -1,10 +1,10 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{impl_lint_pass, RustcVersion}; use rustc_session::{RustcVersion, impl_lint_pass};
use rustc_span::symbol; use rustc_span::symbol;
use std::f64::consts as f64; use std::f64::consts as f64;

View File

@ -4,8 +4,8 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use rustc_hir::{Expr, ExprKind, QPath}; use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;

View File

@ -1,7 +1,7 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_inside_always_const_context; 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_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then; 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::source::snippet_with_context;
use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
use clippy_utils::usage::local_used_after_expr; use clippy_utils::usage::local_used_after_expr;

View File

@ -1,7 +1,7 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; 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::sugg::Sugg;
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
use rustc_errors::Applicability; use rustc_errors::Applicability;

View File

@ -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::diagnostics::span_lint_and_then;
use clippy_utils::is_from_proc_macro; use clippy_utils::is_from_proc_macro;
use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast::{MetaItemKind, NestedMetaItem};
@ -26,7 +26,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
cx, cx,
ALLOW_ATTRIBUTES_WITHOUT_REASON, ALLOW_ATTRIBUTES_WITHOUT_REASON,
attr.span, attr.span,
format!("`{}` attribute without specifying a reason", name.as_str()), format!("`{name}` attribute without specifying a reason"),
|diag| { |diag| {
diag.help("try adding a reason at the end with `, reason = \"..\"`"); diag.help("try adding a reason at the end with `, reason = \"..\"`");
}, },

View File

@ -1,10 +1,10 @@
use super::utils::extract_clippy_lint;
use super::BLANKET_CLIPPY_RESTRICTION_LINTS; 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 clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use rustc_ast::NestedMetaItem; use rustc_ast::NestedMetaItem;
use rustc_lint::{LateContext, Level, LintContext}; use rustc_lint::{LateContext, Level, LintContext};
use rustc_span::symbol::Symbol; 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]) { pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) {
for lint in items { for lint in items {

View File

@ -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_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::AttrStyle; use rustc_ast::AttrStyle;

View File

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_ast::{Attribute, MetaItem}; use rustc_ast::{Attribute, MetaItem};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
fn emit_if_duplicated( fn emit_if_duplicated(
@ -36,7 +36,7 @@ fn check_duplicated_attr(
} }
let Some(ident) = attr.ident() else { return }; let Some(ident) = attr.ident() else { return };
let name = ident.name; 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 // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
// conditions are the same. // conditions are the same.
// `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected.

View File

@ -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::<Vec<_>>();
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);
}
}
}
}
}

View File

@ -1,10 +1,10 @@
use super::utils::is_word;
use super::INLINE_ALWAYS; use super::INLINE_ALWAYS;
use super::utils::is_word;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::Attribute; use rustc_ast::Attribute;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::symbol::Symbol; 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]) { pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
if span.from_expansion() { if span.from_expansion() {

View File

@ -4,7 +4,6 @@ mod blanket_clippy_restriction_lints;
mod deprecated_cfg_attr; mod deprecated_cfg_attr;
mod deprecated_semver; mod deprecated_semver;
mod duplicated_attributes; mod duplicated_attributes;
mod empty_line_after;
mod inline_always; mod inline_always;
mod mixed_attributes_style; mod mixed_attributes_style;
mod non_minimal_cfg; mod non_minimal_cfg;
@ -13,8 +12,8 @@ mod unnecessary_clippy_cfg;
mod useless_attribute; mod useless_attribute;
mod utils; mod utils;
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
@ -126,94 +125,6 @@ declare_clippy_lint! {
"use of `#[deprecated(since = \"x\")]` where x is not semver" "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! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
@ -601,18 +512,12 @@ impl EarlyAttributes {
impl_lint_pass!(EarlyAttributes => [ impl_lint_pass!(EarlyAttributes => [
DEPRECATED_CFG_ATTR, DEPRECATED_CFG_ATTR,
EMPTY_LINE_AFTER_OUTER_ATTR,
EMPTY_LINE_AFTER_DOC_COMMENTS,
NON_MINIMAL_CFG, NON_MINIMAL_CFG,
DEPRECATED_CLIPPY_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR,
UNNECESSARY_CLIPPY_CFG, UNNECESSARY_CLIPPY_CFG,
]); ]);
impl EarlyLintPass for EarlyAttributes { 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) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
deprecated_cfg_attr::check(cx, attr, &self.msrv); deprecated_cfg_attr::check(cx, attr, &self.msrv);
deprecated_cfg_attr::check_clippy(cx, attr); deprecated_cfg_attr::check_clippy(cx, attr);

View File

@ -1,7 +1,7 @@
use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::utils::{extract_clippy_lint, is_lint_level, is_word};
use super::{Attribute, USELESS_ATTRIBUTE}; use super::{Attribute, USELESS_ATTRIBUTE};
use clippy_utils::diagnostics::span_lint_and_then; 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_ast::NestedMetaItem;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind}; use rustc_hir::{Item, ItemKind};
@ -51,6 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute])
| "module_name_repetitions" | "module_name_repetitions"
| "single_component_path_imports" | "single_component_path_imports"
| "disallowed_types" | "disallowed_types"
| "unused_trait_names"
) )
}) { }) {
return; return;

View File

@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::CoroutineLayout; use rustc_middle::mir::CoroutineLayout;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -4,12 +4,12 @@ use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; 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_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_lint::{LateContext, LateLintPass, Level};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -4,7 +4,7 @@ use clippy_utils::ty::expr_sig;
use clippy_utils::{is_default_equivalent, path_def_id}; use clippy_utils::{is_default_equivalent, path_def_id};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; 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_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;

View File

@ -22,7 +22,7 @@ declare_clippy_lint! {
/// ```ignore /// ```ignore
/// b"Hello" /// b"Hello"
/// ``` /// ```
#[clippy::version = "1.68.0"] #[clippy::version = "1.81.0"]
pub BYTE_CHAR_SLICES, pub BYTE_CHAR_SLICES,
style, style,
"hard to read byte char slice" "hard to read byte char slice"

View File

@ -2,7 +2,7 @@ use super::LINT_GROUPS_PRIORITY;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; 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 rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;

View File

@ -10,7 +10,7 @@ use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_middle::ty::{self, FloatTy, Ty};
use rustc_span::hygiene; use rustc_span::hygiene;
use super::{utils, CAST_LOSSLESS}; use super::{CAST_LOSSLESS, utils};
pub(super) fn check( pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,

View File

@ -12,7 +12,7 @@ use rustc_middle::ty::{self, FloatTy, Ty};
use rustc_span::Span; use rustc_span::Span;
use rustc_target::abi::IntegerType; 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<u128> { fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) { if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) {

View File

@ -3,7 +3,7 @@ use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::Ty; 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` // this should be kept in sync with the allowed bit widths of `usize` and `isize`
const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64]; const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64];

View File

@ -4,7 +4,7 @@ use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty}; 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<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
if !cast_from.is_integral() || cast_to.is_integral() { if !cast_from.is_integral() || cast_to.is_integral() {

View File

@ -3,7 +3,7 @@ use std::ops::ControlFlow;
use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint; 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 clippy_utils::{method_chain_args, sext};
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;

View File

@ -5,7 +5,7 @@ use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, UintTy}; 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<'_>) { 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` // We only want to check casts to `ty::Uint` or `ty::Int`

View File

@ -5,7 +5,7 @@ use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty}; 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<'_>) { 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` // We only want to check casts to `ty::Uint` or `ty::Int`

View File

@ -23,8 +23,8 @@ mod unnecessary_cast;
mod utils; mod utils;
mod zero_ptr; mod zero_ptr;
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::is_hir_ty_cfg_dependant; use clippy_utils::is_hir_ty_cfg_dependant;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -410,19 +410,27 @@ declare_clippy_lint! {
/// ### Why is this bad? /// ### Why is this bad?
/// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and /// 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 /// `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 /// ### Example
/// ```no_run /// ```no_run
/// let ptr: *const u32 = &42_u32; /// let ptr: *const u32 = &42_u32;
/// let mut_ptr = ptr as *mut u32; /// let mut_ptr = ptr as *mut u32;
/// let ptr = mut_ptr as *const u32; /// let ptr = mut_ptr as *const u32;
/// let ptr1 = std::ptr::null::<u32>() as *mut u32;
/// let ptr2 = std::ptr::null_mut::<u32>() as *const u32;
/// let ptr3 = std::ptr::null::<u32>().cast_mut();
/// let ptr4 = std::ptr::null_mut::<u32>().cast_const();
/// ``` /// ```
/// Use instead: /// Use instead:
/// ```no_run /// ```no_run
/// let ptr: *const u32 = &42_u32; /// let ptr: *const u32 = &42_u32;
/// let mut_ptr = ptr.cast_mut(); /// let mut_ptr = ptr.cast_mut();
/// let ptr = mut_ptr.cast_const(); /// let ptr = mut_ptr.cast_const();
/// let ptr1 = std::ptr::null_mut::<u32>();
/// let ptr2 = std::ptr::null::<u32>();
/// let ptr3 = std::ptr::null_mut::<u32>();
/// let ptr4 = std::ptr::null::<u32>();
/// ``` /// ```
#[clippy::version = "1.72.0"] #[clippy::version = "1.72.0"]
pub PTR_CAST_CONSTNESS, pub PTR_CAST_CONSTNESS,
@ -809,6 +817,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
char_lit_as_u8::check(cx, expr); char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, &self.msrv); ptr_as_ptr::check(cx, expr, &self.msrv);
cast_slice_different_sizes::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); extract_msrv_attr!(LateContext);

View File

@ -1,10 +1,12 @@
use clippy_config::msrvs::{self, Msrv}; use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::std_or_core;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability}; use rustc_hir::{Expr, ExprKind, Mutability, QPath};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_span::sym;
use super::PTR_CAST_CONSTNESS; use super::PTR_CAST_CONSTNESS;
@ -16,8 +18,7 @@ pub(super) fn check<'tcx>(
cast_to: Ty<'tcx>, cast_to: Ty<'tcx>,
msrv: &Msrv, msrv: &Msrv,
) { ) {
if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind()
&& let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind()
&& let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind()
&& matches!( && matches!(
(from_mutbl, to_mutbl), (from_mutbl, to_mutbl),
@ -26,20 +27,74 @@ pub(super) fn check<'tcx>(
&& from_ty == to_ty && from_ty == to_ty
&& !from_ty.has_erased_regions() && !from_ty.has_erased_regions()
{ {
let sugg = Sugg::hir(cx, cast_expr, "_"); if let ExprKind::Call(func, []) = cast_expr.kind
let constness = match *to_mutbl { && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
Mutability::Not => "const", && let Some(defid) = path.res.opt_def_id()
Mutability::Mut => "mut", && 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( span_lint_and_sugg(
cx, cx,
PTR_CAST_CONSTNESS, PTR_CAST_CONSTNESS,
expr.span, expr.span,
"`as` casting between raw pointers while changing only its constness", "changing constness of a null pointer",
format!("try `pointer::cast_{constness}`, a safer alternative"), format!("use `{method}()` directly instead"),
format!("{}.cast_{constness}()", sugg.maybe_par()), format!("{prefix}::ptr::{method}::<{after_lt}"),
Applicability::MachineApplicable, app,
); );
} }
} }

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg; 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_errors::Applicability;
use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_hir::{Expr, Mutability, Ty, TyKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::source::{snippet_opt, SpanRangeExt}; use clippy_utils::source::{SpanRangeExt, snippet_opt};
use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; 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 clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;

View File

@ -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}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
/// Returns the size in bits of an integral type. /// Returns the size in bits of an integral type.

View File

@ -22,7 +22,7 @@ declare_clippy_lint! {
/// # fn important_check() {} /// # fn important_check() {}
/// important_check(); /// important_check();
/// ``` /// ```
#[clippy::version = "1.73.0"] #[clippy::version = "1.81.0"]
pub CFG_NOT_TEST, pub CFG_NOT_TEST,
restriction, restriction,
"enforce against excluding code from test builds" "enforce against excluding code from test builds"

View File

@ -1,8 +1,8 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; 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_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};

View File

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr_without_closures; 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 core::ops::ControlFlow;
use rustc_ast::ast::Attribute; use rustc_ast::ast::Attribute;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
@ -11,7 +11,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; 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 clippy_utils::{get_enclosing_block, path_to_local_id};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::implements_trait; 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_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;

View File

@ -1,16 +1,17 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; 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::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; use clippy_utils::ty::{InteriorMut, needs_ordered_drop};
use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{ use clippy_utils::{
capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, eq_expr_value, find_binding_init,
is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, 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::iter;
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_errors::Applicability; 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_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;

View File

@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::sym;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,7 +1,7 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_in_test; 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 clippy_utils::source::snippet_with_applicability;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -9,7 +9,7 @@ use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span, SyntaxContext}; use rustc_span::{Span, SyntaxContext, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -49,8 +49,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
crate::attrs::DEPRECATED_SEMVER_INFO, crate::attrs::DEPRECATED_SEMVER_INFO,
crate::attrs::DUPLICATED_ATTRIBUTES_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::INLINE_ALWAYS_INFO,
crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO,
crate::attrs::NON_MINIMAL_CFG_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_LINK_WITH_QUOTES_INFO,
crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_MARKDOWN_INFO,
crate::doc::EMPTY_DOCS_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_ERRORS_DOC_INFO,
crate::doc::MISSING_PANICS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO,
crate::doc::MISSING_SAFETY_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_return::IMPLICIT_RETURN_INFO,
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_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::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO,
crate::incompatible_msrv::INCOMPATIBLE_MSRV_INFO, crate::incompatible_msrv::INCOMPATIBLE_MSRV_INFO,
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_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_async_fn::MANUAL_ASYNC_FN_INFO,
crate::manual_bits::MANUAL_BITS_INFO, crate::manual_bits::MANUAL_BITS_INFO,
crate::manual_clamp::MANUAL_CLAMP_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_FINITE_INFO,
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO,
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_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_let_else::MANUAL_LET_ELSE_INFO,
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_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_FALLIBLE_CONVERSIONS_INFO,
crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO,
crate::methods::UNNECESSARY_FIND_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO,
crate::methods::UNNECESSARY_FIRST_THEN_CHECK_INFO,
crate::methods::UNNECESSARY_FOLD_INFO, crate::methods::UNNECESSARY_FOLD_INFO,
crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO, crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO,
crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_JOIN_INFO,
@ -486,6 +490,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::misc::SHORT_CIRCUIT_STATEMENT_INFO, crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
crate::misc::TOPLEVEL_REF_ARG_INFO, crate::misc::TOPLEVEL_REF_ARG_INFO,
crate::misc::USED_UNDERSCORE_BINDING_INFO, crate::misc::USED_UNDERSCORE_BINDING_INFO,
crate::misc::USED_UNDERSCORE_ITEMS_INFO,
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO, crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
crate::misc_early::DOUBLE_NEG_INFO, crate::misc_early::DOUBLE_NEG_INFO,
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_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_expressive_names::SIMILAR_NAMES_INFO,
crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_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_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::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
crate::octal_escapes::OCTAL_ESCAPES_INFO, crate::octal_escapes::OCTAL_ESCAPES_INFO,
crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_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::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO,
crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_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::precedence::PRECEDENCE_INFO,
crate::ptr::CMP_NULL_INFO, crate::ptr::CMP_NULL_INFO,
crate::ptr::INVALID_NULL_PTR_USAGE_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_result_ok::UNUSED_RESULT_OK_INFO,
crate::unused_rounding::UNUSED_ROUNDING_INFO, crate::unused_rounding::UNUSED_ROUNDING_INFO,
crate::unused_self::UNUSED_SELF_INFO, crate::unused_self::UNUSED_SELF_INFO,
crate::unused_trait_names::UNUSED_TRAIT_NAMES_INFO,
crate::unused_unit::UNUSED_UNIT_INFO, crate::unused_unit::UNUSED_UNIT_INFO,
crate::unwrap::PANICKING_UNWRAP_INFO, crate::unwrap::PANICKING_UNWRAP_INFO,
crate::unwrap::UNNECESSARY_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_div_zero::ZERO_DIVIDED_BY_ZERO_INFO,
crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO, crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO,
crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO, crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO,
crate::zombie_processes::ZOMBIE_PROCESSES_INFO,
]; ];

View File

@ -11,7 +11,7 @@ use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol::{Ident, Symbol}; use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_ty_alias; use clippy_utils::is_ty_alias;
use hir::def::Res;
use hir::ExprKind; use hir::ExprKind;
use hir::def::Res;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};

View File

@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::{last_path_segment, std_or_core}; use clippy_utils::{last_path_segment, std_or_core};
use rustc_errors::Applicability; 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_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::{sym, SyntaxContext}; use rustc_span::{SyntaxContext, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -3,7 +3,7 @@ use clippy_utils::numeric_literal;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability; 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_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;

View File

@ -3,14 +3,14 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::ty::{implements_trait, is_manually_drop}; use clippy_utils::ty::{implements_trait, is_manually_drop};
use clippy_utils::{ use clippy_utils::{
expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local,
ExprUseNode, peel_middle_ty_refs,
}; };
use core::mem; use core::mem;
use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{ use rustc_hir::{
self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
PatKind, Path, QPath, TyKind, UnOp, PatKind, Path, QPath, TyKind, UnOp,
@ -290,13 +290,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
&& let Some(ty) = use_node.defined_ty(cx) && let Some(ty) = use_node.defined_ty(cx)
&& TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable() && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable()
{ {
self.state = Some(( self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
State::ExplicitDeref { mutability: None }, first_expr: expr,
StateData { adjusted_ty,
first_expr: expr, }));
adjusted_ty,
},
));
} }
}, },
RefOp::Method { mutbl, is_ufcs } 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(_))) && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
&& iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
{ {
self.state = Some(( self.state = Some((State::Borrow { mutability }, StateData {
State::Borrow { mutability }, first_expr: expr,
StateData { adjusted_ty,
first_expr: expr, }));
adjusted_ty,
},
));
} }
}, },
_ => {}, _ => {},
@ -508,13 +502,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
let stability = state.stability; let stability = state.stability;
report(cx, expr, State::DerefedBorrow(state), data, typeck); report(cx, expr, State::DerefedBorrow(state), data, typeck);
if stability.is_deref_stable() { if stability.is_deref_stable() {
self.state = Some(( self.state = Some((State::Borrow { mutability }, StateData {
State::Borrow { mutability }, first_expr: expr,
StateData { adjusted_ty,
first_expr: expr, }));
adjusted_ty,
},
));
} }
}, },
(Some((State::DerefedBorrow(state), data)), RefOp::Deref) => { (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
@ -539,13 +530,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
} else if stability.is_deref_stable() } else if stability.is_deref_stable()
&& let Some(parent) = get_parent_expr(cx, expr) && let Some(parent) = get_parent_expr(cx, expr)
{ {
self.state = Some(( self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
State::ExplicitDeref { mutability: None }, first_expr: parent,
StateData { adjusted_ty,
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(outer_pat) = self.ref_locals.get_mut(&local) {
if let Some(pat) = outer_pat { if let Some(pat) = outer_pat {
// Check for auto-deref // Check for auto-deref
if !matches!( if !matches!(cx.typeck_results().expr_adjustments(e), [
cx.typeck_results().expr_adjustments(e), Adjustment {
[ kind: Adjust::Deref(_),
Adjustment {
kind: Adjust::Deref(_),
..
},
Adjustment {
kind: Adjust::Deref(_),
..
},
.. ..
] },
) { Adjustment {
kind: Adjust::Deref(_),
..
},
..
]) {
match get_parent_expr(cx, e) { match get_parent_expr(cx, e) {
// Field accesses are the same no matter the number of references. // Field accesses are the same no matter the number of references.
Some(Expr { Some(Expr {

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::indent_of; use clippy_utils::source::indent_of;
use clippy_utils::{is_default_equivalent, peel_blocks}; use clippy_utils::{is_default_equivalent, peel_blocks};

View File

@ -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 clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def_id::DefId; 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::{ use rustc_hir::{
self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource, 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_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -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<Self> {
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<Span>,
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<Self> {
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<Item = Span> + '_ {
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::<Option<Vec<_>>>()
.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)
}

View File

@ -22,7 +22,6 @@ pub(super) fn check(
range: Range<usize>, range: Range<usize>,
mut span: Span, mut span: Span,
containers: &[super::Container], containers: &[super::Container],
line_break_span: Span,
) { ) {
if doc[range.clone()].contains('\t') { if doc[range.clone()].contains('\t') {
// We don't do tab stops correctly. // We don't do tab stops correctly.
@ -52,29 +51,6 @@ pub(super) fn check(
"doc list item without indentation" "doc list item without indentation"
}; };
span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { 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 { if ccount == 0 && blockquote_level == 0 {
// simpler suggestion style for indentation // simpler suggestion style for indentation
let indent = list_indentation - lcount; let indent = list_indentation - lcount;

View File

@ -3,7 +3,7 @@ use std::ops::Range;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_lint::LateContext; 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<usize>, fragments: Fragments<'_>) { pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'')) if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\''))

View File

@ -5,7 +5,7 @@ use clippy_utils::{is_doc_hidden, return_ty};
use rustc_hir::{BodyId, FnSig, OwnerId, Safety}; use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
pub fn check( pub fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,

View File

@ -23,15 +23,16 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_resolve::rustdoc::{ use rustc_resolve::rustdoc::{
add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range,
DocFragment, span_of_fragments,
}; };
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
use std::ops::Range; use std::ops::Range;
use url::Url; use url::Url;
mod empty_line_after;
mod link_with_quotes; mod link_with_quotes;
mod markdown; mod markdown;
mod missing_headers; mod missing_headers;
@ -449,13 +450,88 @@ declare_clippy_lint! {
/// /// and probably spanning a many rows. /// /// and probably spanning a many rows.
/// struct Foo {} /// struct Foo {}
/// ``` /// ```
#[clippy::version = "1.81.0"] #[clippy::version = "1.82.0"]
pub TOO_LONG_FIRST_DOC_PARAGRAPH, pub TOO_LONG_FIRST_DOC_PARAGRAPH,
style, style,
"ensure that the first line of a documentation paragraph isn't too long" "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 { pub struct Documentation {
valid_idents: FxHashSet<String>, valid_idents: FxHashSet<String>,
check_private_items: bool, check_private_items: bool,
@ -482,6 +558,8 @@ impl_lint_pass!(Documentation => [
SUSPICIOUS_DOC_COMMENTS, SUSPICIOUS_DOC_COMMENTS,
EMPTY_DOCS, EMPTY_DOCS,
DOC_LAZY_CONTINUATION, DOC_LAZY_CONTINUATION,
EMPTY_LINE_AFTER_OUTER_ATTR,
EMPTY_LINE_AFTER_DOC_COMMENTS,
TOO_LONG_FIRST_DOC_PARAGRAPH, TOO_LONG_FIRST_DOC_PARAGRAPH,
]); ]);
@ -612,12 +690,10 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
Some(("fake".into(), "fake".into())) 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; return None;
} }
suspicious_doc_comments::check(cx, attrs);
let (fragments, _) = attrs_to_doc_fragments( let (fragments, _) = attrs_to_doc_fragments(
attrs.iter().filter_map(|attr| { attrs.iter().filter_map(|attr| {
if in_external_macro(cx.sess(), attr.span) { if in_external_macro(cx.sess(), attr.span) {
@ -816,7 +892,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
range.end..next_range.start, range.end..next_range.start,
Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()), Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
&containers[..], &containers[..],
span,
); );
} }
}, },

View File

@ -13,7 +13,7 @@ use rustc_parse::parser::ForceCollect;
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{sym, FileName, Pos}; use rustc_span::{FileName, Pos, sym};
use super::Fragments; use super::Fragments;

View File

@ -7,7 +7,7 @@ use rustc_span::Span;
use super::SUSPICIOUS_DOC_COMMENTS; use super::SUSPICIOUS_DOC_COMMENTS;
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool {
let replacements: Vec<_> = collect_doc_replacements(attrs); let replacements: Vec<_> = collect_doc_replacements(attrs);
if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { 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
} }
} }

View File

@ -79,10 +79,17 @@ pub(super) fn check(
&& let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) && 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(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( diag.span_suggestion(
new_span, new_span,
"add an empty line", "add an empty line",
format!("{snippet}///\n"), format!("{snippet}{comment_form}{snippet}"),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View File

@ -1,17 +1,17 @@
use clippy_utils::diagnostics::span_lint_and_sugg; 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::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
use clippy_utils::{ use clippy_utils::{
can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified,
peel_hir_expr_while, SpanlessEq, peel_hir_expr_while,
}; };
use core::fmt::{self, Write}; use core::fmt::{self, Write};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::hir_id::HirIdSet; 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_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; 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! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -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 clippy_utils::diagnostics::span_lint;
use rustc_hir::{Item, ItemKind}; use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};

View File

@ -1,15 +1,15 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_hir; 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_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause; use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_span::Span;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
pub struct BoxedLocal { pub struct BoxedLocal {

View File

@ -5,8 +5,8 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
declare_clippy_lint! { declare_clippy_lint! {

View File

@ -2,7 +2,7 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use rustc_ast::node_id::NodeSet; 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_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg; 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::source::snippet_with_applicability;
use clippy_utils::{is_expn_of, path_def_id}; use clippy_utils::{is_expn_of, path_def_id};
use rustc_errors::Applicability; 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_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{sym, ExpnId}; use rustc_span::{ExpnId, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -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 clippy_utils::{is_from_proc_macro, trait_ref_of_method};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability; 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::{ use rustc_hir::{
BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
PredicateOrigin, Ty, TyKind, WherePredicate, PredicateOrigin, Ty, TyKind, WherePredicate,
@ -12,8 +12,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::def_id::{DefId, LocalDefId};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -41,7 +41,7 @@ declare_clippy_lint! {
/// } /// }
/// } /// }
/// ``` /// ```
#[clippy::version = "1.78.0"] #[clippy::version = "1.81.0"]
pub FIELD_SCOPED_VISIBILITY_MODIFIERS, pub FIELD_SCOPED_VISIBILITY_MODIFIERS,
restriction, restriction,
"checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields"

View File

@ -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::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{ use clippy_utils::{

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg; 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::macros::{FormatArgsStorage, find_format_arg_expr, root_macro_call_first_node};
use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::source::{SpanRangeExt, snippet_with_context};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span}; use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,11 +1,12 @@
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; 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::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_diag_trait_item; use clippy_utils::is_diag_trait_item;
use clippy_utils::macros::{ use clippy_utils::macros::{
find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span,
is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, 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::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_lang_item}; 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_errors::SuggestionStyle::{CompletelyHidden, ShowCode};
use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition::Edition2021; use rustc_span::edition::Edition::Edition2021;
use rustc_span::{sym, Span, Symbol}; use rustc_span::{Span, Symbol, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; 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 clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_ast::{FormatArgsPiece, FormatTrait};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_span::{sym, Symbol}; use rustc_span::{Symbol, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::higher; use clippy_utils::higher;
use clippy_utils::ty::is_type_lang_item;
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;

View File

@ -1,11 +1,11 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local; use clippy_utils::macros::span_is_local;
use clippy_utils::path_def_id; use clippy_utils::path_def_id;
use clippy_utils::source::SpanRangeExt; use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::intravisit::{Visitor, walk_path};
use rustc_hir::{ use rustc_hir::{
FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path,
PathSegment, Ty, TyKind, PathSegment, Ty, TyKind,

View File

@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::{is_in_const_context, is_integer_literal}; use clippy_utils::{is_in_const_context, is_integer_literal};
use rustc_errors::Applicability; 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_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;

View File

@ -14,8 +14,8 @@ use rustc_hir::intravisit;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::def_id::{DefIdSet, LocalDefId};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::def_id::{DefIdSet, LocalDefId};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty}; 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::attrs::is_proc_macro;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};

View File

@ -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_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;

View File

@ -4,8 +4,8 @@ use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::hir_id::OwnerId; use rustc_hir::hir_id::OwnerId;
use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef}; use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::{Ident, Symbol, kw};
use super::RENAMED_FUNCTION_PARAMS; use super::RENAMED_FUNCTION_PARAMS;

View File

@ -3,11 +3,11 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty}; 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::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::trait_ref_of_method; 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}; use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};

View File

@ -8,7 +8,7 @@ use rustc_middle::ty::print::PrintTraitRefExt;
use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId; 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::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::source::snippet_with_context; 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); snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app);
let closure = if method_name == "then" { "|| " } else { "" }; let closure = if method_name == "then" { "|| " } else { "" };
format!("{closure} {{ {block_snippet}; {arg_snip} }}") format!("{closure} {{ {block_snippet}; {arg_snip} }}")
} else if method_name == "then" {
(std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned()
} else { } else {
arg_snip.into_owned() arg_snip.into_owned()
}; };

View File

@ -3,18 +3,18 @@ use std::collections::BTreeMap;
use rustc_errors::{Applicability, Diag}; use rustc_errors::{Applicability, Diag};
use rustc_hir as hir; 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::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_hir_analysis::lower_ty; use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{Ty, TypeckResults}; use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::sym;
use clippy_utils::diagnostics::span_lint_and_then; 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; use clippy_utils::ty::is_type_diagnostic_item;
declare_clippy_lint! { declare_clippy_lint! {

View File

@ -1,11 +1,17 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_config::Conf;
use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; 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_ast::ast::LitKind;
use rustc_data_structures::packed::Pu128; use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability; 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_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -39,7 +45,49 @@ declare_clippy_lint! {
"Perform saturating subtraction instead of implicitly checking lower bound of data type" "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 { impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { 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 // Check if the conditional expression is a binary operation
&& let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind
// Ensure that the binary operator is >, !=, or <
&& (BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node)
// 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 check_with_condition(cx, expr, cond_op.node, cond_left, cond_right, then);
let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { } else if let Some(higher::If {
if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node { cond,
(cond_left, cond_right) then: if_block,
} else { r#else: Some(else_block),
return; }) = higher::If::hir(expr)
} && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind
} else if SpanlessEq::new(cx).eq_expr(cond_right, target) { {
if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node { check_manual_check(
(cond_right, cond_left) cx, expr, cond_op, cond_left, cond_right, if_block, else_block, &self.msrv,
} else { );
return; }
} }
extract_msrv_attr!(LateContext);
}
#[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,
),
_ => {},
}
}
}
#[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,
);
}
}
struct Var {
span: Span,
hir_id: HirId,
}
impl Var {
fn new(expr: &Expr<'_>) -> Option<Self> {
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)
{
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 { } else {
return; return;
}; }
} else if SpanlessEq::new(cx).eq_expr(cond_right, target) {
// Check if the variable in the condition statement is an integer if BinOpKind::Lt == cond_op || BinOpKind::Ne == cond_op {
if !cx.typeck_results().expr_ty(cond_var).is_integral() { (cond_right, cond_left)
} else {
return; return;
} }
} else {
return;
};
// Get the variable name // Check if the variable in the condition statement is an integer
let var_name = ares_path.segments[0].ident.name.as_str(); if !cx.typeck_results().expr_ty(cond_var).is_integral() {
match cond_num_val.kind { return;
ExprKind::Lit(cond_lit) => { }
// Check if the constant is zero
if let LitKind::Int(Pu128(0), _) = cond_lit.node { // Get the variable name
if cx.typeck_results().expr_ty(cond_left).is_signed() { let var_name = ares_path.segments[0].ident.name.as_str();
} else { match cond_num_val.kind {
print_lint_and_sugg(cx, var_name, expr); 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() {
ExprKind::Path(QPath::TypeRelative(_, name)) => { } else {
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); print_lint_and_sugg(cx, var_name, expr);
} };
}, }
ExprKind::Call(func, []) => { },
if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind ExprKind::Path(QPath::TypeRelative(_, name)) => {
&& name.ident.as_str() == "min_value" if name.ident.as_str() == "MIN"
&& let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) && 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(func_id) && let Some(impl_id) = cx.tcx.impl_of_method(const_id)
&& let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
&& cx.tcx.type_of(impl_id).instantiate_identity().is_integral() && cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
{ {
print_lint_and_sugg(cx, var_name, expr); 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);
}
},
_ => (),
} }
} }
} }

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::Msrv;
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::Msrv;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_in_test; use clippy_utils::is_in_test;
use rustc_attr::{StabilityLevel, StableSince}; use rustc_attr::{StabilityLevel, StableSince};
@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{Expr, ExprKind, HirId}; use rustc_hir::{Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt; 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::def_id::DefId;
use rustc_span::{ExpnKind, Span}; use rustc_span::{ExpnKind, Span};

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet; 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_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId; use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol::Ident;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::Ident;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::{sym, BytePos, Span}; use rustc_span::{BytePos, Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;

Some files were not shown because too many files have changed in this diff Show More