Merge commit 'e18101137866b79045fee0ef996e696e68c920b4' into clippyup

This commit is contained in:
flip1995 2021-11-04 12:52:36 +00:00
parent c2cbf55323
commit e674d0a599
220 changed files with 3219 additions and 1550 deletions

3
.github/deploy.sh vendored
View file

@ -13,7 +13,8 @@ cp util/gh-pages/lints.json out/master
if [[ -n $TAG_NAME ]]; then if [[ -n $TAG_NAME ]]; then
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it" echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
cp -Tr out/master "out/$TAG_NAME" cp -Tr out/master "out/$TAG_NAME"
ln -sf "$TAG_NAME" out/stable rm -f out/stable
ln -s "$TAG_NAME" out/stable
fi fi
if [[ $BETA = "true" ]]; then if [[ $BETA = "true" ]]; then

View file

@ -6,11 +6,162 @@ document.
## Unreleased / In Rust Nightly ## Unreleased / In Rust Nightly
[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master) [b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
## Rust 1.57
Current beta, release 2021-12-02
[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
### New Lints
* [`negative_feature_names`]
[#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
* [`redundant_feature_names`]
[#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
* [`mod_module_files`]
[#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
* [`self_named_module_files`]
[#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
* [`manual_split_once`]
[#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
* [`derivable_impls`]
[#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
* [`needless_option_as_deref`]
[#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
* [`iter_not_returning_iterator`]
[#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
* [`same_name_method`]
[#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
* [`non_send_fields_in_send_ty`]
[#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
* [`equatable_if_let`]
[#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
### Moves and Deprecations
* Move [`shadow_unrelated`] to `restriction`
[#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
* Move [`option_if_let_else`] to `nursery`
[#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
* Move [`branches_sharing_code`] to `nursery`
[#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
`while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
* Move [`many_single_char_names`] to `pedantic`
[#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
* Move [`float_cmp`] to `pedantic`
[#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
* Rename `box_vec` to [`box_collection`] and lint on more general cases
[#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
* Uplift `invalid_atomic_ordering` to rustc
[rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
### Enhancements
* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
limited to certain patterns
[#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
* The `avoid-breaking-exported-api` configuration now also works for
[`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
[`option_option`], [`linkedlist`], [`rc_mutex`]
[#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
* [`unnecessary_unwrap`]: Now also checks for `expect`s
[#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
* [`disallowed_method`]: Allow adding a reason that will be displayed with the
lint message
[#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
[#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
* [`approx_constant`]: Add `TAU`
[#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
* [`needless_borrow`]: Now also lints on needless mutable borrows
[#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
* [`missing_safety_doc`]: Now also lints on unsafe traits
[#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
### False Positive Fixes
* [`manual_map`]: No longer lints when the option is borrowed in the match and
also consumed in the arm
[#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
* [`filter_next`]: No longer lints if `filter` method is not the
`Iterator::filter` method
[#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
* [`manual_flatten`]: No longer lints if expression is used after `if let`
[#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
* [`option_if_let_else`]: Multiple fixes
[#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
* `break` and `continue` statements local to the would-be closure are
allowed
* Don't lint in const contexts
* Don't lint when yield expressions are used
* Don't lint when the captures made by the would-be closure conflict with
the other branch
* Don't lint when a field of a local is used when the type could be
potentially moved from
* In some cases, don't lint when scrutinee expression conflicts with the
captures of the would-be closure
* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
wide pointers with thin pointers
[#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
* [`bool_assert_comparison`]: No longer lints on types that do not implement the
`Not` trait with `Output = bool`
[#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
* [`mut_range_bound`]: No longer lints on range bound mutations, that are
immediately followed by a `break;`
[#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
* [`mutable_key_type`]: Improve accuracy and document remaining false positives
and false negatives
[#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
* [`redundant_closure`]: Rewrite the lint to fix various false positives and
false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
* [`large_enum_variant`]: No longer wrongly identifies the second largest
variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
* [`needless_return`]: No longer lints on let-else expressions
[#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
* [`suspicious_else_formatting`]: No longer lints in proc-macros
[#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
* [`excessive_precision`]: No longer lints when in some cases the float was
already written in the shortest form
[#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
* [`doc_markdown`]: No longer lints on intra-doc links
[#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
### Suggestion Fixes/Improvements
* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
function call in an indexing operation
[#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
* [`manual_split_once`]: Produce semantically equivalent suggestion when
`rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
[#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
* [`manual_assert`]: No better handles complex conditions
[#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
* Correctly handle signs in exponents in numeric literals lints
[#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
[#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
* Drop exponent from suggestion if it is 0 in numeric literals lints
[#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
### ICE Fixes
* [`implicit_hasher`]
[#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
### Others
* Clippy now uses the 2021
[Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
[#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
## Rust 1.56 ## Rust 1.56
Current beta, release 2021-10-21 Current stable, released 2021-10-21
[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e) [74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
@ -74,13 +225,9 @@ Current beta, release 2021-10-21
* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code * [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507) example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
### New Lints
* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
## Rust 1.55 ## Rust 1.55
Current stable, released 2021-09-09 Released 2021-09-09
[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561) [3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
@ -2748,7 +2895,6 @@ Released 2018-09-13
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
@ -2806,6 +2952,7 @@ Released 2018-09-13
[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`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_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
@ -2976,6 +3123,7 @@ Released 2018-09-13
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
@ -3000,6 +3148,7 @@ Released 2018-09-13
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
@ -3046,6 +3195,7 @@ Released 2018-09-13
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`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

View file

@ -262,7 +262,9 @@ to be run inside the `rust` directory):
2. Checkout the commit from the latest available nightly. You can get it using `rustup check`. 2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
3. Sync the changes to the rust-copy of Clippy to your Clippy fork: 3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
```bash ```bash
# Make sure to change `your-github-name` to your github name in the following command # Make sure to change `your-github-name` to your github name in the following command. Also be
# sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
# because changes cannot be fast forwarded
git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
``` ```

View file

@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true }
[dev-dependencies] [dev-dependencies]
cargo_metadata = "0.14" cargo_metadata = "0.14"
compiletest_rs = { version = "0.7", features = ["tmp"] } compiletest_rs = { version = "0.7.1", features = ["tmp"] }
tester = "0.9" tester = "0.9"
regex = "1.5" regex = "1.5"
# This is used by the `collect-metadata` alias. # This is used by the `collect-metadata` alias.

View file

@ -42,7 +42,8 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str
}; };
create_lint(&lint, msrv).context("Unable to create lint implementation")?; create_lint(&lint, msrv).context("Unable to create lint implementation")?;
create_test(&lint).context("Unable to create a test for the new lint") create_test(&lint).context("Unable to create a test for the new lint")?;
add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
} }
fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
@ -80,6 +81,33 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
} }
} }
fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
let path = "clippy_lints/src/lib.rs";
let mut lib_rs = fs::read_to_string(path).context("reading")?;
let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
let new_lint = if enable_msrv {
format!(
"store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ",
lint_pass = lint.pass,
module_name = lint.name,
camel_name = to_camel_case(lint.name),
)
} else {
format!(
"store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ",
lint_pass = lint.pass,
module_name = lint.name,
camel_name = to_camel_case(lint.name),
)
};
lib_rs.insert_str(comment_start, &new_lint);
fs::write(path, lib_rs).context("writing")
}
fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
OpenOptions::new() OpenOptions::new()
@ -151,7 +179,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
}; };
let lint_name = lint.name; let lint_name = lint.name;
let pass_name = lint.pass;
let category = lint.category; let category = lint.category;
let name_camel = to_camel_case(lint.name); let name_camel = to_camel_case(lint.name);
let name_upper = lint_name.to_uppercase(); let name_upper = lint_name.to_uppercase();
@ -228,18 +255,14 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
extract_msrv_attr!({context_import}); extract_msrv_attr!({context_import});
}} }}
// TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
// e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv)));
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
// TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
"}, "},
pass_type = pass_type, pass_type = pass_type,
pass_lifetimes = pass_lifetimes, pass_lifetimes = pass_lifetimes,
pass_name = pass_name,
name_upper = name_upper, name_upper = name_upper,
name_camel = name_camel, name_camel = name_camel,
module_name = lint_name,
context_import = context_import, context_import = context_import,
) )
} else { } else {
@ -248,16 +271,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
declare_lint_pass!({name_camel} => [{name_upper}]); declare_lint_pass!({name_camel} => [{name_upper}]);
impl {pass_type}{pass_lifetimes} for {name_camel} {{}} impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
//
// TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
// e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel}));
"}, "},
pass_type = pass_type, pass_type = pass_type,
pass_lifetimes = pass_lifetimes, pass_lifetimes = pass_lifetimes,
pass_name = pass_name,
name_upper = name_upper, name_upper = name_upper,
name_camel = name_camel, name_camel = name_camel,
module_name = lint_name,
) )
}); });

View file

@ -1,15 +1,88 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::expr_or_init;
use clippy_utils::ty::is_isize_or_usize; use clippy_utils::ty::is_isize_or_usize;
use rustc_hir::Expr; use rustc_hir::{BinOpKind, Expr, ExprKind};
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_POSSIBLE_TRUNCATION}; use super::{utils, CAST_POSSIBLE_TRUNCATION};
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
Some(c)
} else {
None
}
}
fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> {
constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros()))
}
fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 {
match expr_or_init(cx, expr).kind {
ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed),
ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
ExprKind::Binary(op, left, right) => match op.node {
BinOpKind::Div => {
apply_reductions(cx, nbits, left, signed)
- (if signed {
0 // let's be conservative here
} else {
// by dividing by 1, we remove 0 bits, etc.
get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
})
},
BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
.unwrap_or(u64::max_value())
.min(apply_reductions(cx, nbits, left, signed)),
BinOpKind::Shr => {
apply_reductions(cx, nbits, left, signed)
- constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
},
_ => nbits,
},
ExprKind::MethodCall(method, _, [left, right], _) => {
if signed {
return nbits;
}
let max_bits = if method.ident.as_str() == "min" {
get_constant_bits(cx, right)
} else {
None
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
},
ExprKind::MethodCall(method, _, [_, lo, hi], _) => {
if method.ident.as_str() == "clamp" {
//FIXME: make this a diagnostic item
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
return lo_bits.max(hi_bits);
}
}
nbits
},
ExprKind::MethodCall(method, _, [_value], _) => {
if method.ident.name.as_str() == "signum" {
0 // do not lint if cast comes from a `signum` function
} else {
nbits
}
},
_ => nbits,
}
}
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
let msg = match (cast_from.is_integral(), cast_to.is_integral()) { let msg = match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => { (true, true) => {
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); let from_nbits = apply_reductions(
cx,
utils::int_ty_to_nbits(cast_from, cx.tcx),
cast_expr,
cast_from.is_signed(),
);
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {

View file

@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
cast_possible_truncation::check(cx, expr, cast_from, cast_to); cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);

View file

@ -1,3 +1,6 @@
// NOTE: if you add a deprecated lint in this file, please add a corresponding test in
// tests/ui/deprecated.rs
/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This /// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
/// enables the simple extraction of the metadata without changing the current deprecation /// enables the simple extraction of the metadata without changing the current deprecation
/// declaration. /// declaration.

View file

@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
target_mut, target_mut,
}, },
)); ));
} },
_ => (), _ => (),
} }
}, },

View file

@ -1,6 +1,6 @@
use clippy_utils::attrs::is_doc_hidden; use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::first_line_of_span; use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
use if_chain::if_chain; use if_chain::if_chain;
@ -10,7 +10,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter; use rustc_errors::emitter::EmitterWriter;
use rustc_errors::Handler; use rustc_errors::{Applicability, Handler};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{AnonConst, Expr, ExprKind, QPath}; use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
@ -48,7 +48,7 @@ declare_clippy_lint! {
/// content are not linted. /// content are not linted.
/// ///
/// In addition, when writing documentation comments, including `[]` brackets /// In addition, when writing documentation comments, including `[]` brackets
/// inside a link text would trip the parser. Therfore, documenting link with /// inside a link text would trip the parser. Therefore, documenting link with
/// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
/// would fail. /// would fail.
/// ///
@ -578,9 +578,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
// text "http://example.com" by pulldown-cmark // text "http://example.com" by pulldown-cmark
continue; continue;
} }
headers.safety |= in_heading && text.trim() == "Safety"; let trimmed_text = text.trim();
headers.errors |= in_heading && text.trim() == "Errors"; headers.safety |= in_heading && trimmed_text == "Safety";
headers.panics |= in_heading && text.trim() == "Panics"; headers.safety |= in_heading && trimmed_text == "Implementation safety";
headers.safety |= in_heading && trimmed_text == "Implementation Safety";
headers.errors |= in_heading && trimmed_text == "Errors";
headers.panics |= in_heading && trimmed_text == "Panics";
if in_code { if in_code {
if is_rust { if is_rust {
let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition()); let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
@ -686,10 +689,18 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str
for word in text.split(|c: char| c.is_whitespace() || c == '\'') { for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
// Trim punctuation as in `some comment (see foo::bar).` // Trim punctuation as in `some comment (see foo::bar).`
// ^^ // ^^
// Or even as in `_foo bar_` which is emphasized. // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
let word = word.trim_matches(|c: char| !c.is_alphanumeric()); let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
if valid_idents.contains(word) { // Remove leading or trailing single `:` which may be part of a sentence.
if word.starts_with(':') && !word.starts_with("::") {
word = word.trim_start_matches(':');
}
if word.ends_with(':') && !word.ends_with("::") {
word = word.trim_end_matches(':');
}
if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
continue; continue;
} }
@ -744,17 +755,22 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
} }
} }
// We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343) // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
if has_underscore(word) && has_hyphen(word) { if has_underscore(word) && has_hyphen(word) {
return; return;
} }
if has_underscore(word) || word.contains("::") || is_camel_case(word) { if has_underscore(word) || word.contains("::") || is_camel_case(word) {
span_lint( let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx, cx,
DOC_MARKDOWN, DOC_MARKDOWN,
span, span,
&format!("you should put `{}` between ticks in the documentation", word), "item in documentation is missing backticks",
"try",
format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
applicability,
); );
} }
} }
@ -793,9 +809,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
// check for `unwrap` // check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option) if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.cx, reciever_ty, sym::Result) || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
{ {
self.panic_span = Some(expr.span); self.panic_span = Some(expr.span);
} }

View file

@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map
ExprKind::MethodCall( ExprKind::MethodCall(
_, _,
_, _,
[map, Expr { [
kind: ExprKind::AddrOf(_, _, key), map,
span: key_span, Expr {
.. kind: ExprKind::AddrOf(_, _, key),
}], span: key_span,
..
},
],
_, _,
) if key_span.ctxt() == expr.span.ctxt() => { ) if key_span.ctxt() == expr.span.ctxt() => {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;

View file

@ -1,8 +1,8 @@
//! lint on enum variants that are prefixed or suffixed by the same characters //! lint on enum variants that are prefixed or suffixed by the same characters
use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source; use clippy_utils::source::is_present_in_source;
use clippy_utils::str_utils::{self, count_match_end, count_match_start};
use rustc_hir::{EnumDef, Item, ItemKind}; use rustc_hir::{EnumDef, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [
MODULE_INCEPTION MODULE_INCEPTION
]); ]);
/// Returns the number of chars that match from the start
#[must_use]
fn partial_match(pre: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next_back(); // make sure the name is never fully matched
pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
}
/// Returns the number of chars that match from the end
#[must_use]
fn partial_rmatch(post: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next(); // make sure the name is never fully matched
post.chars()
.rev()
.zip(name_iter.rev())
.take_while(|&(l, r)| l == r)
.count()
}
fn check_variant( fn check_variant(
cx: &LateContext<'_>, cx: &LateContext<'_>,
threshold: u64, threshold: u64,
@ -150,7 +130,7 @@ fn check_variant(
} }
for var in def.variants { for var in def.variants {
let name = var.ident.name.as_str(); let name = var.ident.name.as_str();
if partial_match(item_name, &name) == item_name_chars if count_match_start(item_name, &name).char_count == item_name_chars
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
{ {
@ -161,7 +141,7 @@ fn check_variant(
"variant name starts with the enum's name", "variant name starts with the enum's name",
); );
} }
if partial_rmatch(item_name, &name) == item_name_chars { if count_match_end(item_name, &name).char_count == item_name_chars {
span_lint( span_lint(
cx, cx,
ENUM_VARIANT_NAMES, ENUM_VARIANT_NAMES,
@ -171,14 +151,14 @@ fn check_variant(
} }
} }
let first = &def.variants[0].ident.name.as_str(); let first = &def.variants[0].ident.name.as_str();
let mut pre = &first[..camel_case::until(&*first)]; let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
let mut post = &first[camel_case::from(&*first)..]; let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
for var in def.variants { for var in def.variants {
let name = var.ident.name.as_str(); let name = var.ident.name.as_str();
let pre_match = partial_match(pre, &name); let pre_match = count_match_start(pre, &name).byte_count;
pre = &pre[..pre_match]; pre = &pre[..pre_match];
let pre_camel = camel_case::until(pre); let pre_camel = str_utils::camel_case_until(pre).byte_index;
pre = &pre[..pre_camel]; pre = &pre[..pre_camel];
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
if next.is_numeric() { if next.is_numeric() {
@ -186,18 +166,18 @@ fn check_variant(
} }
if next.is_lowercase() { if next.is_lowercase() {
let last = pre.len() - last.len_utf8(); let last = pre.len() - last.len_utf8();
let last_camel = camel_case::until(&pre[..last]); let last_camel = str_utils::camel_case_until(&pre[..last]);
pre = &pre[..last_camel]; pre = &pre[..last_camel.byte_index];
} else { } else {
break; break;
} }
} }
let post_match = partial_rmatch(post, &name); let post_match = count_match_end(post, &name);
let post_end = post.len() - post_match; let post_end = post.len() - post_match.byte_count;
post = &post[post_end..]; post = &post[post_end..];
let post_camel = camel_case::from(post); let post_camel = str_utils::camel_case_start(post);
post = &post[post_camel..]; post = &post[post_camel.byte_index..];
} }
let (what, value) = match (pre.is_empty(), post.is_empty()) { let (what, value) = match (pre.is_empty(), post.is_empty()) {
(true, true) => return, (true, true) => return,
@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames {
); );
} }
} }
if item.vis.node.is_pub() { // The `module_name_repetitions` lint should only trigger if the item has the module in its
let matching = partial_match(mod_camel, &item_camel); // name. Having the same name is accepted.
let rmatching = partial_rmatch(mod_camel, &item_camel); if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count(); let nchars = mod_camel.chars().count();
let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric(); let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
if matching == nchars { if matching.char_count == nchars {
match item_camel.chars().nth(nchars) { match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) => span_lint( Some(c) if is_word_beginning(c) => span_lint(
cx, cx,
@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames {
_ => (), _ => (),
} }
} }
if rmatching == nchars { if rmatching.char_count == nchars {
span_lint( span_lint(
cx, cx,
MODULE_NAME_REPETITIONS, MODULE_NAME_REPETITIONS,

View file

@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
} }
match *cx.typeck_results().expr_adjustments(arg) { match *cx.typeck_results().expr_adjustments(arg) {
[] => true, [] => true,
[Adjustment { [
kind: Adjust::Deref(None), Adjustment {
.. kind: Adjust::Deref(None),
}, Adjustment { ..
kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), },
.. Adjustment {
}] => { kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
..
},
] => {
// re-borrow with the same mutability is allowed // re-borrow with the same mutability is allowed
let ty = cx.typeck_results().expr_ty(arg); let ty = cx.typeck_results().expr_ty(arg);
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into()) matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())

View file

@ -49,15 +49,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
if format_args.value_args.is_empty() { if format_args.value_args.is_empty() {
if_chain! { if format_args.format_string_parts.is_empty() {
if let [e] = &*format_args.format_string_parts; span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
if let ExprKind::Lit(lit) = &e.kind; } else {
if let Some(s_src) = snippet_opt(cx, lit.span); if_chain! {
then { if let [e] = &*format_args.format_string_parts;
// Simulate macro expansion, converting {{ and }} to { and }. if let ExprKind::Lit(lit) = &e.kind;
let s_expand = s_src.replace("{{", "{").replace("}}", "}"); if let Some(s_src) = snippet_opt(cx, lit.span);
let sugg = format!("{}.to_string()", s_expand); then {
span_useless_format(cx, call_site, sugg, applicability); // Simulate macro expansion, converting {{ and }} to { and }.
let s_expand = s_src.replace("{{", "{").replace("}}", "}");
let sugg = format!("{}.to_string()", s_expand);
span_useless_format(cx, call_site, sugg, applicability);
}
} }
} }
} else if let [value] = *format_args.value_args { } else if let [value] = *format_args.value_args {
@ -89,6 +93,18 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
} }
} }
fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
span_lint_and_sugg(
cx,
USELESS_FORMAT,
span,
"useless use of `format!`",
"consider using `String::new()`",
sugg,
applicability,
);
}
fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,

View file

@ -2,9 +2,9 @@
//! on the condition //! on the condition
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp}; use clippy_utils::is_else_clause;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_middle::lint::in_external_macro; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! { declare_clippy_lint! {
@ -46,14 +46,21 @@ declare_clippy_lint! {
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]); declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
impl EarlyLintPass for IfNotElse { impl LateLintPass<'_> for IfNotElse {
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
if in_external_macro(cx.sess, item.span) { // While loops will be desugared to ExprKind::If. This will cause the lint to fire.
// To fix this, return early if this span comes from a macro or desugaring.
if item.span.from_expansion() {
return; return;
} }
if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind { if let ExprKind::If(cond, _, Some(els)) = item.kind {
if let ExprKind::Block(..) = els.kind { if let ExprKind::Block(..) = els.kind {
match cond.kind { // Disable firing the lint in "else if" expressions.
if is_else_clause(cx.tcx, item) {
return;
}
match cond.peel_drop_temps().kind {
ExprKind::Unary(UnOp::Not, _) => { ExprKind::Unary(UnOp::Not, _) => {
span_lint_and_help( span_lint_and_help(
cx, cx,

View file

@ -89,7 +89,7 @@ impl IntPlusOne {
}, },
_ => None, _ => None,
} }
} },
// case where `x + 1 <= ...` or `1 + x <= ...` // case where `x + 1 <= ...` or `1 + x <= ...`
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
if lhskind.node == BinOpKind::Add => if lhskind.node == BinOpKind::Add =>
@ -104,7 +104,7 @@ impl IntPlusOne {
}, },
_ => None, _ => None,
} }
} },
// case where `... >= y - 1` or `... >= -1 + y` // case where `... >= y - 1` or `... >= -1 + y`
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {

View file

@ -1,5 +1,3 @@
use std::cmp::Ordering;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
@ -7,11 +5,11 @@ use rustc_middle::ty::{self, IntTy, UintTy};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span; use rustc_span::Span;
use clippy_utils::comparisons;
use clippy_utils::comparisons::Rel; use clippy_utils::comparisons::Rel;
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::{comparisons, sext};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -39,53 +37,6 @@ declare_clippy_lint! {
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]); declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
#[derive(Copy, Clone, Debug, Eq)]
enum FullInt {
S(i128),
U(u128),
}
impl FullInt {
#[allow(clippy::cast_sign_loss)]
#[must_use]
fn cmp_s_u(s: i128, u: u128) -> Ordering {
if s < 0 {
Ordering::Less
} else if u > (i128::MAX as u128) {
Ordering::Greater
} else {
(s as u128).cmp(&u)
}
}
}
impl PartialEq for FullInt {
#[must_use]
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
}
}
impl PartialOrd for FullInt {
#[must_use]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(match (self, other) {
(&Self::S(s), &Self::S(o)) => s.cmp(&o),
(&Self::U(s), &Self::U(o)) => s.cmp(&o),
(&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
(&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
})
}
}
impl Ord for FullInt {
#[must_use]
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other)
.expect("`partial_cmp` for FullInt can never return `None`")
}
}
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> { fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(cast_exp, _) = expr.kind { if let ExprKind::Cast(cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp); let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
@ -118,19 +69,6 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) ->
} }
} }
fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
let val = constant(cx, cx.typeck_results(), expr)?.0;
if let Constant::Int(const_int) = val {
match *cx.typeck_results().expr_ty(expr).kind() {
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
ty::Uint(_) => Some(FullInt::U(const_int)),
_ => None,
}
} else {
None
}
}
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) { fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
if let ExprKind::Cast(cast_val, _) = expr.kind { if let ExprKind::Cast(cast_val, _) = expr.kind {
span_lint( span_lint(
@ -156,7 +94,7 @@ fn upcast_comparison_bounds_err<'tcx>(
invert: bool, invert: bool,
) { ) {
if let Some((lb, ub)) = lhs_bounds { if let Some((lb, ub)) = lhs_bounds {
if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
if rel == Rel::Eq || rel == Rel::Ne { if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub { if norm_rhs_val < lb || norm_rhs_val > ub {
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);

View file

@ -76,7 +76,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(get_last_with_len::GET_LAST_WITH_LEN), LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
LintId::of(identity_op::IDENTITY_OP), LintId::of(identity_op::IDENTITY_OP),
LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(if_let_mutex::IF_LET_MUTEX),
LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER), LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(inherent_to_string::INHERENT_TO_STRING),
@ -218,6 +217,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@ -282,6 +282,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC), LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_ARG), LintId::of(unit_types::UNIT_ARG),
LintId::of(unit_types::UNIT_CMP), LintId::of(unit_types::UNIT_CMP),

View file

@ -64,6 +64,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC), LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP), LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),

View file

@ -159,7 +159,6 @@ store.register_lints(&[
identity_op::IDENTITY_OP, identity_op::IDENTITY_OP,
if_let_mutex::IF_LET_MUTEX, if_let_mutex::IF_LET_MUTEX,
if_not_else::IF_NOT_ELSE, if_not_else::IF_NOT_ELSE,
if_then_panic::IF_THEN_PANIC,
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
implicit_hasher::IMPLICIT_HASHER, implicit_hasher::IMPLICIT_HASHER,
implicit_return::IMPLICIT_RETURN, implicit_return::IMPLICIT_RETURN,
@ -216,6 +215,7 @@ store.register_lints(&[
loops::WHILE_LET_ON_ITERATOR, loops::WHILE_LET_ON_ITERATOR,
macro_use::MACRO_USE_IMPORTS, macro_use::MACRO_USE_IMPORTS,
main_recursion::MAIN_RECURSION, main_recursion::MAIN_RECURSION,
manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN, manual_async_fn::MANUAL_ASYNC_FN,
manual_map::MANUAL_MAP, manual_map::MANUAL_MAP,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
@ -327,6 +327,7 @@ store.register_lints(&[
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS, misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_PATTERN, misc_early::REDUNDANT_PATTERN,
misc_early::SEPARATED_LITERAL_SUFFIX,
misc_early::UNNEEDED_FIELD_PATTERN, misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::UNSEPARATED_LITERAL_SUFFIX, misc_early::UNSEPARATED_LITERAL_SUFFIX,
@ -431,6 +432,7 @@ store.register_lints(&[
strings::STRING_ADD_ASSIGN, strings::STRING_ADD_ASSIGN,
strings::STRING_FROM_UTF8_AS_BYTES, strings::STRING_FROM_UTF8_AS_BYTES,
strings::STRING_LIT_AS_BYTES, strings::STRING_LIT_AS_BYTES,
strings::STRING_SLICE,
strings::STRING_TO_STRING, strings::STRING_TO_STRING,
strings::STR_TO_STRING, strings::STR_TO_STRING,
strlen_on_c_strings::STRLEN_ON_C_STRINGS, strlen_on_c_strings::STRLEN_ON_C_STRINGS,
@ -476,6 +478,7 @@ store.register_lints(&[
unicode::NON_ASCII_LITERAL, unicode::NON_ASCII_LITERAL,
unicode::UNICODE_NOT_NFC, unicode::UNICODE_NOT_NFC,
uninit_vec::UNINIT_VEC, uninit_vec::UNINIT_VEC,
unit_hash::UNIT_HASH,
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
unit_types::LET_UNIT_VALUE, unit_types::LET_UNIT_VALUE,
unit_types::UNIT_ARG, unit_types::UNIT_ARG,

View file

@ -17,7 +17,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_INTEGER), LintId::of(mutex_atomic::MUTEX_INTEGER),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),

View file

@ -48,6 +48,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(loops::EXPLICIT_ITER_LOOP), LintId::of(loops::EXPLICIT_ITER_LOOP),
LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(macro_use::MACRO_USE_IMPORTS),
LintId::of(manual_assert::MANUAL_ASSERT),
LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(manual_ok_or::MANUAL_OK_OR),
LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_BOOL),
@ -65,7 +66,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(methods::MAP_UNWRAP_OR), LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(misc::FLOAT_CMP), LintId::of(misc::FLOAT_CMP),
LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(misc::USED_UNDERSCORE_BINDING),
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(mut_mut::MUT_MUT), LintId::of(mut_mut::MUT_MUT),
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
@ -88,7 +88,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST), LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION), LintId::of(types::OPTION_OPTION),
LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unicode::UNICODE_NOT_NFC), LintId::of(unicode::UNICODE_NOT_NFC),
LintId::of(unit_types::LET_UNIT_VALUE), LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),

View file

@ -35,7 +35,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(methods::GET_UNWRAP), LintId::of(methods::GET_UNWRAP),
LintId::of(methods::UNWRAP_USED), LintId::of(methods::UNWRAP_USED),
LintId::of(misc::FLOAT_CMP_CONST), LintId::of(misc::FLOAT_CMP_CONST),
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
@ -53,11 +55,13 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(shadow::SHADOW_SAME), LintId::of(shadow::SHADOW_SAME),
LintId::of(shadow::SHADOW_UNRELATED), LintId::of(shadow::SHADOW_UNRELATED),
LintId::of(strings::STRING_ADD), LintId::of(strings::STRING_ADD),
LintId::of(strings::STRING_SLICE),
LintId::of(strings::STRING_TO_STRING), LintId::of(strings::STRING_TO_STRING),
LintId::of(strings::STR_TO_STRING), LintId::of(strings::STR_TO_STRING),
LintId::of(types::RC_BUFFER), LintId::of(types::RC_BUFFER),
LintId::of(types::RC_MUTEX), LintId::of(types::RC_MUTEX),
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS), LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
LintId::of(verbose_file_reads::VERBOSE_FILE_READS), LintId::of(verbose_file_reads::VERBOSE_FILE_READS),

View file

@ -27,7 +27,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::RESULT_UNIT_ERR),
LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(len_zero::COMPARISON_TO_EMPTY), LintId::of(len_zero::COMPARISON_TO_EMPTY),
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),

View file

@ -15,6 +15,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(loops::MUT_RANGE_BOUND), LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
]) ])

View file

@ -228,7 +228,6 @@ mod get_last_with_len;
mod identity_op; mod identity_op;
mod if_let_mutex; mod if_let_mutex;
mod if_not_else; mod if_not_else;
mod if_then_panic;
mod if_then_some_else_none; mod if_then_some_else_none;
mod implicit_hasher; mod implicit_hasher;
mod implicit_return; mod implicit_return;
@ -255,6 +254,7 @@ mod literal_representation;
mod loops; mod loops;
mod macro_use; mod macro_use;
mod main_recursion; mod main_recursion;
mod manual_assert;
mod manual_async_fn; mod manual_async_fn;
mod manual_map; mod manual_map;
mod manual_non_exhaustive; mod manual_non_exhaustive;
@ -364,6 +364,7 @@ mod undocumented_unsafe_blocks;
mod undropped_manually_drops; mod undropped_manually_drops;
mod unicode; mod unicode;
mod uninit_vec; mod uninit_vec;
mod unit_hash;
mod unit_return_expecting_ord; mod unit_return_expecting_ord;
mod unit_types; mod unit_types;
mod unnamed_address; mod unnamed_address;
@ -522,6 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch)); store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
store.register_late_pass(|| Box::new(unicode::Unicode)); store.register_late_pass(|| Box::new(unicode::Unicode));
store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
store.register_late_pass(|| Box::new(unit_hash::UnitHash));
store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(strings::StringAdd));
store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
@ -666,7 +668,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::new(double_parens::DoubleParens)); store.register_early_pass(|| Box::new(double_parens::DoubleParens));
store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new())); store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
store.register_early_pass(|| Box::new(formatting::Formatting)); store.register_early_pass(|| Box::new(formatting::Formatting));
@ -720,6 +721,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems)); store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
@ -770,14 +772,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
store.register_late_pass(move || Box::new(feature_name::FeatureName)); store.register_late_pass(move || Box::new(feature_name::FeatureName));
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic)); store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
store.register_late_pass(move || Box::new(format_args::FormatArgs)); store.register_late_pass(move || Box::new(format_args::FormatArgs));
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
// add lints here, do not remove this comment, it's used in `new_lint`
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -828,6 +830,7 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
/// ///
/// Used in `./src/driver.rs`. /// Used in `./src/driver.rs`.
pub fn register_renamed(ls: &mut rustc_lint::LintStore) { pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
// NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions"); ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default"); ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"); ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");

View file

@ -378,11 +378,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
match ty.kind { match ty.kind {
TyKind::OpaqueDef(item, _) => { TyKind::OpaqueDef(item, bounds) => {
let map = self.cx.tcx.hir(); let map = self.cx.tcx.hir();
let item = map.item(item); let item = map.item(item);
walk_item(self, item); walk_item(self, item);
walk_ty(self, ty); walk_ty(self, ty);
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
_ => None,
}));
}, },
TyKind::BareFn(&BareFnTy { decl, .. }) => { TyKind::BareFn(&BareFnTy { decl, .. }) => {
let mut sub_visitor = RefVisitor::new(self.cx); let mut sub_visitor = RefVisitor::new(self.cx);

View file

@ -338,7 +338,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(), sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
meth_name, meth_name,
) )
} },
_ => format!( _ => format!(
"{}.into_iter()", "{}.into_iter()",
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()

View file

@ -26,14 +26,14 @@ declare_clippy_lint! {
/// let sad_people: Vec<&str> = vec![]; /// let sad_people: Vec<&str> = vec![];
/// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
/// ``` /// ```
pub IF_THEN_PANIC, pub MANUAL_ASSERT,
style, pedantic,
"`panic!` and only a `panic!` in `if`-then statement" "`panic!` and only a `panic!` in `if`-then statement"
} }
declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]); declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
impl LateLintPass<'_> for IfThenPanic { impl LateLintPass<'_> for ManualAssert {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! { if_chain! {
if let Expr { if let Expr {
@ -54,23 +54,24 @@ impl LateLintPass<'_> for IfThenPanic {
if !cx.tcx.sess.source_map().is_multiline(cond.span); if !cx.tcx.sess.source_map().is_multiline(cond.span);
then { then {
let span = if let Some(panic_expn) = PanicExpn::parse(semi) { let call = if_chain! {
if let ExprKind::Block(block, _) = semi.kind;
if let Some(init) = block.expr;
then {
init
} else {
semi
}
};
let span = if let Some(panic_expn) = PanicExpn::parse(call) {
match *panic_expn.format_args.value_args { match *panic_expn.format_args.value_args {
[] => panic_expn.format_args.format_string_span, [] => panic_expn.format_args.format_string_span,
[.., last] => panic_expn.format_args.format_string_span.to(last.span), [.., last] => panic_expn.format_args.format_string_span.to(last.span),
} }
} else if let ExprKind::Call(_, [format_args]) = call.kind {
format_args.span
} else { } else {
if_chain! { return
if let ExprKind::Block(block, _) = semi.kind;
if let Some(init) = block.expr;
if let ExprKind::Call(_, [format_args]) = init.kind;
then {
format_args.span
} else {
return
}
}
}; };
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
@ -86,7 +87,7 @@ impl LateLintPass<'_> for IfThenPanic {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
IF_THEN_PANIC, MANUAL_ASSERT,
expr.span, expr.span,
"only a `panic!` in `if`-then statement", "only a `panic!` in `if`-then statement",
"try", "try",

View file

@ -127,10 +127,10 @@ fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> { fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> {
let case_check = match case_method { let case_check = match case_method {
CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) }, CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) }, CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) }, CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) }, CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
}; };
for arm in arms { for arm in arms {
@ -153,7 +153,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) { fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
let (method_str, suggestion) = match case_method { let (method_str, suggestion) = match case_method {
CaseMethod::LowerCase => ("to_lower_case", bad_case_str.to_lowercase()), CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()), CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()), CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()), CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),

View file

@ -1,4 +1,4 @@
use clippy_utils::consts::{constant, miri_to_const, Constant}; use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
use clippy_utils::diagnostics::{ use clippy_utils::diagnostics::{
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
}; };
@ -930,9 +930,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() { if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex)); let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
let type_ranges = type_ranges(&ranges); if !ranges.is_empty() {
if !type_ranges.is_empty() { if let Some((start, end)) = overlapping(&ranges) {
if let Some((start, end)) = overlapping(&type_ranges) {
span_lint_and_note( span_lint_and_note(
cx, cx,
MATCH_OVERLAPPING_ARM, MATCH_OVERLAPPING_ARM,
@ -968,8 +967,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
} }
if_chain! { if_chain! {
if matching_wild; if matching_wild;
if let ExprKind::Block(block, _) = arm.body.kind; if is_panic_call(arm.body);
if is_panic_block(block);
then { then {
// `Err(_)` or `Err(_e)` arm with `panic!` found // `Err(_)` or `Err(_e)` arm with `panic!` found
span_lint_and_note(cx, span_lint_and_note(cx,
@ -1172,14 +1170,19 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
} }
// If the block contains only a `panic!` macro (as expression or statement) // If the block contains only a `panic!` macro (as expression or statement)
fn is_panic_block(block: &Block<'_>) -> bool { fn is_panic_call(expr: &Expr<'_>) -> bool {
match (&block.expr, block.stmts.len(), block.stmts.first()) { // Unwrap any wrapping blocks
(&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(), let span = if let ExprKind::Block(block, _) = expr.kind {
(&None, 1, Some(stmt)) => { match (&block.expr, block.stmts.len(), block.stmts.first()) {
is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none() (&Some(exp), 0, _) => exp.span,
}, (&None, 1, Some(stmt)) => stmt.span,
_ => false, _ => return false,
} }
} else {
expr.span
};
is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
} }
fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
@ -1601,7 +1604,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
} }
/// Gets all arms that are unbounded `PatRange`s. /// Gets all arms that are unbounded `PatRange`s.
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> { fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
arms.iter() arms.iter()
.filter_map(|arm| { .filter_map(|arm| {
if let Arm { pat, guard: None, .. } = *arm { if let Arm { pat, guard: None, .. } = *arm {
@ -1614,21 +1617,25 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
}; };
let rhs = match range_end {
RangeEnd::Included => Bound::Included(rhs), let lhs_val = lhs.int_value(cx, ty)?;
RangeEnd::Excluded => Bound::Excluded(rhs), let rhs_val = rhs.int_value(cx, ty)?;
let rhs_bound = match range_end {
RangeEnd::Included => Bound::Included(rhs_val),
RangeEnd::Excluded => Bound::Excluded(rhs_val),
}; };
return Some(SpannedRange { return Some(SpannedRange {
span: pat.span, span: pat.span,
node: (lhs, rhs), node: (lhs_val, rhs_bound),
}); });
} }
if let PatKind::Lit(value) = pat.kind { if let PatKind::Lit(value) = pat.kind {
let value = constant(cx, cx.typeck_results(), value)?.0; let value = constant_full_int(cx, cx.typeck_results(), value)?;
return Some(SpannedRange { return Some(SpannedRange {
span: pat.span, span: pat.span,
node: (value.clone(), Bound::Included(value)), node: (value, Bound::Included(value)),
}); });
} }
} }
@ -1643,32 +1650,6 @@ pub struct SpannedRange<T> {
pub node: (T, Bound<T>), pub node: (T, Bound<T>),
} }
type TypedRanges = Vec<SpannedRange<u128>>;
/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
/// and other types than
/// `Uint` and `Int` probably don't make sense.
fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
ranges
.iter()
.filter_map(|range| match range.node {
(Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Included(end)),
}),
(Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Excluded(end)),
}),
(Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Unbounded),
}),
_ => None,
})
.collect()
}
// Checks if arm has the form `None => None` // Checks if arm has the form `None => None`
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))

View file

@ -85,7 +85,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
{ {
return; return;
} },
ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..) | ExprKind::Field(..)
@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
) => ) =>
{ {
return; return;
} },
_ => false, _ => false,
}; };

View file

@ -186,7 +186,7 @@ pub(super) fn check<'tcx>(
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
} }
} }
} },
_ => (), _ => (),
} }
} }

View file

@ -1,4 +1,3 @@
use super::MiscEarlyLints;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, UnOp}; use rustc_ast::ast::{Expr, ExprKind, UnOp};
use rustc_lint::EarlyContext; use rustc_lint::EarlyContext;
@ -6,18 +5,14 @@ use rustc_lint::EarlyContext;
use super::DOUBLE_NEG; use super::DOUBLE_NEG;
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) { pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
match expr.kind { if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
ExprKind::Unary(UnOp::Neg, ref inner) => { if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { span_lint(
span_lint( cx,
cx, DOUBLE_NEG,
DOUBLE_NEG, expr.span,
expr.span, "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", );
); }
}
},
ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
_ => (),
} }
} }

View file

@ -0,0 +1,38 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
val
} else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() {
if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
span_lint_and_sugg(
cx,
SEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should not be separated by an underscore", sugg_type),
"remove the underscore",
format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
} else {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should be separated by an underscore", sugg_type),
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}
}

View file

@ -1,15 +1,15 @@
mod builtin_type_shadow; mod builtin_type_shadow;
mod double_neg; mod double_neg;
mod literal_suffix;
mod mixed_case_hex_literals; mod mixed_case_hex_literals;
mod redundant_pattern; mod redundant_pattern;
mod unneeded_field_pattern; mod unneeded_field_pattern;
mod unneeded_wildcard_pattern; mod unneeded_wildcard_pattern;
mod unseparated_literal_suffix;
mod zero_prefixed_literal; mod zero_prefixed_literal;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::visit::FnKind; use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
@ -115,9 +115,11 @@ declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Warns if literal suffixes are not separated by an /// Warns if literal suffixes are not separated by an
/// underscore. /// underscore.
/// To enforce unseparated literal suffix style,
/// see the `separated_literal_suffix` lint.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// It is much less readable. /// Suffix style should be consistent.
/// ///
/// ### Example /// ### Example
/// ```rust /// ```rust
@ -128,10 +130,32 @@ declare_clippy_lint! {
/// let y = 123832_i32; /// let y = 123832_i32;
/// ``` /// ```
pub UNSEPARATED_LITERAL_SUFFIX, pub UNSEPARATED_LITERAL_SUFFIX,
pedantic, restriction,
"literals whose suffix is not separated by an underscore" "literals whose suffix is not separated by an underscore"
} }
declare_clippy_lint! {
/// ### What it does
/// Warns if literal suffixes are separated by an underscore.
/// To enforce separated literal suffix style,
/// see the `unseparated_literal_suffix` lint.
///
/// ### Why is this bad?
/// Suffix style should be consistent.
///
/// ### Example
/// ```rust
/// // Bad
/// let y = 123832_i32;
///
/// // Good
/// let y = 123832i32;
/// ```
pub SEPARATED_LITERAL_SUFFIX,
restriction,
"literals whose suffix is separated by an underscore"
}
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Warns if an integral constant literal starts with `0`. /// Warns if an integral constant literal starts with `0`.
@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [
DOUBLE_NEG, DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS, MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX,
SEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL, ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW, BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN, REDUNDANT_PATTERN,
@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess, expr.span) {
return; return;
} }
if let ExprKind::Lit(ref lit) = expr.kind {
MiscEarlyLints::check_lit(cx, lit);
}
double_neg::check(cx, expr); double_neg::check(cx, expr);
} }
} }
@ -332,7 +361,7 @@ impl MiscEarlyLints {
LitIntType::Unsigned(ty) => ty.name_str(), LitIntType::Unsigned(ty) => ty.name_str(),
LitIntType::Unsuffixed => "", LitIntType::Unsuffixed => "",
}; };
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") { if lit_snip.starts_with("0x") {
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip); mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
@ -342,7 +371,7 @@ impl MiscEarlyLints {
} }
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind { } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
let suffix = float_ty.name_str(); let suffix = float_ty.name_str();
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
} }
} }
} }

View file

@ -1,26 +0,0 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::UNSEPARATED_LITERAL_SUFFIX;
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
val
} else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should be separated by an underscore", sugg_type),
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}

View file

@ -106,7 +106,7 @@ impl EarlyLintPass for ModStyle {
} }
process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders); process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
check_self_named_mod_exists(cx, path, file); check_self_named_mod_exists(cx, path, file);
} },
_ => {}, _ => {},
} }
} }

View file

@ -107,14 +107,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
if let [Adjustment { if let [
kind: Adjust::Deref(_), .. Adjustment {
}, Adjustment { kind: Adjust::Deref(_), ..
kind: Adjust::Deref(_), .. },
}, Adjustment { Adjustment {
kind: Adjust::Borrow(_), kind: Adjust::Deref(_), ..
.. },
}] = *adj3 Adjustment {
kind: Adjust::Borrow(_),
..
},
] = *adj3
{ {
let help_msg_ty = if matches!(mutability, Mutability::Not) { let help_msg_ty = if matches!(mutability, Mutability::Not) {
format!("&{}", ty) format!("&{}", ty)

View file

@ -44,7 +44,7 @@ declare_clippy_lint! {
/// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
/// or specify correct bounds on generic type parameters (`T: Send`). /// or specify correct bounds on generic type parameters (`T: Send`).
pub NON_SEND_FIELDS_IN_SEND_TY, pub NON_SEND_FIELDS_IN_SEND_TY,
nursery, suspicious,
"there is field that does not implement `Send` in a `Send` struct" "there is field that does not implement `Send` in a `Send` struct"
} }

View file

@ -22,7 +22,7 @@ declare_clippy_lint! {
/// expression). /// expression).
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// Using the dedicated functions of the Option type is clearer and /// Using the dedicated functions of the `Option` type is clearer and
/// more concise than an `if let` expression. /// more concise than an `if let` expression.
/// ///
/// ### Known problems /// ### Known problems

View file

@ -3,16 +3,16 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::ptr::get_spans; use clippy_utils::ptr::get_spans;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; use clippy_utils::ty::walk_ptrs_hir_ty;
use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths}; use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{ use rustc_hir::{
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item, BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
@ -153,7 +153,7 @@ declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USA
impl<'tcx> LateLintPass<'tcx> for Ptr { impl<'tcx> LateLintPass<'tcx> for Ptr {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Fn(ref sig, _, body_id) = item.kind { if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); check_fn(cx, sig.decl, Some(body_id));
} }
} }
@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
return; // ignore trait impls return; // ignore trait impls
} }
} }
check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); check_fn(cx, sig.decl, Some(body_id));
} }
} }
@ -176,7 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
} else { } else {
None None
}; };
check_fn(cx, sig.decl, item.hir_id(), body_id); check_fn(cx, sig.decl, body_id);
} }
} }
@ -244,13 +244,10 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
} }
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) { fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
let sig = cx.tcx.fn_sig(fn_def_id);
let fn_ty = sig.skip_binder();
let body = opt_body_id.map(|id| cx.tcx.hir().body(id)); let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() { for (idx, arg) in decl.inputs.iter().enumerate() {
// Honor the allow attribute on parameters. See issue 5644. // Honor the allow attribute on parameters. See issue 5644.
if let Some(body) = &body { if let Some(body) = &body {
if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) { if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
@ -258,8 +255,20 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
} }
} }
if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { let (item_name, path) = if_chain! {
if is_type_diagnostic_item(cx, ty, sym::Vec) { if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
if let Res::Def(_, did) = path.res;
if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
then {
(item_name, path)
} else {
continue
}
};
match item_name {
sym::Vec => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
span_lint_and_then( span_lint_and_then(
cx, cx,
@ -289,7 +298,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
}, },
); );
} }
} else if is_type_diagnostic_item(cx, ty, sym::String) { },
sym::String => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
span_lint_and_then( span_lint_and_then(
cx, cx,
@ -311,7 +321,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
}, },
); );
} }
} else if is_type_diagnostic_item(cx, ty, sym::PathBuf) { },
sym::PathBuf => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
span_lint_and_then( span_lint_and_then(
cx, cx,
@ -338,11 +349,10 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
}, },
); );
} }
} else if match_type(cx, ty, &paths::COW) { },
sym::Cow => {
if_chain! { if_chain! {
if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind; if let [ref bx] = *path.segments;
if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
if let [ref bx] = *pp.segments;
if let Some(params) = bx.args; if let Some(params) = bx.args;
if !params.parenthesized; if !params.parenthesized;
if let Some(inner) = params.args.iter().find_map(|arg| match arg { if let Some(inner) = params.args.iter().find_map(|arg| match arg {
@ -363,7 +373,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
); );
} }
} }
} },
_ => {},
} }
} }

View file

@ -172,23 +172,17 @@ impl QuestionMark {
} }
} }
fn expression_returns_unmodified_err( fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
cx: &LateContext<'_>, match expr.kind {
expression: &Expr<'_>,
origin_hir_id: &Expr<'_>,
) -> bool {
match expression.kind {
ExprKind::Block(block, _) => { ExprKind::Block(block, _) => {
if let Some(return_expression) = Self::return_expression(block) { if let Some(return_expression) = Self::return_expression(block) {
return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id); return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
} }
false false
}, },
ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => { ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
Self::expression_returns_unmodified_err(cx, expr, origin_hir_id) ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
},
ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id),
_ => false, _ => false,
} }
} }

View file

@ -107,51 +107,87 @@ declare_clippy_lint! {
"calling `as_bytes` on a string literal instead of using a byte string literal" "calling `as_bytes` on a string literal instead of using a byte string literal"
} }
declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]); declare_clippy_lint! {
/// ### What it does
/// Checks for slice operations on strings
///
/// ### Why is this bad?
/// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
/// counts and string indices. This may lead to panics, and should warrant some test cases
/// containing wide UTF-8 characters. This lint is most useful in code that should avoid
/// panics at all costs.
///
/// ### Known problems
/// Probably lots of false positives. If an index comes from a known valid position (e.g.
/// obtained via `char_indices` over the same string), it is totally OK.
///
/// # Example
/// ```rust,should_panic
/// &"Ölkanne"[1..];
/// ```
pub STRING_SLICE,
restriction,
"slicing a string"
}
declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
impl<'tcx> LateLintPass<'tcx> for StringAdd { impl<'tcx> LateLintPass<'tcx> for StringAdd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), e.span) { if in_external_macro(cx.sess(), e.span) {
return; return;
} }
match e.kind {
if let ExprKind::Binary( ExprKind::Binary(
Spanned { Spanned {
node: BinOpKind::Add, .. node: BinOpKind::Add, ..
}, },
left, left,
_, _,
) = e.kind ) => {
{ if is_string(cx, left) {
if is_string(cx, left) { if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { let parent = get_parent_expr(cx, e);
let parent = get_parent_expr(cx, e); if let Some(p) = parent {
if let Some(p) = parent { if let ExprKind::Assign(target, _, _) = p.kind {
if let ExprKind::Assign(target, _, _) = p.kind { // avoid duplicate matches
// avoid duplicate matches if SpanlessEq::new(cx).eq_expr(target, left) {
if SpanlessEq::new(cx).eq_expr(target, left) { return;
return; }
} }
} }
} }
span_lint(
cx,
STRING_ADD,
e.span,
"you added something to a string. Consider using `String::push_str()` instead",
);
} }
span_lint( },
cx, ExprKind::Assign(target, src, _) => {
STRING_ADD, if is_string(cx, target) && is_add(cx, src, target) {
e.span, span_lint(
"you added something to a string. Consider using `String::push_str()` instead", cx,
); STRING_ADD_ASSIGN,
} e.span,
} else if let ExprKind::Assign(target, src, _) = e.kind { "you assigned the result of adding something to this string. Consider using \
if is_string(cx, target) && is_add(cx, src, target) { `String::push_str()` instead",
span_lint( );
cx, }
STRING_ADD_ASSIGN, },
e.span, ExprKind::Index(target, _idx) => {
"you assigned the result of adding something to this string. Consider using \ let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
`String::push_str()` instead", if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
); span_lint(
} cx,
STRING_SLICE,
e.span,
"indexing into a string may panic if the index is within a UTF-8 character",
);
}
},
_ => {},
} }
} }
} }

View file

@ -145,8 +145,9 @@ impl UndocumentedUnsafeBlocks {
let file_name = source_map.span_to_filename(between_span); let file_name = source_map.span_to_filename(between_span);
let source_file = source_map.get_source_file(&file_name)?; let source_file = source_map.get_source_file(&file_name)?;
let lex_start = (between_span.lo().0 + 1) as usize; let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string(); let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
let mut pos = 0; let mut pos = 0;
let mut comment = false; let mut comment = false;

View file

@ -45,7 +45,7 @@ declare_clippy_lint! {
/// let x = String::from("\u{20ac}"); /// let x = String::from("\u{20ac}");
/// ``` /// ```
pub NON_ASCII_LITERAL, pub NON_ASCII_LITERAL,
pedantic, restriction,
"using any literal non-ASCII chars in a string literal instead of using the `\\u` escape" "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
} }

View file

@ -0,0 +1,77 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Detects `().hash(_)`.
///
/// ### Why is this bad?
/// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
///
/// ### Example
/// ```rust
/// # use std::hash::Hash;
/// # use std::collections::hash_map::DefaultHasher;
/// # enum Foo { Empty, WithValue(u8) }
/// # use Foo::*;
/// # let mut state = DefaultHasher::new();
/// # let my_enum = Foo::Empty;
/// match my_enum {
/// Empty => ().hash(&mut state),
/// WithValue(x) => x.hash(&mut state),
/// }
/// ```
/// Use instead:
/// ```rust
/// # use std::hash::Hash;
/// # use std::collections::hash_map::DefaultHasher;
/// # enum Foo { Empty, WithValue(u8) }
/// # use Foo::*;
/// # let mut state = DefaultHasher::new();
/// # let my_enum = Foo::Empty;
/// match my_enum {
/// Empty => 0_u8.hash(&mut state),
/// WithValue(x) => x.hash(&mut state),
/// }
/// ```
pub UNIT_HASH,
correctness,
"hashing a unit value, which does nothing"
}
declare_lint_pass!(UnitHash => [UNIT_HASH]);
impl LateLintPass<'tcx> for UnitHash {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if_chain! {
if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
if name_ident.ident.name == sym::hash;
if let [recv, state_param] = args;
if cx.typeck_results().expr_ty(recv).is_unit();
then {
span_lint_and_then(
cx,
UNIT_HASH,
expr.span,
"this call to `hash` on the unit type will do nothing",
|diag| {
diag.span_suggestion(
expr.span,
"remove the call to `hash` or consider using",
format!(
"0_u8.hash({})",
snippet(cx, state_param.span, ".."),
),
Applicability::MaybeIncorrect,
);
diag.note("the implementation of `Hash` for `()` is a no-op");
}
);
}
}
}
}

View file

@ -13,7 +13,7 @@ use rustc_span::{sym, Span};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Checks for functions of type Result that contain `expect()` or `unwrap()` /// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.

View file

@ -288,10 +288,10 @@ define_Conf! {
/// ///
/// The list of imports to always rename, a fully qualified path followed by the rename. /// The list of imports to always rename, a fully qualified path followed by the rename.
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()), (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
/// Lint: RESTRICTED_SCRIPTS. /// Lint: DISALLOWED_SCRIPT_IDENTS.
/// ///
/// The list of unicode scripts allowed to be used in the scope. /// The list of unicode scripts allowed to be used in the scope.
(allowed_scripts: Vec<String> = vec!["Latin".to_string()]), (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
/// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
/// ///
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`. /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.

View file

@ -512,12 +512,21 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str); let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
let mut docs = String::from(&*lines.next()?.as_str()); let mut docs = String::from(&*lines.next()?.as_str());
let mut in_code_block = false; let mut in_code_block = false;
let mut is_code_block_rust = false;
for line in lines { for line in lines {
docs.push('\n');
let line = line.as_str(); let line = line.as_str();
let line = &*line; let line = &*line;
// Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
if is_code_block_rust && line.trim_start().starts_with("# ") {
continue;
}
// The line should be represented in the lint list, even if it's just an empty line
docs.push('\n');
if let Some(info) = line.trim_start().strip_prefix("```") { if let Some(info) = line.trim_start().strip_prefix("```") {
in_code_block = !in_code_block; in_code_block = !in_code_block;
is_code_block_rust = false;
if in_code_block { if in_code_block {
let lang = info let lang = info
.trim() .trim()
@ -528,6 +537,8 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
.unwrap_or("rust"); .unwrap_or("rust");
docs.push_str("```"); docs.push_str("```");
docs.push_str(lang); docs.push_str(lang);
is_code_block_rust = lang == "rust";
continue; continue;
} }
} }

View file

@ -1,117 +0,0 @@
/// Returns the index of the character after the first camel-case component of `s`.
#[must_use]
pub fn until(s: &str) -> usize {
let mut iter = s.char_indices();
if let Some((_, first)) = iter.next() {
if !first.is_uppercase() {
return 0;
}
} else {
return 0;
}
let mut up = true;
let mut last_i = 0;
for (i, c) in iter {
if up {
if c.is_lowercase() {
up = false;
} else {
return last_i;
}
} else if c.is_uppercase() {
up = true;
last_i = i;
} else if !c.is_lowercase() {
return i;
}
}
if up { last_i } else { s.len() }
}
/// Returns index of the last camel-case component of `s`.
#[must_use]
pub fn from(s: &str) -> usize {
let mut iter = s.char_indices().rev();
if let Some((_, first)) = iter.next() {
if !first.is_lowercase() {
return s.len();
}
} else {
return s.len();
}
let mut down = true;
let mut last_i = s.len();
for (i, c) in iter {
if down {
if c.is_uppercase() {
down = false;
last_i = i;
} else if !c.is_lowercase() {
return last_i;
}
} else if c.is_lowercase() {
down = true;
} else if c.is_uppercase() {
last_i = i;
} else {
return last_i;
}
}
last_i
}
#[cfg(test)]
mod test {
use super::{from, until};
#[test]
fn from_full() {
assert_eq!(from("AbcDef"), 0);
assert_eq!(from("Abc"), 0);
assert_eq!(from("ABcd"), 0);
assert_eq!(from("ABcdEf"), 0);
assert_eq!(from("AabABcd"), 0);
}
#[test]
fn from_partial() {
assert_eq!(from("abcDef"), 3);
assert_eq!(from("aDbc"), 1);
assert_eq!(from("aabABcd"), 3);
}
#[test]
fn from_not() {
assert_eq!(from("AbcDef_"), 7);
assert_eq!(from("AbcDD"), 5);
}
#[test]
fn from_caps() {
assert_eq!(from("ABCD"), 4);
}
#[test]
fn until_full() {
assert_eq!(until("AbcDef"), 6);
assert_eq!(until("Abc"), 3);
}
#[test]
fn until_not() {
assert_eq!(until("abcDef"), 0);
assert_eq!(until("aDbc"), 0);
}
#[test]
fn until_partial() {
assert_eq!(until("AbcDef_"), 6);
assert_eq!(until("CallTypeC"), 8);
assert_eq!(until("AbcDD"), 3);
}
#[test]
fn until_caps() {
assert_eq!(until("ABCD"), 0);
}
}

View file

@ -155,6 +155,19 @@ impl Constant {
_ => None, _ => None,
} }
} }
/// Returns the integer value or `None` if `self` or `val_type` is not integer type.
pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
if let Constant::Int(const_int) = *self {
match *val_type.kind() {
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
ty::Uint(_) => Some(FullInt::U(const_int)),
_ => None,
}
} else {
None
}
}
} }
/// Parses a `LitKind` to a `Constant`. /// Parses a `LitKind` to a `Constant`.
@ -202,6 +215,52 @@ pub fn constant_simple<'tcx>(
constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
} }
pub fn constant_full_int(
lcx: &LateContext<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>,
) -> Option<FullInt> {
constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
}
#[derive(Copy, Clone, Debug, Eq)]
pub enum FullInt {
S(i128),
U(u128),
}
impl PartialEq for FullInt {
#[must_use]
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl PartialOrd for FullInt {
#[must_use]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FullInt {
#[must_use]
fn cmp(&self, other: &Self) -> Ordering {
use FullInt::{S, U};
fn cmp_s_u(s: i128, u: u128) -> Ordering {
u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
}
match (*self, *other) {
(S(s), S(o)) => s.cmp(&o),
(U(s), U(o)) => s.cmp(&o),
(S(s), U(o)) => cmp_s_u(s, o),
(U(s), S(o)) => cmp_s_u(o, s).reverse(),
}
}
}
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. /// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
pub fn constant_context<'a, 'tcx>( pub fn constant_context<'a, 'tcx>(
lcx: &'a LateContext<'tcx>, lcx: &'a LateContext<'tcx>,

View file

@ -72,7 +72,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
/// 6 | let other_f64_nan = 0.0f64 / 0.0; /// 6 | let other_f64_nan = 0.0f64 / 0.0;
/// | ^^^^^^^^^^^^ /// | ^^^^^^^^^^^^
/// | /// |
/// = help: Consider using `f64::NAN` if you would like a constant representing NaN /// = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ``` /// ```
pub fn span_lint_and_help<'a, T: LintContext>( pub fn span_lint_and_help<'a, T: LintContext>(
cx: &'a T, cx: &'a T,

View file

@ -1,14 +1,14 @@
//! This module contains functions that retrieves specifiec elements. //! This module contains functions that retrieve specific elements.
#![deny(clippy::missing_docs_in_private_items)] #![deny(clippy::missing_docs_in_private_items)]
use crate::ty::is_type_diagnostic_item; use crate::ty::is_type_diagnostic_item;
use crate::{is_expn_of, last_path_segment, match_def_path, paths}; use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{self, LitKind}; use rustc_ast::ast::{self, LitKind};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{ use rustc_hir::{
Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp, Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
}; };
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::{sym, symbol, ExpnKind, Span, Symbol}; use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
@ -513,6 +513,8 @@ pub struct FormatArgsExpn<'tcx> {
pub format_string_parts: &'tcx [Expr<'tcx>], pub format_string_parts: &'tcx [Expr<'tcx>],
/// Symbols corresponding to [`Self::format_string_parts`] /// Symbols corresponding to [`Self::format_string_parts`]
pub format_string_symbols: Vec<Symbol>, pub format_string_symbols: Vec<Symbol>,
/// Match arm patterns, the `arg0`, etc. from the next field `args`
pub arg_names: &'tcx [Pat<'tcx>],
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)` /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
pub args: &'tcx [Expr<'tcx>], pub args: &'tcx [Expr<'tcx>],
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable /// The final argument passed to `Arguments::new_v1_formatted`, if applicable
@ -557,6 +559,7 @@ impl FormatArgsExpn<'tcx> {
_ => None, _ => None,
}) })
.collect(); .collect();
if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
if let ExprKind::Array(args) = arm.body.kind; if let ExprKind::Array(args) = arm.body.kind;
then { then {
Some(FormatArgsExpn { Some(FormatArgsExpn {
@ -564,6 +567,7 @@ impl FormatArgsExpn<'tcx> {
value_args, value_args,
format_string_parts, format_string_parts,
format_string_symbols, format_string_symbols,
arg_names,
args, args,
fmt_expr, fmt_expr,
}) })
@ -587,9 +591,15 @@ impl FormatArgsExpn<'tcx> {
if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
if let ExprKind::Lit(lit) = &position_field.expr.kind; if let ExprKind::Lit(lit) = &position_field.expr.kind;
if let LitKind::Int(position, _) = lit.node; if let LitKind::Int(position, _) = lit.node;
if let Ok(i) = usize::try_from(position);
let arg = &self.args[i];
if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
if let Some(j) = self
.arg_names
.iter()
.position(|pat| path_to_local_id(arg_name, pat.hir_id));
then { then {
let i = usize::try_from(position).unwrap(); Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
} else { } else {
None None
} }
@ -718,9 +728,7 @@ impl PanicExpn<'tcx> {
/// Parses an expanded `panic!` invocation /// Parses an expanded `panic!` invocation
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> { pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
if_chain! { if_chain! {
if let ExprKind::Block(block, _) = expr.kind; if let ExprKind::Call(_, [format_args]) = expr.kind;
if let Some(init) = block.expr;
if let ExprKind::Call(_, [format_args]) = init.kind;
let expn_data = expr.span.ctxt().outer_expn_data(); let expn_data = expr.span.ctxt().outer_expn_data();
if let Some(format_args) = FormatArgsExpn::parse(format_args); if let Some(format_args) = FormatArgsExpn::parse(format_args);
then { then {
@ -770,13 +778,13 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
} }
return Some(VecInitKind::WithExprCapacity(arg.hir_id)); return Some(VecInitKind::WithExprCapacity(arg.hir_id));
} }
} },
ExprKind::Path(QPath::Resolved(_, path)) ExprKind::Path(QPath::Resolved(_, path))
if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
{ {
return Some(VecInitKind::Default); return Some(VecInitKind::Default);
} },
_ => (), _ => (),
} }
} }

View file

@ -37,7 +37,6 @@ pub mod sym_helper;
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub mod ast_utils; pub mod ast_utils;
pub mod attrs; pub mod attrs;
pub mod camel_case;
pub mod comparisons; pub mod comparisons;
pub mod consts; pub mod consts;
pub mod diagnostics; pub mod diagnostics;
@ -50,6 +49,7 @@ pub mod paths;
pub mod ptr; pub mod ptr;
pub mod qualify_min_const_fn; pub mod qualify_min_const_fn;
pub mod source; pub mod source;
pub mod str_utils;
pub mod sugg; pub mod sugg;
pub mod ty; pub mod ty;
pub mod usage; pub mod usage;
@ -712,7 +712,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
/// Checks if the top level expression can be moved into a closure as is. /// Checks if the top level expression can be moved into a closure as is.
/// Currently checks for: /// Currently checks for:
/// * Break/Continue outside the given loop HIR ids. /// * Break/Continue outside the given loop HIR ids.
/// * Yield/Return statments. /// * Yield/Return statements.
/// * Inline assembly. /// * Inline assembly.
/// * Usages of a field of a local where the type of the local can be partially moved. /// * Usages of a field of a local where the type of the local can be partially moved.
/// ///
@ -844,10 +844,13 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind
let mut capture_expr_ty = e; let mut capture_expr_ty = e;
for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) { for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
if let [Adjustment { if let [
kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), Adjustment {
target, kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
}, ref adjust @ ..] = *cx target,
},
ref adjust @ ..,
] = *cx
.typeck_results() .typeck_results()
.adjustments() .adjustments()
.get(child_id) .get(child_id)
@ -1232,9 +1235,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti
for (_, node) in tcx.hir().parent_iter(expr.hir_id) { for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
match node { match node {
Node::Expr( Node::Expr(
e e @ Expr {
@
Expr {
kind: ExprKind::Loop(..) | ExprKind::Closure(..), kind: ExprKind::Loop(..) | ExprKind::Closure(..),
.. ..
}, },
@ -1692,10 +1693,12 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call( if let ExprKind::Call(
_, _,
&[Expr { &[
kind: ExprKind::Closure(_, _, body, _, _), Expr {
.. kind: ExprKind::Closure(_, _, body, _, _),
}], ..
},
],
) = body.value.kind ) = body.value.kind
{ {
if let ExprKind::Block( if let ExprKind::Block(
@ -2123,7 +2126,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
vis.found vis.found
} }
/// Checks whether item either has `test` attribute appelied, or /// Checks whether item either has `test` attribute applied, or
/// is a module with `test` in its name. /// is a module with `test` in its name.
/// ///
/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`. /// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.

View file

@ -0,0 +1,230 @@
/// Dealing with sting indices can be hard, this struct ensures that both the
/// character and byte index are provided for correct indexing.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrIndex {
pub char_index: usize,
pub byte_index: usize,
}
impl StrIndex {
pub fn new(char_index: usize, byte_index: usize) -> Self {
Self { char_index, byte_index }
}
}
/// Returns the index of the character after the first camel-case component of `s`.
///
/// ```
/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
/// ```
#[must_use]
pub fn camel_case_until(s: &str) -> StrIndex {
let mut iter = s.char_indices().enumerate();
if let Some((_char_index, (_, first))) = iter.next() {
if !first.is_uppercase() {
return StrIndex::new(0, 0);
}
} else {
return StrIndex::new(0, 0);
}
let mut up = true;
let mut last_index = StrIndex::new(0, 0);
for (char_index, (byte_index, c)) in iter {
if up {
if c.is_lowercase() {
up = false;
} else {
return last_index;
}
} else if c.is_uppercase() {
up = true;
last_index.byte_index = byte_index;
last_index.char_index = char_index;
} else if !c.is_lowercase() {
return StrIndex::new(char_index, byte_index);
}
}
if up {
last_index
} else {
StrIndex::new(s.chars().count(), s.len())
}
}
/// Returns index of the last camel-case component of `s`.
///
/// ```
/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
/// ```
#[must_use]
pub fn camel_case_start(s: &str) -> StrIndex {
let char_count = s.chars().count();
let range = 0..char_count;
let mut iter = range.rev().zip(s.char_indices().rev());
if let Some((char_index, (_, first))) = iter.next() {
if !first.is_lowercase() {
return StrIndex::new(char_index, s.len());
}
} else {
return StrIndex::new(char_count, s.len());
}
let mut down = true;
let mut last_index = StrIndex::new(char_count, s.len());
for (char_index, (byte_index, c)) in iter {
if down {
if c.is_uppercase() {
down = false;
last_index.byte_index = byte_index;
last_index.char_index = char_index;
} else if !c.is_lowercase() {
return last_index;
}
} else if c.is_lowercase() {
down = true;
} else if c.is_uppercase() {
last_index.byte_index = byte_index;
last_index.char_index = char_index;
} else {
return last_index;
}
}
last_index
}
/// Dealing with sting comparison can be complicated, this struct ensures that both the
/// character and byte count are provided for correct indexing.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrCount {
pub char_count: usize,
pub byte_count: usize,
}
impl StrCount {
pub fn new(char_count: usize, byte_count: usize) -> Self {
Self { char_count, byte_count }
}
}
/// Returns the number of chars that match from the start
///
/// ```
/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
/// ```
#[must_use]
pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
// (char_index, char1)
let char_count = str1.chars().count();
let iter1 = (0..=char_count).zip(str1.chars());
// (byte_index, char2)
let iter2 = str2.char_indices();
iter1
.zip(iter2)
.take_while(|((_, c1), (_, c2))| c1 == c2)
.last()
.map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
StrCount::new(char_index + 1, byte_index + character.len_utf8())
})
}
/// Returns the number of chars and bytes that match from the end
///
/// ```
/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
/// ```
#[must_use]
pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
let char_count = str1.chars().count();
if char_count == 0 {
return StrCount::default();
}
// (char_index, char1)
let iter1 = (0..char_count).rev().zip(str1.chars().rev());
// (byte_index, char2)
let byte_count = str2.len();
let iter2 = str2.char_indices().rev();
iter1
.zip(iter2)
.take_while(|((_, c1), (_, c2))| c1 == c2)
.last()
.map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
StrCount::new(char_count - char_index, byte_count - byte_index)
})
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn camel_case_start_full() {
assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
}
#[test]
fn camel_case_start_partial() {
assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
}
#[test]
fn camel_case_start_not() {
assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
}
#[test]
fn camel_case_start_caps() {
assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
}
#[test]
fn camel_case_until_full() {
assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
}
#[test]
fn camel_case_until_not() {
assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
}
#[test]
fn camel_case_until_partial() {
assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
}
#[test]
fn until_caps() {
assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
}
}

View file

@ -16,6 +16,7 @@ because that's clearly a non-descriptive name.
- [Edition 2018 tests](#edition-2018-tests) - [Edition 2018 tests](#edition-2018-tests)
- [Testing manually](#testing-manually) - [Testing manually](#testing-manually)
- [Lint declaration](#lint-declaration) - [Lint declaration](#lint-declaration)
- [Lint registration](#lint-registration)
- [Lint passes](#lint-passes) - [Lint passes](#lint-passes)
- [Emitting a lint](#emitting-a-lint) - [Emitting a lint](#emitting-a-lint)
- [Adding the lint logic](#adding-the-lint-logic) - [Adding the lint logic](#adding-the-lint-logic)
@ -43,9 +44,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this
lint you can run `cargo dev new_lint --name=foo_functions --pass=early lint you can run `cargo dev new_lint --name=foo_functions --pass=early
--category=pedantic` (category will default to nursery if not provided). This --category=pedantic` (category will default to nursery if not provided). This
command will create two files: `tests/ui/foo_functions.rs` and command will create two files: `tests/ui/foo_functions.rs` and
`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to `clippy_lints/src/foo_functions.rs`, as well as
register the new lint. For cargo lints, two project hierarchies (fail/pass) will [registering the lint](#lint-registration). For cargo lints, two project
be created by default under `tests/ui-cargo`. hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
Next, we'll open up these files and add our lint! Next, we'll open up these files and add our lint!
@ -220,32 +221,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
impl EarlyLintPass for FooFunctions {} impl EarlyLintPass for FooFunctions {}
``` ```
Normally after declaring the lint, we have to run `cargo dev update_lints`, [declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
which updates some files, so Clippy knows about the new lint. Since we used [example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
`cargo dev new_lint ...` to generate the lint declaration, this was done [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
automatically. While `update_lints` automates most of the things, it doesn't [category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
automate everything. We will have to register our lint pass manually in the
`register_plugins` function in `clippy_lints/src/lib.rs`: ## Lint registration
When using `cargo dev new_lint`, the lint is automatically registered and
nothing more has to be done.
When declaring a new lint by hand and `cargo dev update_lints` is used, the lint
pass may have to be registered manually in the `register_plugins` function in
`clippy_lints/src/lib.rs`:
```rust ```rust
store.register_early_pass(|| box foo_functions::FooFunctions); store.register_early_pass(|| Box::new(foo_functions::FooFunctions));
``` ```
As one may expect, there is a corresponding `register_late_pass` method As one may expect, there is a corresponding `register_late_pass` method
available as well. Without a call to one of `register_early_pass` or available as well. Without a call to one of `register_early_pass` or
`register_late_pass`, the lint pass in question will not be run. `register_late_pass`, the lint pass in question will not be run.
One reason that `cargo dev` does not automate this step is that multiple lints One reason that `cargo dev update_lints` does not automate this step is that
can use the same lint pass, so registering the lint pass may already be done multiple lints can use the same lint pass, so registering the lint pass may
when adding a new lint. Another reason that this step is not automated is that already be done when adding a new lint. Another reason that this step is not
the order that the passes are registered determines the order the passes automated is that the order that the passes are registered determines the order
actually run, which in turn affects the order that any emitted lints are output the passes actually run, which in turn affects the order that any emitted lints
in. are output in.
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
## Lint passes ## Lint passes
@ -564,7 +567,8 @@ in the following steps:
/// <The configuration field doc comment> /// <The configuration field doc comment>
(configuration_ident: Type = DefaultValue), (configuration_ident: Type = DefaultValue),
``` ```
The doc comment will be automatically added to the lint documentation. The doc comment is automatically added to the documentation of the listed lints. The default
value will be formatted using the `Debug` implementation of the type.
2. Adding the configuration value to the lint impl struct: 2. Adding the configuration value to the lint impl struct:
1. This first requires the definition of a lint impl struct. Lint impl structs are usually 1. This first requires the definition of a lint impl struct. Lint impl structs are usually
generated with the `declare_lint_pass!` macro. This struct needs to be defined manually generated with the `declare_lint_pass!` macro. This struct needs to be defined manually

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2021-10-21" channel = "nightly-2021-11-04"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"] components = ["llvm-tools-preview", "rustc-dev", "rust-src"]

View file

@ -104,7 +104,10 @@ fn extern_flags() -> String {
} }
fn default_config() -> compiletest::Config { fn default_config() -> compiletest::Config {
let mut config = compiletest::Config::default(); let mut config = compiletest::Config {
edition: Some("2021".into()),
..compiletest::Config::default()
};
if let Ok(filters) = env::var("TESTNAME") { if let Ok(filters) = env::var("TESTNAME") {
config.filters = filters.split(',').map(std::string::ToString::to_string).collect(); config.filters = filters.split(',').map(std::string::ToString::to_string).collect();

View file

@ -1,7 +1,10 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)] #![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)] #![allow(clippy::assertions_on_constants)]
#![feature(path_file_prefix)]
use std::cmp::Ordering;
use std::ffi::OsStr;
use std::fs::{self, DirEntry}; use std::fs::{self, DirEntry};
use std::path::Path; use std::path::Path;
@ -21,29 +24,39 @@ fn test_missing_tests() {
} }
} }
/* // Test for missing files.
Test for missing files.
Since rs files are alphabetically before stderr/stdout, we can sort by the full name
and iter in that order. If we've seen the file stem for the first time and it's not
a rust file, it means the rust file has to be missing.
*/
fn explore_directory(dir: &Path) -> Vec<String> { fn explore_directory(dir: &Path) -> Vec<String> {
let mut missing_files: Vec<String> = Vec::new(); let mut missing_files: Vec<String> = Vec::new();
let mut current_file = String::new(); let mut current_file = String::new();
let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect(); let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
files.sort_by_key(std::fs::DirEntry::path); files.sort_by(|x, y| {
match x.path().file_prefix().cmp(&y.path().file_prefix()) {
Ordering::Equal => (),
ord => return ord,
}
// Sort rs files before the others if they share the same prefix. So when we see
// the file prefix for the first time and it's not a rust file, it means the rust
// file has to be missing.
match (
x.path().extension().and_then(OsStr::to_str),
y.path().extension().and_then(OsStr::to_str),
) {
(Some("rs"), _) => Ordering::Less,
(_, Some("rs")) => Ordering::Greater,
_ => Ordering::Equal,
}
});
for entry in &files { for entry in &files {
let path = entry.path(); let path = entry.path();
if path.is_dir() { if path.is_dir() {
missing_files.extend(explore_directory(&path)); missing_files.extend(explore_directory(&path));
} else { } else {
let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string(); let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
if let Some(ext) = path.extension() { if let Some(ext) = path.extension() {
match ext.to_str().unwrap() { match ext.to_str().unwrap() {
"rs" => current_file = file_stem.clone(), "rs" => current_file = file_prefix.clone(),
"stderr" | "stdout" => { "stderr" | "stdout" => {
if file_stem != current_file { if file_prefix != current_file {
missing_files.push(path.to_str().unwrap().to_string()); missing_files.push(path.to_str().unwrap().to_string());
} }
}, },

View file

@ -1,5 +1,3 @@
// edition:2018
#![warn(clippy::too_many_lines)] #![warn(clippy::too_many_lines)]
// This function should be considered one line. // This function should be considered one line.

View file

@ -1,5 +1,5 @@
error: this function has too many lines (2/1) error: this function has too many lines (2/1)
--> $DIR/test.rs:20:1 --> $DIR/test.rs:18:1
| |
LL | / fn too_many_lines() { LL | / fn too_many_lines() {
LL | | println!("This is bad."); LL | | println!("This is bad.");
@ -10,7 +10,7 @@ LL | | }
= note: `-D clippy::too-many-lines` implied by `-D warnings` = note: `-D clippy::too-many-lines` implied by `-D warnings`
error: this function has too many lines (4/1) error: this function has too many lines (4/1)
--> $DIR/test.rs:26:1 --> $DIR/test.rs:24:1
| |
LL | / async fn async_too_many_lines() { LL | / async fn async_too_many_lines() {
LL | | println!("This is bad."); LL | | println!("This is bad.");
@ -19,7 +19,7 @@ LL | | }
| |_^ | |_^
error: this function has too many lines (4/1) error: this function has too many lines (4/1)
--> $DIR/test.rs:32:1 --> $DIR/test.rs:30:1
| |
LL | / fn closure_too_many_lines() { LL | / fn closure_too_many_lines() {
LL | | let _ = { LL | | let _ = {
@ -30,7 +30,7 @@ LL | | }
| |_^ | |_^
error: this function has too many lines (2/1) error: this function has too many lines (2/1)
--> $DIR/test.rs:54:1 --> $DIR/test.rs:52:1
| |
LL | / fn comment_before_code() { LL | / fn comment_before_code() {
LL | | let _ = "test"; LL | | let _ = "test";

View file

@ -1,3 +1,4 @@
//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
#![allow(non_fmt_panics)] #![allow(non_fmt_panics)]
macro_rules! assert_const { macro_rules! assert_const {
@ -6,7 +7,6 @@ macro_rules! assert_const {
debug_assert!($len < 0); debug_assert!($len < 0);
}; };
} }
fn main() { fn main() {
assert!(true); assert!(true);
assert!(false); assert!(false);
@ -14,7 +14,7 @@ fn main() {
assert!(false, "false message"); assert!(false, "false message");
let msg = "panic message"; let msg = "panic message";
assert!(false, msg.to_uppercase()); assert!(false, "{}", msg.to_uppercase());
const B: bool = true; const B: bool = true;
assert!(B); assert!(B);

View file

@ -26,22 +26,13 @@ LL | assert!(true, "true message");
= help: remove it = help: remove it
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(false, "false message")` should probably be replaced error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:14:5 --> $DIR/assertions_on_constants.rs:14:5
| |
LL | assert!(false, "false message"); LL | assert!(false, "false message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: use `panic!("false message")` or `unreachable!("false message")` = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(false, msg.to_uppercase())` should probably be replaced
--> $DIR/assertions_on_constants.rs:17:5
|
LL | assert!(false, msg.to_uppercase());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(true)` will be optimized out by the compiler error: `assert!(true)` will be optimized out by the compiler
@ -62,13 +53,13 @@ LL | assert!(C);
= help: use `panic!()` or `unreachable!()` = help: use `panic!()` or `unreachable!()`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(false, "C message")` should probably be replaced error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:24:5 --> $DIR/assertions_on_constants.rs:24:5
| |
LL | assert!(C, "C message"); LL | assert!(C, "C message");
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: use `panic!("C message")` or `unreachable!("C message")` = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `debug_assert!(true)` will be optimized out by the compiler error: `debug_assert!(true)` will be optimized out by the compiler
@ -80,5 +71,5 @@ LL | debug_assert!(true);
= help: remove it = help: remove it
= note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 9 previous errors error: aborting due to 8 previous errors

View file

@ -1,5 +1,4 @@
// run-rustfix // run-rustfix
// edition:2018
#![feature(async_closure)] #![feature(async_closure)]
#![warn(clippy::async_yields_async)] #![warn(clippy::async_yields_async)]

View file

@ -1,5 +1,4 @@
// run-rustfix // run-rustfix
// edition:2018
#![feature(async_closure)] #![feature(async_closure)]
#![warn(clippy::async_yields_async)] #![warn(clippy::async_yields_async)]

View file

@ -1,5 +1,5 @@
error: an async construct yields a type which is itself awaitable error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:40:9 --> $DIR/async_yields_async.rs:39:9
| |
LL | let _h = async { LL | let _h = async {
| ____________________- | ____________________-
@ -20,7 +20,7 @@ LL + }.await
| |
error: an async construct yields a type which is itself awaitable error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:45:9 --> $DIR/async_yields_async.rs:44:9
| |
LL | let _i = async { LL | let _i = async {
| ____________________- | ____________________-
@ -33,7 +33,7 @@ LL | | };
| |_____- outer async construct | |_____- outer async construct
error: an async construct yields a type which is itself awaitable error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:51:9 --> $DIR/async_yields_async.rs:50:9
| |
LL | let _j = async || { LL | let _j = async || {
| _______________________- | _______________________-
@ -53,7 +53,7 @@ LL + }.await
| |
error: an async construct yields a type which is itself awaitable error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:56:9 --> $DIR/async_yields_async.rs:55:9
| |
LL | let _k = async || { LL | let _k = async || {
| _______________________- | _______________________-
@ -66,7 +66,7 @@ LL | | };
| |_____- outer async construct | |_____- outer async construct
error: an async construct yields a type which is itself awaitable error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:58:23 --> $DIR/async_yields_async.rs:57:23
| |
LL | let _l = async || CustomFutureType; LL | let _l = async || CustomFutureType;
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -76,7 +76,7 @@ LL | let _l = async || CustomFutureType;
| help: consider awaiting this value: `CustomFutureType.await` | help: consider awaiting this value: `CustomFutureType.await`
error: an async construct yields a type which is itself awaitable error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:64:9 --> $DIR/async_yields_async.rs:63:9
| |
LL | let _m = async || { LL | let _m = async || {
| _______________________- | _______________________-

View file

@ -1,4 +1,3 @@
// edition:2018
#![warn(clippy::await_holding_lock)] #![warn(clippy::await_holding_lock)]
use std::sync::Mutex; use std::sync::Mutex;

View file

@ -1,12 +1,12 @@
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:7:9 --> $DIR/await_holding_lock.rs:6:9
| |
LL | let guard = x.lock().unwrap(); LL | let guard = x.lock().unwrap();
| ^^^^^ | ^^^^^
| |
= note: `-D clippy::await-holding-lock` implied by `-D warnings` = note: `-D clippy::await-holding-lock` implied by `-D warnings`
note: these are all the await points this lock is held through note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:7:5 --> $DIR/await_holding_lock.rs:6:5
| |
LL | / let guard = x.lock().unwrap(); LL | / let guard = x.lock().unwrap();
LL | | baz().await LL | | baz().await
@ -14,13 +14,13 @@ LL | | }
| |_^ | |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:28:9 --> $DIR/await_holding_lock.rs:27:9
| |
LL | let guard = x.lock().unwrap(); LL | let guard = x.lock().unwrap();
| ^^^^^ | ^^^^^
| |
note: these are all the await points this lock is held through note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:28:5 --> $DIR/await_holding_lock.rs:27:5
| |
LL | / let guard = x.lock().unwrap(); LL | / let guard = x.lock().unwrap();
LL | | LL | |
@ -32,13 +32,13 @@ LL | | }
| |_^ | |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:41:13 --> $DIR/await_holding_lock.rs:40:13
| |
LL | let guard = x.lock().unwrap(); LL | let guard = x.lock().unwrap();
| ^^^^^ | ^^^^^
| |
note: these are all the await points this lock is held through note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:41:9 --> $DIR/await_holding_lock.rs:40:9
| |
LL | / let guard = x.lock().unwrap(); LL | / let guard = x.lock().unwrap();
LL | | baz().await LL | | baz().await
@ -46,13 +46,13 @@ LL | | };
| |_____^ | |_____^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:53:13 --> $DIR/await_holding_lock.rs:52:13
| |
LL | let guard = x.lock().unwrap(); LL | let guard = x.lock().unwrap();
| ^^^^^ | ^^^^^
| |
note: these are all the await points this lock is held through note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:53:9 --> $DIR/await_holding_lock.rs:52:9
| |
LL | / let guard = x.lock().unwrap(); LL | / let guard = x.lock().unwrap();
LL | | baz().await LL | | baz().await

View file

@ -1,4 +1,3 @@
// edition:2018
#![warn(clippy::await_holding_refcell_ref)] #![warn(clippy::await_holding_refcell_ref)]
use std::cell::RefCell; use std::cell::RefCell;

View file

@ -1,12 +1,12 @@
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:7:9 --> $DIR/await_holding_refcell_ref.rs:6:9
| |
LL | let b = x.borrow(); LL | let b = x.borrow();
| ^ | ^
| |
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
note: these are all the await points this ref is held through note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:7:5 --> $DIR/await_holding_refcell_ref.rs:6:5
| |
LL | / let b = x.borrow(); LL | / let b = x.borrow();
LL | | baz().await LL | | baz().await
@ -14,13 +14,13 @@ LL | | }
| |_^ | |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:12:9 --> $DIR/await_holding_refcell_ref.rs:11:9
| |
LL | let b = x.borrow_mut(); LL | let b = x.borrow_mut();
| ^ | ^
| |
note: these are all the await points this ref is held through note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:12:5 --> $DIR/await_holding_refcell_ref.rs:11:5
| |
LL | / let b = x.borrow_mut(); LL | / let b = x.borrow_mut();
LL | | baz().await LL | | baz().await
@ -28,13 +28,13 @@ LL | | }
| |_^ | |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:33:9 --> $DIR/await_holding_refcell_ref.rs:32:9
| |
LL | let b = x.borrow_mut(); LL | let b = x.borrow_mut();
| ^ | ^
| |
note: these are all the await points this ref is held through note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:33:5 --> $DIR/await_holding_refcell_ref.rs:32:5
| |
LL | / let b = x.borrow_mut(); LL | / let b = x.borrow_mut();
LL | | LL | |
@ -46,13 +46,13 @@ LL | | }
| |_^ | |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:45:9 --> $DIR/await_holding_refcell_ref.rs:44:9
| |
LL | let b = x.borrow_mut(); LL | let b = x.borrow_mut();
| ^ | ^
| |
note: these are all the await points this ref is held through note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:45:5 --> $DIR/await_holding_refcell_ref.rs:44:5
| |
LL | / let b = x.borrow_mut(); LL | / let b = x.borrow_mut();
LL | | LL | |
@ -64,13 +64,13 @@ LL | | }
| |_^ | |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:60:13 --> $DIR/await_holding_refcell_ref.rs:59:13
| |
LL | let b = x.borrow_mut(); LL | let b = x.borrow_mut();
| ^ | ^
| |
note: these are all the await points this ref is held through note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:60:9 --> $DIR/await_holding_refcell_ref.rs:59:9
| |
LL | / let b = x.borrow_mut(); LL | / let b = x.borrow_mut();
LL | | baz().await LL | | baz().await
@ -78,13 +78,13 @@ LL | | };
| |_____^ | |_____^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:72:13 --> $DIR/await_holding_refcell_ref.rs:71:13
| |
LL | let b = x.borrow_mut(); LL | let b = x.borrow_mut();
| ^ | ^
| |
note: these are all the await points this ref is held through note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:72:9 --> $DIR/await_holding_refcell_ref.rs:71:9
| |
LL | / let b = x.borrow_mut(); LL | / let b = x.borrow_mut();
LL | | baz().await LL | | baz().await

View file

@ -92,4 +92,27 @@ fn main() {
(1i64).checked_rem_euclid(-1i64).unwrap() as u64; (1i64).checked_rem_euclid(-1i64).unwrap() as u64;
(1i64).checked_rem_euclid(-1i64).unwrap() as u128; (1i64).checked_rem_euclid(-1i64).unwrap() as u128;
(1isize).checked_rem_euclid(-1isize).unwrap() as usize; (1isize).checked_rem_euclid(-1isize).unwrap() as usize;
// no lint for `cast_possible_truncation`
// with `signum` method call (see issue #5395)
let x: i64 = 5;
let _ = x.signum() as i32;
let s = x.signum();
let _ = s as i32;
// Test for signed min
(-99999999999i64).min(1) as i8; // should be linted because signed
// Test for various operations that remove enough bits for the result to fit
(999999u64 & 1) as u8;
(999999u64 % 15) as u8;
(999999u64 / 0x1_0000_0000_0000) as u16;
({ 999999u64 >> 56 }) as u8;
({
let x = 999999u64;
x.min(1)
}) as u8;
999999u64.clamp(0, 255) as u8;
999999u64.clamp(0, 256) as u8; // should still be linted
} }

View file

@ -138,5 +138,17 @@ error: casting `isize` to `usize` may lose the sign of the value
LL | -1isize as usize; LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
error: aborting due to 22 previous errors error: casting `i64` to `i8` may truncate the value
--> $DIR/cast.rs:105:5
|
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `u64` to `u8` may truncate the value
--> $DIR/cast.rs:117:5
|
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 24 previous errors

View file

@ -0,0 +1,3 @@
fn zero() {
unsafe { 0 };
}

View file

@ -7,7 +7,6 @@
// in type inference. // in type inference.
#![feature(trivial_bounds)] #![feature(trivial_bounds)]
#![allow(unused)] #![allow(unused)]
trait A {} trait A {}
impl A for i32 {} impl A for i32 {}
@ -22,9 +21,9 @@ where
fn unsized_local() fn unsized_local()
where where
for<'a> Dst<A + 'a>: Sized, for<'a> Dst<dyn A + 'a>: Sized,
{ {
let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>);
} }
fn return_str() -> str fn return_str() -> str

View file

@ -1,30 +1,34 @@
error: trait objects without an explicit `dyn` are deprecated error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:25:17 --> $DIR/ice-3969.rs:20:10
| |
LL | for<'a> Dst<A + 'a>: Sized, LL | str: Sized;
| ^^^^^^ help: use `dyn`: `dyn A + 'a` | ^^^^^
| |
= note: `-D bare-trait-objects` implied by `-D warnings` = note: `-D trivial-bounds` implied by `-D warnings`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: trait objects without an explicit `dyn` are deprecated error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:27:16 --> $DIR/ice-3969.rs:24:30
| |
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); LL | for<'a> Dst<dyn A + 'a>: Sized,
| ^ help: use `dyn`: `dyn A` | ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
error: trait objects without an explicit `dyn` are deprecated error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:27:57 --> $DIR/ice-3969.rs:31:10
| |
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); LL | str: Sized,
| ^ help: use `dyn`: `dyn A` | ^^^^^
error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:38:13
| |
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! LL | String: ::std::ops::Neg<Output = String>,
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:45:10
|
LL | i32: Iterator,
| ^^^^^^^^
error: aborting due to 5 previous errors

View file

@ -1,5 +1,3 @@
// edition:2018
// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
pub async fn bar<'a, T: 'a>(_: T) {} pub async fn bar<'a, T: 'a>(_: T) {}

View file

@ -1,6 +1,5 @@
// originally from glacier fixed/77919.rs // originally from glacier fixed/77919.rs
// encountered errors resolving bounds after type-checking // encountered errors resolving bounds after type-checking
trait TypeVal<T> { trait TypeVal<T> {
const VAL: T; const VAL: T;
} }

View file

@ -1,16 +1,20 @@
error[E0412]: cannot find type `PhantomData` in this scope error[E0412]: cannot find type `PhantomData` in this scope
--> $DIR/ice-6252.rs:9:9 --> $DIR/ice-6252.rs:8:9
| |
LL | _n: PhantomData, LL | _n: PhantomData,
| ^^^^^^^^^^^ not found in this scope | ^^^^^^^^^^^ not found in this scope
| |
help: consider importing this struct help: consider importing one of these items
|
LL | use core::marker::PhantomData;
|
LL | use serde::__private::PhantomData;
| |
LL | use std::marker::PhantomData; LL | use std::marker::PhantomData;
| |
error[E0412]: cannot find type `VAL` in this scope error[E0412]: cannot find type `VAL` in this scope
--> $DIR/ice-6252.rs:11:63 --> $DIR/ice-6252.rs:10:63
| |
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
| - ^^^ not found in this scope | - ^^^ not found in this scope
@ -18,7 +22,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
| help: you might be missing a type parameter: `, VAL` | help: you might be missing a type parameter: `, VAL`
error[E0046]: not all trait items implemented, missing: `VAL` error[E0046]: not all trait items implemented, missing: `VAL`
--> $DIR/ice-6252.rs:11:1 --> $DIR/ice-6252.rs:10:1
| |
LL | const VAL: T; LL | const VAL: T;
| ------------- `VAL` from trait | ------------- `VAL` from trait

View file

@ -1,4 +1,3 @@
// edition:2018
#![allow(clippy::never_loop)] #![allow(clippy::never_loop)]
async fn f() { async fn f() {

View file

@ -0,0 +1,7 @@
#![warn(clippy::undocumented_unsafe_blocks)]
#![allow(clippy::no_effect)]
#[path = "auxiliary/ice-7868-aux.rs"]
mod zero;
fn main() {}

View file

@ -0,0 +1,15 @@
error: unsafe block missing a safety comment
--> $DIR/auxiliary/ice-7868-aux.rs:2:5
|
LL | unsafe { 0 };
| ^^^^^^^^^^^^
|
= note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
help: consider adding a safety comment
|
LL ~ // Safety: ...
LL ~ unsafe { 0 };
|
error: aborting due to previous error

View file

@ -0,0 +1,7 @@
enum Tila {
TyöAlkoi,
TyöKeskeytyi,
TyöValmis,
}
fn main() {}

View file

@ -0,0 +1,15 @@
error: all variants have the same prefix: `Työ`
--> $DIR/ice-7869.rs:1:1
|
LL | / enum Tila {
LL | | TyöAlkoi,
LL | | TyöKeskeytyi,
LL | | TyöValmis,
LL | | }
| |_^
|
= note: `-D clippy::enum-variant-names` implied by `-D warnings`
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: aborting due to previous error

View file

@ -1,5 +1,3 @@
// edition:2018
use serde::Deserialize; use serde::Deserialize;
/// Tests that we do not lint for unused underscores in a `MacroAttribute` /// Tests that we do not lint for unused underscores in a `MacroAttribute`

View file

@ -1,9 +1,9 @@
// compile-flags: --edition=2018
#![feature(custom_inner_attributes)] #![feature(custom_inner_attributes)]
#![rustfmt::skip] #![rustfmt::skip]
#![warn(clippy::debug_assert_with_mut_call)] #![warn(clippy::debug_assert_with_mut_call)]
#![allow(clippy::redundant_closure_call)] #![allow(clippy::redundant_closure_call)]
struct S; struct S;
impl S { impl S {

View file

@ -1,19 +1,18 @@
#[warn(clippy::unstable_as_slice)] #![warn(clippy::should_assert_eq)]
#[warn(clippy::unstable_as_mut_slice)] #![warn(clippy::extend_from_slice)]
#[warn(clippy::misaligned_transmute)] #![warn(clippy::range_step_by_zero)]
#[warn(clippy::unused_collect)] #![warn(clippy::unstable_as_slice)]
#[warn(clippy::invalid_ref)] #![warn(clippy::unstable_as_mut_slice)]
#[warn(clippy::into_iter_on_array)] #![warn(clippy::misaligned_transmute)]
#[warn(clippy::unused_label)] #![warn(clippy::assign_ops)]
#[warn(clippy::regex_macro)] #![warn(clippy::if_let_redundant_pattern_matching)]
#[warn(clippy::drop_bounds)] #![warn(clippy::unsafe_vector_initialization)]
#[warn(clippy::temporary_cstring_as_ptr)] #![warn(clippy::unused_collect)]
#[warn(clippy::panic_params)] #![warn(clippy::replace_consts)]
#[warn(clippy::unknown_clippy_lints)] #![warn(clippy::regex_macro)]
#[warn(clippy::find_map)] #![warn(clippy::find_map)]
#[warn(clippy::filter_map)] #![warn(clippy::filter_map)]
#[warn(clippy::pub_enum_variant_names)] #![warn(clippy::pub_enum_variant_names)]
#[warn(clippy::wrong_pub_self_convention)] #![warn(clippy::wrong_pub_self_convention)]
#[warn(clippy::invalid_atomic_ordering)]
fn main() {} fn main() {}

View file

@ -1,106 +1,100 @@
error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
--> $DIR/deprecated.rs:1:8 --> $DIR/deprecated.rs:1:9
| |
LL | #[warn(clippy::unstable_as_slice)] LL | #![warn(clippy::should_assert_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: `-D renamed-and-removed-lints` implied by `-D warnings` = note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
--> $DIR/deprecated.rs:2:8 --> $DIR/deprecated.rs:2:9
| |
LL | #[warn(clippy::unstable_as_mut_slice)] LL | #![warn(clippy::extend_from_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
--> $DIR/deprecated.rs:3:9
|
LL | #![warn(clippy::range_step_by_zero)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
--> $DIR/deprecated.rs:4:9
|
LL | #![warn(clippy::unstable_as_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
--> $DIR/deprecated.rs:5:9
|
LL | #![warn(clippy::unstable_as_mut_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
--> $DIR/deprecated.rs:3:8 --> $DIR/deprecated.rs:6:9
| |
LL | #[warn(clippy::misaligned_transmute)] LL | #![warn(clippy::misaligned_transmute)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
--> $DIR/deprecated.rs:7:9
|
LL | #![warn(clippy::assign_ops)]
| ^^^^^^^^^^^^^^^^^^
error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
--> $DIR/deprecated.rs:8:9
|
LL | #![warn(clippy::if_let_redundant_pattern_matching)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
--> $DIR/deprecated.rs:9:9
|
LL | #![warn(clippy::unsafe_vector_initialization)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
--> $DIR/deprecated.rs:4:8 --> $DIR/deprecated.rs:10:9
| |
LL | #[warn(clippy::unused_collect)] LL | #![warn(clippy::unused_collect)]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::invalid_ref` has been renamed to `invalid_value` error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
--> $DIR/deprecated.rs:5:8 --> $DIR/deprecated.rs:11:9
| |
LL | #[warn(clippy::invalid_ref)] LL | #![warn(clippy::replace_consts)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` | ^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> $DIR/deprecated.rs:6:8
|
LL | #[warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> $DIR/deprecated.rs:7:8
|
LL | #[warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018 error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
--> $DIR/deprecated.rs:8:8 --> $DIR/deprecated.rs:12:9
| |
LL | #[warn(clippy::regex_macro)] LL | #![warn(clippy::regex_macro)]
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> $DIR/deprecated.rs:9:8
|
LL | #[warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
--> $DIR/deprecated.rs:10:8
|
LL | #[warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> $DIR/deprecated.rs:11:8
|
LL | #[warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> $DIR/deprecated.rs:12:8
|
LL | #[warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
--> $DIR/deprecated.rs:13:8 --> $DIR/deprecated.rs:13:9
| |
LL | #[warn(clippy::find_map)] LL | #![warn(clippy::find_map)]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
--> $DIR/deprecated.rs:14:8 --> $DIR/deprecated.rs:14:9
| |
LL | #[warn(clippy::filter_map)] LL | #![warn(clippy::filter_map)]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
--> $DIR/deprecated.rs:15:8 --> $DIR/deprecated.rs:15:9
| |
LL | #[warn(clippy::pub_enum_variant_names)] LL | #![warn(clippy::pub_enum_variant_names)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
--> $DIR/deprecated.rs:16:8 --> $DIR/deprecated.rs:16:9
| |
LL | #[warn(clippy::wrong_pub_self_convention)] LL | #![warn(clippy::wrong_pub_self_convention)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` error: aborting due to 16 previous errors
--> $DIR/deprecated.rs:17:8
|
LL | #[warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: aborting due to 17 previous errors

View file

@ -1,6 +1,5 @@
#![warn(clippy::diverging_sub_expression)] #![warn(clippy::diverging_sub_expression)]
#![allow(clippy::match_same_arms, clippy::logic_bug)] #![allow(clippy::match_same_arms, clippy::logic_bug)]
#[allow(clippy::empty_loop)] #[allow(clippy::empty_loop)]
fn diverge() -> ! { fn diverge() -> ! {
loop {} loop {}

View file

@ -1,5 +1,5 @@
error: sub-expression diverges error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:20:10 --> $DIR/diverging_sub_expression.rs:19:10
| |
LL | b || diverge(); LL | b || diverge();
| ^^^^^^^^^ | ^^^^^^^^^
@ -7,34 +7,42 @@ LL | b || diverge();
= note: `-D clippy::diverging-sub-expression` implied by `-D warnings` = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
error: sub-expression diverges error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:21:10 --> $DIR/diverging_sub_expression.rs:20:10
| |
LL | b || A.foo(); LL | b || A.foo();
| ^^^^^^^ | ^^^^^^^
error: sub-expression diverges error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:30:26 --> $DIR/diverging_sub_expression.rs:29:26
| |
LL | 6 => true || return, LL | 6 => true || return,
| ^^^^^^ | ^^^^^^
error: sub-expression diverges error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:31:26 --> $DIR/diverging_sub_expression.rs:30:26
| |
LL | 7 => true || continue, LL | 7 => true || continue,
| ^^^^^^^^ | ^^^^^^^^
error: sub-expression diverges error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:34:26 --> $DIR/diverging_sub_expression.rs:33:26
| |
LL | 3 => true || diverge(), LL | 3 => true || diverge(),
| ^^^^^^^^^ | ^^^^^^^^^
error: sub-expression diverges error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:39:26 --> $DIR/diverging_sub_expression.rs:36:30
|
LL | _ => true || panic!("boo"),
| ^^^^^^^^^^^^^
|
= note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:38:26
| |
LL | _ => true || break, LL | _ => true || break,
| ^^^^^ | ^^^^^
error: aborting due to 6 previous errors error: aborting due to 7 previous errors

View file

@ -0,0 +1,215 @@
// run-rustfix
//! This file tests for the `DOC_MARKDOWN` lint.
#![allow(dead_code, incomplete_features)]
#![warn(clippy::doc_markdown)]
#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
#![rustfmt::skip]
/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there)
/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun`
/// which should be reported only once despite being __doubly bad__.
/// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though.
/// Import an item from `::awesome::global::blob::` (Intended postfix)
/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
/// That's not code ~`NotInCodeBlock`~.
/// `be_sure_we_got_to_the_end_of_it`
fn foo_bar() {
}
/// That one tests multiline ticks.
/// ```rust
/// foo_bar FOO_BAR
/// _foo bar_
/// ```
///
/// ~~~rust
/// foo_bar FOO_BAR
/// _foo bar_
/// ~~~
/// `be_sure_we_got_to_the_end_of_it`
fn multiline_codeblock() {
}
/// This _is a test for
/// multiline
/// emphasis_.
/// `be_sure_we_got_to_the_end_of_it`
fn test_emphasis() {
}
/// This tests units. See also #835.
/// kiB MiB GiB TiB PiB EiB
/// kib Mib Gib Tib Pib Eib
/// kB MB GB TB PB EB
/// kb Mb Gb Tb Pb Eb
/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
/// 32kB 32MB 32GB 32TB 32PB 32EB
/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
/// NaN
/// `be_sure_we_got_to_the_end_of_it`
fn test_units() {
}
/// This tests allowed identifiers.
/// KiB MiB GiB TiB PiB EiB
/// DirectX
/// ECMAScript
/// GPLv2 GPLv3
/// GitHub GitLab
/// IPv4 IPv6
/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
/// NaN NaNs
/// OAuth GraphQL
/// OCaml
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
/// WebGL
/// TensorFlow
/// TrueType
/// iOS macOS FreeBSD
/// TeX LaTeX BibTeX BibLaTeX
/// MinGW
/// CamelCase (see also #2395)
/// `be_sure_we_got_to_the_end_of_it`
fn test_allowed() {
}
/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
/// It can also be [`inline_link2`].
///
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
/// [inline_link]: https://foobar
/// [inline_link2]: https://foobar
/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
/// `multiline_ticks` functions.
///
/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
/// `be_sure_we_got_to_the_end_of_it`
fn main() {
foo_bar();
multiline_codeblock();
test_emphasis();
test_units();
}
/// ## `CamelCaseThing`
/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
///
/// # `CamelCaseThing`
///
/// Not a title #897 `CamelCaseThing`
/// `be_sure_we_got_to_the_end_of_it`
fn issue897() {
}
/// I am confused by brackets? (`x_y`)
/// I am confused by brackets? (foo `x_y`)
/// I am confused by brackets? (`x_y` foo)
/// `be_sure_we_got_to_the_end_of_it`
fn issue900() {
}
/// Diesel queries also have a similar problem to [Iterator][iterator], where
/// /// More talking
/// returning them from a function requires exposing the implementation of that
/// function. The [`helper_types`][helper_types] module exists to help with this,
/// but you might want to hide the return type or have it conditionally change.
/// Boxing can achieve both.
///
/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
/// [helper_types]: ../helper_types/index.html
/// `be_sure_we_got_to_the_end_of_it`
fn issue883() {
}
/// `foo_bar
/// baz_quz`
/// [foo
/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
fn multiline() {
}
/** E.g., serialization of an empty list: `FooBar`
```
That's in a code block: `PackedNode`
```
And `BarQuz` too.
`be_sure_we_got_to_the_end_of_it`
*/
fn issue1073() {
}
/** E.g., serialization of an empty list: `FooBar`
```
That's in a code block: PackedNode
```
And `BarQuz` too.
`be_sure_we_got_to_the_end_of_it`
*/
fn issue1073_alt() {
}
/// Tests more than three quotes:
/// ````
/// DoNotWarn
/// ```
/// StillDont
/// ````
/// `be_sure_we_got_to_the_end_of_it`
fn four_quotes() {
}
#[cfg_attr(feature = "a", doc = " ```")]
#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
/// fn main() {
/// let s = "localhost:10000".to_string();
/// println!("{}", s);
/// }
/// ```
fn issue_1469() {}
/**
* This is a doc comment that should not be a list
*This would also be an error under a strict common mark interpretation
*/
fn issue_1920() {}
/// An iterator over `mycrate::Collection`'s values.
/// It should not lint a `'static` lifetime in ticks.
fn issue_2210() {}
/// This should not cause the lint to trigger:
/// #REQ-data-family.lint_partof_exists
fn issue_2343() {}
/// This should not cause an ICE:
/// __|_ _|__||_|
fn pulldown_cmark_crash() {}
/// This should not lint
/// (regression test for #7758)
/// [plain text][path::to::item]
fn intra_doc_link() {}
// issue #7033 - generic_const_exprs ICE
struct S<T, const N: usize>
where [(); N.checked_next_power_of_two().unwrap()]: {
arr: [T; N.checked_next_power_of_two().unwrap()],
n: usize,
}
impl<T: Copy + Default, const N: usize> S<T, N>
where [(); N.checked_next_power_of_two().unwrap()]: {
fn new() -> Self {
Self {
arr: [T::default(); N.checked_next_power_of_two().unwrap()],
n: 0,
}
}
}

View file

@ -1,3 +1,4 @@
// run-rustfix
//! This file tests for the `DOC_MARKDOWN` lint. //! This file tests for the `DOC_MARKDOWN` lint.
#![allow(dead_code, incomplete_features)] #![allow(dead_code, incomplete_features)]
@ -8,7 +9,9 @@
/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
/// which should be reported only once despite being __doubly bad__. /// which should be reported only once despite being __doubly bad__.
/// Here be ::a::global:path. /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
/// Import an item from ::awesome::global::blob:: (Intended postfix)
/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
/// That's not code ~NotInCodeBlock~. /// That's not code ~NotInCodeBlock~.
/// be_sure_we_got_to_the_end_of_it /// be_sure_we_got_to_the_end_of_it
fn foo_bar() { fn foo_bar() {
@ -162,12 +165,6 @@ fn issue1073_alt() {
fn four_quotes() { fn four_quotes() {
} }
/// See [NIST SP 800-56A, revision 2].
///
/// [NIST SP 800-56A, revision 2]:
/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
fn issue_902_comment() {}
#[cfg_attr(feature = "a", doc = " ```")] #[cfg_attr(feature = "a", doc = " ```")]
#[cfg_attr(not(feature = "a"), doc = " ```ignore")] #[cfg_attr(not(feature = "a"), doc = " ```ignore")]
/// fn main() { /// fn main() {
@ -183,14 +180,6 @@ fn issue_1469() {}
*/ */
fn issue_1920() {} fn issue_1920() {}
/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
///
/// Not ok: http://www.unicode.org
/// Not ok: https://www.unicode.org
/// Not ok: http://www.unicode.org/
/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
fn issue_1832() {}
/// An iterator over mycrate::Collection's values. /// An iterator over mycrate::Collection's values.
/// It should not lint a `'static` lifetime in ticks. /// It should not lint a `'static` lifetime in ticks.
fn issue_2210() {} fn issue_2210() {}

View file

@ -0,0 +1,184 @@
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:9:9
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^ help: try: ``foo_bar``
|
= note: `-D clippy::doc-markdown` implied by `-D warnings`
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:9:51
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^^ help: try: ``foo::bar``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:10:83
|
LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
| ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:12:13
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
| ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:12:36
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:13:25
|
LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:14:31
|
LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
| ^^^^^ help: try: ``::Cat``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:15:22
|
LL | /// That's not code ~NotInCodeBlock~.
| ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:16:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:30:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:37:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:51:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:74:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:78:22
|
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
| ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:81:21
|
LL | /// It can also be [inline_link2].
| ^^^^^^^^^^^^ help: try: ``inline_link2``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:91:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:99:8
|
LL | /// ## CamelCaseThing
| ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:102:7
|
LL | /// # CamelCaseThing
| ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:104:22
|
LL | /// Not a title #897 CamelCaseThing
| ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:105:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:112:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:125:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:136:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^ help: try: ``FooBar``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:141:5
|
LL | And BarQuz too.
| ^^^^^^ help: try: ``BarQuz``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:142:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:147:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^ help: try: ``FooBar``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:152:5
|
LL | And BarQuz too.
| ^^^^^^ help: try: ``BarQuz``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:153:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:164:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:183:22
|
LL | /// An iterator over mycrate::Collection's values.
| ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
error: aborting due to 30 previous errors

View file

@ -1,190 +0,0 @@
error: you should put `foo_bar` between ticks in the documentation
--> $DIR/doc.rs:8:9
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^
|
= note: `-D clippy::doc-markdown` implied by `-D warnings`
error: you should put `foo::bar` between ticks in the documentation
--> $DIR/doc.rs:8:51
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^^
error: you should put `Foo::some_fun` between ticks in the documentation
--> $DIR/doc.rs:9:83
|
LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
| ^^^^^^^^^^^^^
error: you should put `a::global:path` between ticks in the documentation
--> $DIR/doc.rs:11:15
|
LL | /// Here be ::a::global:path.
| ^^^^^^^^^^^^^^
error: you should put `NotInCodeBlock` between ticks in the documentation
--> $DIR/doc.rs:12:22
|
LL | /// That's not code ~NotInCodeBlock~.
| ^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:13:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:27:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:34:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:48:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:71:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `link_with_underscores` between ticks in the documentation
--> $DIR/doc.rs:75:22
|
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
| ^^^^^^^^^^^^^^^^^^^^^
error: you should put `inline_link2` between ticks in the documentation
--> $DIR/doc.rs:78:21
|
LL | /// It can also be [inline_link2].
| ^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:88:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:96:8
|
LL | /// ## CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:99:7
|
LL | /// # CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:101:22
|
LL | /// Not a title #897 CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:102:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:109:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:122:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `FooBar` between ticks in the documentation
--> $DIR/doc.rs:133:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
error: you should put `BarQuz` between ticks in the documentation
--> $DIR/doc.rs:138:5
|
LL | And BarQuz too.
| ^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:139:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `FooBar` between ticks in the documentation
--> $DIR/doc.rs:144:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
error: you should put `BarQuz` between ticks in the documentation
--> $DIR/doc.rs:149:5
|
LL | And BarQuz too.
| ^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:150:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:161:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:188:13
|
LL | /// Not ok: http://www.unicode.org
| ^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:189:13
|
LL | /// Not ok: https://www.unicode.org
| ^^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:190:13
|
LL | /// Not ok: http://www.unicode.org/
| ^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:191:13
|
LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `mycrate::Collection` between ticks in the documentation
--> $DIR/doc.rs:194:22
|
LL | /// An iterator over mycrate::Collection's values.
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 31 previous errors

View file

@ -0,0 +1,9 @@
/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
///
/// Not ok: http://www.unicode.org
/// Not ok: https://www.unicode.org
/// Not ok: http://www.unicode.org/
/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
fn issue_1832() {}
fn main() {}

View file

@ -0,0 +1,7 @@
/// See [NIST SP 800-56A, revision 2].
///
/// [NIST SP 800-56A, revision 2]:
/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
fn issue_902_comment() {}
fn main() {}

View file

@ -18,11 +18,11 @@ LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
| |
= help: a backtick may be missing a pair = help: a backtick may be missing a pair
error: you should put `should_be` between ticks in the documentation error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:15:32 --> $DIR/unbalanced_ticks.rs:15:32
| |
LL | /// This paragraph is fine and should_be linted normally. LL | /// This paragraph is fine and should_be linted normally.
| ^^^^^^^^^ | ^^^^^^^^^ help: try: ``should_be``
error: backticks are unbalanced error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:17:1 --> $DIR/unbalanced_ticks.rs:17:1
@ -32,11 +32,11 @@ LL | /// Double unbalanced backtick from ``here to here` should lint.
| |
= help: a backtick may be missing a pair = help: a backtick may be missing a pair
error: you should put `not_fine` between ticks in the documentation error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:30:8 --> $DIR/unbalanced_ticks.rs:30:8
| |
LL | /// ## not_fine LL | /// ## not_fine
| ^^^^^^^^ | ^^^^^^^^ help: try: ``not_fine``
error: backticks are unbalanced error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:32:1 --> $DIR/unbalanced_ticks.rs:32:1
@ -54,11 +54,11 @@ LL | /// - This `item has unbalanced tick marks
| |
= help: a backtick may be missing a pair = help: a backtick may be missing a pair
error: you should put `backticks_here` between ticks in the documentation error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:35:23 --> $DIR/unbalanced_ticks.rs:35:23
| |
LL | /// - This item needs backticks_here LL | /// - This item needs backticks_here
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ help: try: ``backticks_here``
error: aborting due to 8 previous errors error: aborting due to 8 previous errors

View file

@ -1,4 +1,3 @@
// edition:2018
#![warn(clippy::missing_errors_doc)] #![warn(clippy::missing_errors_doc)]
#![allow(clippy::result_unit_err)] #![allow(clippy::result_unit_err)]
#![allow(clippy::unnecessary_wraps)] #![allow(clippy::unnecessary_wraps)]

View file

@ -1,5 +1,5 @@
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:8:1 --> $DIR/doc_errors.rs:7:1
| |
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!(); LL | | unimplemented!();
@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::missing-errors-doc` implied by `-D warnings` = note: `-D clippy::missing-errors-doc` implied by `-D warnings`
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:12:1 --> $DIR/doc_errors.rs:11:1
| |
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!(); LL | | unimplemented!();
@ -17,7 +17,7 @@ LL | | }
| |_^ | |_^
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:17:1 --> $DIR/doc_errors.rs:16:1
| |
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!(); LL | | unimplemented!();
@ -25,7 +25,7 @@ LL | | }
| |_^ | |_^
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:22:1 --> $DIR/doc_errors.rs:21:1
| |
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!(); LL | | unimplemented!();
@ -33,7 +33,7 @@ LL | | }
| |_^ | |_^
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:52:5 --> $DIR/doc_errors.rs:51:5
| |
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!(); LL | | unimplemented!();
@ -41,7 +41,7 @@ LL | | }
| |_____^ | |_____^
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:57:5 --> $DIR/doc_errors.rs:56:5
| |
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!(); LL | | unimplemented!();
@ -49,7 +49,7 @@ LL | | }
| |_____^ | |_____^
error: docs for function returning `Result` missing `# Errors` section error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:86:5 --> $DIR/doc_errors.rs:85:5
| |
LL | fn trait_method_missing_errors_header() -> Result<(), ()>; LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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