mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-26 06:30:32 +00:00
Merge commit 'e18101137866b79045fee0ef996e696e68c920b4' into clippyup
This commit is contained in:
parent
c2cbf55323
commit
e674d0a599
220 changed files with 3219 additions and 1550 deletions
3
.github/deploy.sh
vendored
3
.github/deploy.sh
vendored
|
@ -13,7 +13,8 @@ cp util/gh-pages/lints.json out/master
|
|||
if [[ -n $TAG_NAME ]]; then
|
||||
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
|
||||
cp -Tr out/master "out/$TAG_NAME"
|
||||
ln -sf "$TAG_NAME" out/stable
|
||||
rm -f out/stable
|
||||
ln -s "$TAG_NAME" out/stable
|
||||
fi
|
||||
|
||||
if [[ $BETA = "true" ]]; then
|
||||
|
|
166
CHANGELOG.md
166
CHANGELOG.md
|
@ -6,11 +6,162 @@ document.
|
|||
|
||||
## 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
|
||||
|
||||
Current beta, release 2021-10-21
|
||||
Current stable, released 2021-10-21
|
||||
|
||||
[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
|
||||
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
|
||||
|
||||
Current stable, released 2021-09-09
|
||||
Released 2021-09-09
|
||||
|
||||
[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_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_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
|
||||
[`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
|
||||
|
@ -2806,6 +2952,7 @@ Released 2018-09-13
|
|||
[`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
|
||||
[`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_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
|
||||
|
@ -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_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
|
||||
[`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
|
||||
[`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
|
||||
|
@ -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_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_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
|
||||
[`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
|
||||
|
@ -3046,6 +3195,7 @@ Released 2018-09-13
|
|||
[`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_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
|
||||
[`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
|
||||
|
|
|
@ -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`.
|
||||
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
|
||||
```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
|
||||
```
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true }
|
|||
|
||||
[dev-dependencies]
|
||||
cargo_metadata = "0.14"
|
||||
compiletest_rs = { version = "0.7", features = ["tmp"] }
|
||||
compiletest_rs = { version = "0.7.1", features = ["tmp"] }
|
||||
tester = "0.9"
|
||||
regex = "1.5"
|
||||
# This is used by the `collect-metadata` alias.
|
||||
|
|
|
@ -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_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<()> {
|
||||
|
@ -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 inner(path: &Path, contents: &[u8]) -> io::Result<()> {
|
||||
OpenOptions::new()
|
||||
|
@ -151,7 +179,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
};
|
||||
|
||||
let lint_name = lint.name;
|
||||
let pass_name = lint.pass;
|
||||
let category = lint.category;
|
||||
let name_camel = to_camel_case(lint.name);
|
||||
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});
|
||||
}}
|
||||
|
||||
// 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 test to `tests/ui/min_rust_version_attr.rs`.
|
||||
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
|
||||
"},
|
||||
pass_type = pass_type,
|
||||
pass_lifetimes = pass_lifetimes,
|
||||
pass_name = pass_name,
|
||||
name_upper = name_upper,
|
||||
name_camel = name_camel,
|
||||
module_name = lint_name,
|
||||
context_import = context_import,
|
||||
)
|
||||
} else {
|
||||
|
@ -248,16 +271,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
declare_lint_pass!({name_camel} => [{name_upper}]);
|
||||
|
||||
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_lifetimes = pass_lifetimes,
|
||||
pass_name = pass_name,
|
||||
name_upper = name_upper,
|
||||
name_camel = name_camel,
|
||||
module_name = lint_name,
|
||||
)
|
||||
});
|
||||
|
||||
|
|
|
@ -1,15 +1,88 @@
|
|||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::expr_or_init;
|
||||
use clippy_utils::ty::is_isize_or_usize;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
|
||||
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()) {
|
||||
(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 (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
|
||||
|
|
|
@ -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_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) {
|
||||
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_precision_loss::check(cx, expr, cast_from, cast_to);
|
||||
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
|
|
|
@ -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
|
||||
/// enables the simple extraction of the metadata without changing the current deprecation
|
||||
/// declaration.
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
|||
target_mut,
|
||||
},
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
|
||||
use clippy_utils::source::first_line_of_span;
|
||||
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, snippet_with_applicability};
|
||||
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 if_chain::if_chain;
|
||||
|
@ -10,7 +10,7 @@ use rustc_ast::token::CommentKind;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::emitter::EmitterWriter;
|
||||
use rustc_errors::Handler;
|
||||
use rustc_errors::{Applicability, Handler};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
|
||||
|
@ -48,7 +48,7 @@ declare_clippy_lint! {
|
|||
/// content are not linted.
|
||||
///
|
||||
/// 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
|
||||
/// 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
|
||||
continue;
|
||||
}
|
||||
headers.safety |= in_heading && text.trim() == "Safety";
|
||||
headers.errors |= in_heading && text.trim() == "Errors";
|
||||
headers.panics |= in_heading && text.trim() == "Panics";
|
||||
let trimmed_text = text.trim();
|
||||
headers.safety |= in_heading && trimmed_text == "Safety";
|
||||
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 is_rust {
|
||||
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 == '\'') {
|
||||
// Trim punctuation as in `some comment (see foo::bar).`
|
||||
// ^^
|
||||
// Or even as in `_foo bar_` which is emphasized.
|
||||
let word = word.trim_matches(|c: char| !c.is_alphanumeric());
|
||||
// Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
return;
|
||||
}
|
||||
|
||||
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
|
||||
span_lint(
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
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`
|
||||
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
||||
let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
|
||||
if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
|
||||
|| is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
|
||||
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
|
||||
if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|
||||
|| is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
|
||||
{
|
||||
self.panic_span = Some(expr.span);
|
||||
}
|
||||
|
|
|
@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map
|
|||
ExprKind::MethodCall(
|
||||
_,
|
||||
_,
|
||||
[map, Expr {
|
||||
kind: ExprKind::AddrOf(_, _, key),
|
||||
span: key_span,
|
||||
..
|
||||
}],
|
||||
[
|
||||
map,
|
||||
Expr {
|
||||
kind: ExprKind::AddrOf(_, _, key),
|
||||
span: key_span,
|
||||
..
|
||||
},
|
||||
],
|
||||
_,
|
||||
) if key_span.ctxt() == expr.span.ctxt() => {
|
||||
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! 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::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_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [
|
|||
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(
|
||||
cx: &LateContext<'_>,
|
||||
threshold: u64,
|
||||
|
@ -150,7 +130,7 @@ fn check_variant(
|
|||
}
|
||||
for var in def.variants {
|
||||
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 + 1).map_or(false, |c| !c.is_numeric())
|
||||
{
|
||||
|
@ -161,7 +141,7 @@ fn check_variant(
|
|||
"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(
|
||||
cx,
|
||||
ENUM_VARIANT_NAMES,
|
||||
|
@ -171,14 +151,14 @@ fn check_variant(
|
|||
}
|
||||
}
|
||||
let first = &def.variants[0].ident.name.as_str();
|
||||
let mut pre = &first[..camel_case::until(&*first)];
|
||||
let mut post = &first[camel_case::from(&*first)..];
|
||||
let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
|
||||
let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
|
||||
for var in def.variants {
|
||||
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];
|
||||
let pre_camel = camel_case::until(pre);
|
||||
let pre_camel = str_utils::camel_case_until(pre).byte_index;
|
||||
pre = &pre[..pre_camel];
|
||||
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
|
||||
if next.is_numeric() {
|
||||
|
@ -186,18 +166,18 @@ fn check_variant(
|
|||
}
|
||||
if next.is_lowercase() {
|
||||
let last = pre.len() - last.len_utf8();
|
||||
let last_camel = camel_case::until(&pre[..last]);
|
||||
pre = &pre[..last_camel];
|
||||
let last_camel = str_utils::camel_case_until(&pre[..last]);
|
||||
pre = &pre[..last_camel.byte_index];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let post_match = partial_rmatch(post, &name);
|
||||
let post_end = post.len() - post_match;
|
||||
let post_match = count_match_end(post, &name);
|
||||
let post_end = post.len() - post_match.byte_count;
|
||||
post = &post[post_end..];
|
||||
let post_camel = camel_case::from(post);
|
||||
post = &post[post_camel..];
|
||||
let post_camel = str_utils::camel_case_start(post);
|
||||
post = &post[post_camel.byte_index..];
|
||||
}
|
||||
let (what, value) = match (pre.is_empty(), post.is_empty()) {
|
||||
(true, true) => return,
|
||||
|
@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
);
|
||||
}
|
||||
}
|
||||
if item.vis.node.is_pub() {
|
||||
let matching = partial_match(mod_camel, &item_camel);
|
||||
let rmatching = partial_rmatch(mod_camel, &item_camel);
|
||||
// The `module_name_repetitions` lint should only trigger if the item has the module in its
|
||||
// name. Having the same name is accepted.
|
||||
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 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) {
|
||||
Some(c) if is_word_beginning(c) => span_lint(
|
||||
cx,
|
||||
|
@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
_ => (),
|
||||
}
|
||||
}
|
||||
if rmatching == nchars {
|
||||
if rmatching.char_count == nchars {
|
||||
span_lint(
|
||||
cx,
|
||||
MODULE_NAME_REPETITIONS,
|
||||
|
|
|
@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
|
|||
}
|
||||
match *cx.typeck_results().expr_adjustments(arg) {
|
||||
[] => true,
|
||||
[Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
..
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
|
||||
..
|
||||
}] => {
|
||||
[
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
|
||||
..
|
||||
},
|
||||
] => {
|
||||
// re-borrow with the same mutability is allowed
|
||||
let ty = cx.typeck_results().expr_ty(arg);
|
||||
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
|
||||
|
|
|
@ -49,15 +49,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
|||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
if format_args.value_args.is_empty() {
|
||||
if_chain! {
|
||||
if let [e] = &*format_args.format_string_parts;
|
||||
if let ExprKind::Lit(lit) = &e.kind;
|
||||
if let Some(s_src) = snippet_opt(cx, lit.span);
|
||||
then {
|
||||
// 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);
|
||||
if format_args.format_string_parts.is_empty() {
|
||||
span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
|
||||
} else {
|
||||
if_chain! {
|
||||
if let [e] = &*format_args.format_string_parts;
|
||||
if let ExprKind::Lit(lit) = &e.kind;
|
||||
if let Some(s_src) = snippet_opt(cx, lit.span);
|
||||
then {
|
||||
// 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 {
|
||||
|
@ -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) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
//! on the condition
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use clippy_utils::is_else_clause;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -46,14 +46,21 @@ declare_clippy_lint! {
|
|||
|
||||
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
|
||||
|
||||
impl EarlyLintPass for IfNotElse {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
impl LateLintPass<'_> for IfNotElse {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
|
||||
// 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;
|
||||
}
|
||||
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 {
|
||||
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, _) => {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
|
|
@ -89,7 +89,7 @@ impl IntPlusOne {
|
|||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
},
|
||||
// case where `x + 1 <= ...` or `1 + x <= ...`
|
||||
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
|
||||
if lhskind.node == BinOpKind::Add =>
|
||||
|
@ -104,7 +104,7 @@ impl IntPlusOne {
|
|||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
},
|
||||
// case where `... >= y - 1` or `... >= -1 + y`
|
||||
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
|
||||
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
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_span::Span;
|
||||
|
||||
use clippy_utils::comparisons;
|
||||
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::source::snippet;
|
||||
use clippy_utils::{comparisons, sext};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -39,53 +37,6 @@ declare_clippy_lint! {
|
|||
|
||||
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)> {
|
||||
if let ExprKind::Cast(cast_exp, _) = expr.kind {
|
||||
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) {
|
||||
if let ExprKind::Cast(cast_val, _) = expr.kind {
|
||||
span_lint(
|
||||
|
@ -156,7 +94,7 @@ fn upcast_comparison_bounds_err<'tcx>(
|
|||
invert: bool,
|
||||
) {
|
||||
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 norm_rhs_val < lb || norm_rhs_val > ub {
|
||||
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
|
||||
|
|
|
@ -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(identity_op::IDENTITY_OP),
|
||||
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(infinite_iter::INFINITE_ITER),
|
||||
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_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
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(option_env_unwrap::OPTION_ENV_UNWRAP),
|
||||
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(unicode::INVISIBLE_CHARACTERS),
|
||||
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_types::UNIT_ARG),
|
||||
LintId::of(unit_types::UNIT_CMP),
|
||||
|
|
|
@ -64,6 +64,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
|
|||
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
|
||||
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
||||
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_types::UNIT_CMP),
|
||||
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
|
|
|
@ -159,7 +159,6 @@ store.register_lints(&[
|
|||
identity_op::IDENTITY_OP,
|
||||
if_let_mutex::IF_LET_MUTEX,
|
||||
if_not_else::IF_NOT_ELSE,
|
||||
if_then_panic::IF_THEN_PANIC,
|
||||
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
|
||||
implicit_hasher::IMPLICIT_HASHER,
|
||||
implicit_return::IMPLICIT_RETURN,
|
||||
|
@ -216,6 +215,7 @@ store.register_lints(&[
|
|||
loops::WHILE_LET_ON_ITERATOR,
|
||||
macro_use::MACRO_USE_IMPORTS,
|
||||
main_recursion::MAIN_RECURSION,
|
||||
manual_assert::MANUAL_ASSERT,
|
||||
manual_async_fn::MANUAL_ASYNC_FN,
|
||||
manual_map::MANUAL_MAP,
|
||||
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
|
||||
|
@ -327,6 +327,7 @@ store.register_lints(&[
|
|||
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
|
||||
misc_early::MIXED_CASE_HEX_LITERALS,
|
||||
misc_early::REDUNDANT_PATTERN,
|
||||
misc_early::SEPARATED_LITERAL_SUFFIX,
|
||||
misc_early::UNNEEDED_FIELD_PATTERN,
|
||||
misc_early::UNNEEDED_WILDCARD_PATTERN,
|
||||
misc_early::UNSEPARATED_LITERAL_SUFFIX,
|
||||
|
@ -431,6 +432,7 @@ store.register_lints(&[
|
|||
strings::STRING_ADD_ASSIGN,
|
||||
strings::STRING_FROM_UTF8_AS_BYTES,
|
||||
strings::STRING_LIT_AS_BYTES,
|
||||
strings::STRING_SLICE,
|
||||
strings::STRING_TO_STRING,
|
||||
strings::STR_TO_STRING,
|
||||
strlen_on_c_strings::STRLEN_ON_C_STRINGS,
|
||||
|
@ -476,6 +478,7 @@ store.register_lints(&[
|
|||
unicode::NON_ASCII_LITERAL,
|
||||
unicode::UNICODE_NOT_NFC,
|
||||
uninit_vec::UNINIT_VEC,
|
||||
unit_hash::UNIT_HASH,
|
||||
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
|
||||
unit_types::LET_UNIT_VALUE,
|
||||
unit_types::UNIT_ARG,
|
||||
|
|
|
@ -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(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
|
||||
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(option_if_let_else::OPTION_IF_LET_ELSE),
|
||||
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
|
||||
|
|
|
@ -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_ITER_LOOP),
|
||||
LintId::of(macro_use::MACRO_USE_IMPORTS),
|
||||
LintId::of(manual_assert::MANUAL_ASSERT),
|
||||
LintId::of(manual_ok_or::MANUAL_OK_OR),
|
||||
LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
|
||||
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(misc::FLOAT_CMP),
|
||||
LintId::of(misc::USED_UNDERSCORE_BINDING),
|
||||
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
|
||||
LintId::of(mut_mut::MUT_MUT),
|
||||
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
|
||||
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(types::LINKEDLIST),
|
||||
LintId::of(types::OPTION_OPTION),
|
||||
LintId::of(unicode::NON_ASCII_LITERAL),
|
||||
LintId::of(unicode::UNICODE_NOT_NFC),
|
||||
LintId::of(unit_types::LET_UNIT_VALUE),
|
||||
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
|
||||
|
|
|
@ -35,7 +35,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
|
|||
LintId::of(methods::GET_UNWRAP),
|
||||
LintId::of(methods::UNWRAP_USED),
|
||||
LintId::of(misc::FLOAT_CMP_CONST),
|
||||
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
|
||||
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_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
|
||||
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_UNRELATED),
|
||||
LintId::of(strings::STRING_ADD),
|
||||
LintId::of(strings::STRING_SLICE),
|
||||
LintId::of(strings::STRING_TO_STRING),
|
||||
LintId::of(strings::STR_TO_STRING),
|
||||
LintId::of(types::RC_BUFFER),
|
||||
LintId::of(types::RC_MUTEX),
|
||||
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
|
||||
LintId::of(unicode::NON_ASCII_LITERAL),
|
||||
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
|
||||
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
|
||||
LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
|
||||
|
|
|
@ -27,7 +27,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
|
|||
LintId::of(functions::DOUBLE_MUST_USE),
|
||||
LintId::of(functions::MUST_USE_UNIT),
|
||||
LintId::of(functions::RESULT_UNIT_ERR),
|
||||
LintId::of(if_then_panic::IF_THEN_PANIC),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
LintId::of(len_zero::COMPARISON_TO_EMPTY),
|
||||
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
|
||||
|
|
|
@ -15,6 +15,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
|
|||
LintId::of(loops::MUT_RANGE_BOUND),
|
||||
LintId::of(methods::SUSPICIOUS_MAP),
|
||||
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_OP_ASSIGN_IMPL),
|
||||
])
|
||||
|
|
|
@ -228,7 +228,6 @@ mod get_last_with_len;
|
|||
mod identity_op;
|
||||
mod if_let_mutex;
|
||||
mod if_not_else;
|
||||
mod if_then_panic;
|
||||
mod if_then_some_else_none;
|
||||
mod implicit_hasher;
|
||||
mod implicit_return;
|
||||
|
@ -255,6 +254,7 @@ mod literal_representation;
|
|||
mod loops;
|
||||
mod macro_use;
|
||||
mod main_recursion;
|
||||
mod manual_assert;
|
||||
mod manual_async_fn;
|
||||
mod manual_map;
|
||||
mod manual_non_exhaustive;
|
||||
|
@ -364,6 +364,7 @@ mod undocumented_unsafe_blocks;
|
|||
mod undropped_manually_drops;
|
||||
mod unicode;
|
||||
mod uninit_vec;
|
||||
mod unit_hash;
|
||||
mod unit_return_expecting_ord;
|
||||
mod unit_types;
|
||||
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(unicode::Unicode));
|
||||
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(strings::StringAdd));
|
||||
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_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(if_not_else::IfNotElse));
|
||||
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(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(future_not_send::FutureNotSend));
|
||||
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(mut_mutex_lock::MutMutexLock));
|
||||
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(feature_name::FeatureName));
|
||||
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;
|
||||
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(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
|
||||
store.register_late_pass(move || Box::new(format_args::FormatArgs));
|
||||
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]
|
||||
|
@ -828,6 +830,7 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
|
|||
///
|
||||
/// Used in `./src/driver.rs`.
|
||||
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::new_without_default_derive", "clippy::new_without_default");
|
||||
ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
|
||||
|
|
|
@ -378,11 +378,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
|
|||
|
||||
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
|
||||
match ty.kind {
|
||||
TyKind::OpaqueDef(item, _) => {
|
||||
TyKind::OpaqueDef(item, bounds) => {
|
||||
let map = self.cx.tcx.hir();
|
||||
let item = map.item(item);
|
||||
walk_item(self, item);
|
||||
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, .. }) => {
|
||||
let mut sub_visitor = RefVisitor::new(self.cx);
|
||||
|
|
|
@ -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(),
|
||||
meth_name,
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => format!(
|
||||
"{}.into_iter()",
|
||||
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
|
||||
|
|
|
@ -26,14 +26,14 @@ declare_clippy_lint! {
|
|||
/// let sad_people: Vec<&str> = vec![];
|
||||
/// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
|
||||
/// ```
|
||||
pub IF_THEN_PANIC,
|
||||
style,
|
||||
pub MANUAL_ASSERT,
|
||||
pedantic,
|
||||
"`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<'_>) {
|
||||
if_chain! {
|
||||
if let Expr {
|
||||
|
@ -54,23 +54,24 @@ impl LateLintPass<'_> for IfThenPanic {
|
|||
if !cx.tcx.sess.source_map().is_multiline(cond.span);
|
||||
|
||||
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 {
|
||||
[] => panic_expn.format_args.format_string_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 {
|
||||
if_chain! {
|
||||
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
|
||||
}
|
||||
}
|
||||
return
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
|
||||
|
@ -86,7 +87,7 @@ impl LateLintPass<'_> for IfThenPanic {
|
|||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IF_THEN_PANIC,
|
||||
MANUAL_ASSERT,
|
||||
expr.span,
|
||||
"only a `panic!` in `if`-then statement",
|
||||
"try",
|
|
@ -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)> {
|
||||
let case_check = match case_method {
|
||||
CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) },
|
||||
CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) },
|
||||
CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) },
|
||||
CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) },
|
||||
CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
|
||||
CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
|
||||
CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
|
||||
CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
|
||||
};
|
||||
|
||||
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) {
|
||||
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::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
|
||||
CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),
|
||||
|
|
|
@ -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::{
|
||||
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<'_>]) {
|
||||
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 type_ranges = type_ranges(&ranges);
|
||||
if !type_ranges.is_empty() {
|
||||
if let Some((start, end)) = overlapping(&type_ranges) {
|
||||
if !ranges.is_empty() {
|
||||
if let Some((start, end)) = overlapping(&ranges) {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
MATCH_OVERLAPPING_ARM,
|
||||
|
@ -968,8 +967,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
|
|||
}
|
||||
if_chain! {
|
||||
if matching_wild;
|
||||
if let ExprKind::Block(block, _) = arm.body.kind;
|
||||
if is_panic_block(block);
|
||||
if is_panic_call(arm.body);
|
||||
then {
|
||||
// `Err(_)` or `Err(_e)` arm with `panic!` found
|
||||
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)
|
||||
fn is_panic_block(block: &Block<'_>) -> bool {
|
||||
match (&block.expr, block.stmts.len(), block.stmts.first()) {
|
||||
(&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
|
||||
(&None, 1, Some(stmt)) => {
|
||||
is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
fn is_panic_call(expr: &Expr<'_>) -> bool {
|
||||
// Unwrap any wrapping blocks
|
||||
let span = if let ExprKind::Block(block, _) = expr.kind {
|
||||
match (&block.expr, block.stmts.len(), block.stmts.first()) {
|
||||
(&Some(exp), 0, _) => exp.span,
|
||||
(&None, 1, Some(stmt)) => stmt.span,
|
||||
_ => 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<'_>)
|
||||
|
@ -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.
|
||||
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()
|
||||
.filter_map(|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,
|
||||
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
|
||||
};
|
||||
let rhs = match range_end {
|
||||
RangeEnd::Included => Bound::Included(rhs),
|
||||
RangeEnd::Excluded => Bound::Excluded(rhs),
|
||||
|
||||
let lhs_val = lhs.int_value(cx, ty)?;
|
||||
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 {
|
||||
span: pat.span,
|
||||
node: (lhs, rhs),
|
||||
node: (lhs_val, rhs_bound),
|
||||
});
|
||||
}
|
||||
|
||||
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 {
|
||||
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>),
|
||||
}
|
||||
|
||||
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`
|
||||
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
||||
matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
|
||||
|
|
|
@ -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) =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
|
||||
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
|
||||
| ExprKind::Field(..)
|
||||
|
@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
|
|||
) =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ pub(super) fn check<'tcx>(
|
|||
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::MiscEarlyLints;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast::{Expr, ExprKind, UnOp};
|
||||
use rustc_lint::EarlyContext;
|
||||
|
@ -6,18 +5,14 @@ use rustc_lint::EarlyContext;
|
|||
use super::DOUBLE_NEG;
|
||||
|
||||
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
match expr.kind {
|
||||
ExprKind::Unary(UnOp::Neg, ref inner) => {
|
||||
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
|
||||
span_lint(
|
||||
cx,
|
||||
DOUBLE_NEG,
|
||||
expr.span,
|
||||
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
|
||||
);
|
||||
}
|
||||
},
|
||||
ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
|
||||
_ => (),
|
||||
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
|
||||
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
|
||||
span_lint(
|
||||
cx,
|
||||
DOUBLE_NEG,
|
||||
expr.span,
|
||||
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
38
clippy_lints/src/misc_early/literal_suffix.rs
Normal file
38
clippy_lints/src/misc_early/literal_suffix.rs
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
mod builtin_type_shadow;
|
||||
mod double_neg;
|
||||
mod literal_suffix;
|
||||
mod mixed_case_hex_literals;
|
||||
mod redundant_pattern;
|
||||
mod unneeded_field_pattern;
|
||||
mod unneeded_wildcard_pattern;
|
||||
mod unseparated_literal_suffix;
|
||||
mod zero_prefixed_literal;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
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_data_structures::fx::FxHashMap;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
|
@ -115,9 +115,11 @@ declare_clippy_lint! {
|
|||
/// ### What it does
|
||||
/// Warns if literal suffixes are not separated by an
|
||||
/// underscore.
|
||||
/// To enforce unseparated literal suffix style,
|
||||
/// see the `separated_literal_suffix` lint.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It is much less readable.
|
||||
/// Suffix style should be consistent.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
|
@ -128,10 +130,32 @@ declare_clippy_lint! {
|
|||
/// let y = 123832_i32;
|
||||
/// ```
|
||||
pub UNSEPARATED_LITERAL_SUFFIX,
|
||||
pedantic,
|
||||
restriction,
|
||||
"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! {
|
||||
/// ### What it does
|
||||
/// Warns if an integral constant literal starts with `0`.
|
||||
|
@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [
|
|||
DOUBLE_NEG,
|
||||
MIXED_CASE_HEX_LITERALS,
|
||||
UNSEPARATED_LITERAL_SUFFIX,
|
||||
SEPARATED_LITERAL_SUFFIX,
|
||||
ZERO_PREFIXED_LITERAL,
|
||||
BUILTIN_TYPE_SHADOW,
|
||||
REDUNDANT_PATTERN,
|
||||
|
@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints {
|
|||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::Lit(ref lit) = expr.kind {
|
||||
MiscEarlyLints::check_lit(cx, lit);
|
||||
}
|
||||
double_neg::check(cx, expr);
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +361,7 @@ impl MiscEarlyLints {
|
|||
LitIntType::Unsigned(ty) => ty.name_str(),
|
||||
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") {
|
||||
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
|
||||
} 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 {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -106,7 +106,7 @@ impl EarlyLintPass for ModStyle {
|
|||
}
|
||||
process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
|
||||
check_self_named_mod_exists(cx, path, file);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,14 +107,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
|
|||
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
|
||||
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
|
||||
for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
|
||||
if let [Adjustment {
|
||||
kind: Adjust::Deref(_), ..
|
||||
}, Adjustment {
|
||||
kind: Adjust::Deref(_), ..
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(_),
|
||||
..
|
||||
}] = *adj3
|
||||
if let [
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_), ..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_), ..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Borrow(_),
|
||||
..
|
||||
},
|
||||
] = *adj3
|
||||
{
|
||||
let help_msg_ty = if matches!(mutability, Mutability::Not) {
|
||||
format!("&{}", ty)
|
||||
|
|
|
@ -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)
|
||||
/// or specify correct bounds on generic type parameters (`T: Send`).
|
||||
pub NON_SEND_FIELDS_IN_SEND_TY,
|
||||
nursery,
|
||||
suspicious,
|
||||
"there is field that does not implement `Send` in a `Send` struct"
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ declare_clippy_lint! {
|
|||
/// expression).
|
||||
///
|
||||
/// ### 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.
|
||||
///
|
||||
/// ### Known problems
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::ptr::get_spans;
|
||||
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 if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{
|
||||
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
|
||||
ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
|
||||
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
|
||||
Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
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 {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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)]
|
||||
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, 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();
|
||||
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
|
||||
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.
|
||||
if let Some(body) = &body {
|
||||
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() {
|
||||
if is_type_diagnostic_item(cx, ty, sym::Vec) {
|
||||
let (item_name, path) = if_chain! {
|
||||
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()")]) {
|
||||
span_lint_and_then(
|
||||
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", "")]) {
|
||||
span_lint_and_then(
|
||||
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", "")]) {
|
||||
span_lint_and_then(
|
||||
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 let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
|
||||
if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
|
||||
if let [ref bx] = *pp.segments;
|
||||
if let [ref bx] = *path.segments;
|
||||
if let Some(params) = bx.args;
|
||||
if !params.parenthesized;
|
||||
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:
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,23 +172,17 @@ impl QuestionMark {
|
|||
}
|
||||
}
|
||||
|
||||
fn expression_returns_unmodified_err(
|
||||
cx: &LateContext<'_>,
|
||||
expression: &Expr<'_>,
|
||||
origin_hir_id: &Expr<'_>,
|
||||
) -> bool {
|
||||
match expression.kind {
|
||||
fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Block(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
|
||||
},
|
||||
ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => {
|
||||
Self::expression_returns_unmodified_err(cx, expr, origin_hir_id)
|
||||
},
|
||||
ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id),
|
||||
ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
|
||||
ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,51 +107,87 @@ declare_clippy_lint! {
|
|||
"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 {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if in_external_macro(cx.sess(), e.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Add, ..
|
||||
},
|
||||
left,
|
||||
_,
|
||||
) = e.kind
|
||||
{
|
||||
if is_string(cx, left) {
|
||||
if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
|
||||
let parent = get_parent_expr(cx, e);
|
||||
if let Some(p) = parent {
|
||||
if let ExprKind::Assign(target, _, _) = p.kind {
|
||||
// avoid duplicate matches
|
||||
if SpanlessEq::new(cx).eq_expr(target, left) {
|
||||
return;
|
||||
match e.kind {
|
||||
ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Add, ..
|
||||
},
|
||||
left,
|
||||
_,
|
||||
) => {
|
||||
if is_string(cx, left) {
|
||||
if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
|
||||
let parent = get_parent_expr(cx, e);
|
||||
if let Some(p) = parent {
|
||||
if let ExprKind::Assign(target, _, _) = p.kind {
|
||||
// avoid duplicate matches
|
||||
if SpanlessEq::new(cx).eq_expr(target, left) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
span_lint(
|
||||
cx,
|
||||
STRING_ADD,
|
||||
e.span,
|
||||
"you added something to a string. Consider using `String::push_str()` instead",
|
||||
);
|
||||
}
|
||||
span_lint(
|
||||
cx,
|
||||
STRING_ADD,
|
||||
e.span,
|
||||
"you added something to a string. Consider using `String::push_str()` instead",
|
||||
);
|
||||
}
|
||||
} else if let ExprKind::Assign(target, src, _) = e.kind {
|
||||
if is_string(cx, target) && is_add(cx, src, target) {
|
||||
span_lint(
|
||||
cx,
|
||||
STRING_ADD_ASSIGN,
|
||||
e.span,
|
||||
"you assigned the result of adding something to this string. Consider using \
|
||||
`String::push_str()` instead",
|
||||
);
|
||||
}
|
||||
},
|
||||
ExprKind::Assign(target, src, _) => {
|
||||
if is_string(cx, target) && is_add(cx, src, target) {
|
||||
span_lint(
|
||||
cx,
|
||||
STRING_ADD_ASSIGN,
|
||||
e.span,
|
||||
"you assigned the result of adding something to this string. Consider using \
|
||||
`String::push_str()` instead",
|
||||
);
|
||||
}
|
||||
},
|
||||
ExprKind::Index(target, _idx) => {
|
||||
let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||
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",
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,8 +145,9 @@ impl UndocumentedUnsafeBlocks {
|
|||
let file_name = source_map.span_to_filename(between_span);
|
||||
let source_file = source_map.get_source_file(&file_name)?;
|
||||
|
||||
let lex_start = (between_span.lo().0 + 1) as usize;
|
||||
let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
|
||||
let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
|
||||
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 comment = false;
|
||||
|
|
|
@ -45,7 +45,7 @@ declare_clippy_lint! {
|
|||
/// let x = String::from("\u{20ac}");
|
||||
/// ```
|
||||
pub NON_ASCII_LITERAL,
|
||||
pedantic,
|
||||
restriction,
|
||||
"using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
|
||||
}
|
||||
|
||||
|
|
77
clippy_lints/src/unit_hash.rs
Normal file
77
clippy_lints/src/unit_hash.rs
Normal 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");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ use rustc_span::{sym, Span};
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### 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?
|
||||
/// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
|
||||
|
|
|
@ -288,10 +288,10 @@ define_Conf! {
|
|||
///
|
||||
/// 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()),
|
||||
/// Lint: RESTRICTED_SCRIPTS.
|
||||
/// Lint: DISALLOWED_SCRIPT_IDENTS.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
|
||||
|
|
|
@ -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 docs = String::from(&*lines.next()?.as_str());
|
||||
let mut in_code_block = false;
|
||||
let mut is_code_block_rust = false;
|
||||
for line in lines {
|
||||
docs.push('\n');
|
||||
let line = line.as_str();
|
||||
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("```") {
|
||||
in_code_block = !in_code_block;
|
||||
is_code_block_rust = false;
|
||||
if in_code_block {
|
||||
let lang = info
|
||||
.trim()
|
||||
|
@ -528,6 +537,8 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
|
|||
.unwrap_or("rust");
|
||||
docs.push_str("```");
|
||||
docs.push_str(lang);
|
||||
|
||||
is_code_block_rust = lang == "rust";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -155,6 +155,19 @@ impl Constant {
|
|||
_ => 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`.
|
||||
|
@ -202,6 +215,52 @@ pub fn constant_simple<'tcx>(
|
|||
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`.
|
||||
pub fn constant_context<'a, 'tcx>(
|
||||
lcx: &'a LateContext<'tcx>,
|
||||
|
|
|
@ -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;
|
||||
/// | ^^^^^^^^^^^^
|
||||
/// |
|
||||
/// = 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>(
|
||||
cx: &'a T,
|
||||
|
|
|
@ -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)]
|
||||
|
||||
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 rustc_ast::ast::{self, LitKind};
|
||||
use rustc_hir as 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_span::{sym, symbol, ExpnKind, Span, Symbol};
|
||||
|
@ -513,6 +513,8 @@ pub struct FormatArgsExpn<'tcx> {
|
|||
pub format_string_parts: &'tcx [Expr<'tcx>],
|
||||
/// Symbols corresponding to [`Self::format_string_parts`]
|
||||
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)`
|
||||
pub args: &'tcx [Expr<'tcx>],
|
||||
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable
|
||||
|
@ -557,6 +559,7 @@ impl FormatArgsExpn<'tcx> {
|
|||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
|
||||
if let ExprKind::Array(args) = arm.body.kind;
|
||||
then {
|
||||
Some(FormatArgsExpn {
|
||||
|
@ -564,6 +567,7 @@ impl FormatArgsExpn<'tcx> {
|
|||
value_args,
|
||||
format_string_parts,
|
||||
format_string_symbols,
|
||||
arg_names,
|
||||
args,
|
||||
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 ExprKind::Lit(lit) = &position_field.expr.kind;
|
||||
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 {
|
||||
let i = usize::try_from(position).unwrap();
|
||||
Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
|
||||
Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -718,9 +728,7 @@ impl PanicExpn<'tcx> {
|
|||
/// Parses an expanded `panic!` invocation
|
||||
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
|
||||
if_chain! {
|
||||
if let ExprKind::Block(block, _) = expr.kind;
|
||||
if let Some(init) = block.expr;
|
||||
if let ExprKind::Call(_, [format_args]) = init.kind;
|
||||
if let ExprKind::Call(_, [format_args]) = expr.kind;
|
||||
let expn_data = expr.span.ctxt().outer_expn_data();
|
||||
if let Some(format_args) = FormatArgsExpn::parse(format_args);
|
||||
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));
|
||||
}
|
||||
}
|
||||
},
|
||||
ExprKind::Path(QPath::Resolved(_, path))
|
||||
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) =>
|
||||
{
|
||||
return Some(VecInitKind::Default);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ pub mod sym_helper;
|
|||
#[allow(clippy::module_name_repetitions)]
|
||||
pub mod ast_utils;
|
||||
pub mod attrs;
|
||||
pub mod camel_case;
|
||||
pub mod comparisons;
|
||||
pub mod consts;
|
||||
pub mod diagnostics;
|
||||
|
@ -50,6 +49,7 @@ pub mod paths;
|
|||
pub mod ptr;
|
||||
pub mod qualify_min_const_fn;
|
||||
pub mod source;
|
||||
pub mod str_utils;
|
||||
pub mod sugg;
|
||||
pub mod ty;
|
||||
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.
|
||||
/// Currently checks for:
|
||||
/// * Break/Continue outside the given loop HIR ids.
|
||||
/// * Yield/Return statments.
|
||||
/// * Yield/Return statements.
|
||||
/// * Inline assembly.
|
||||
/// * 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;
|
||||
|
||||
for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
|
||||
if let [Adjustment {
|
||||
kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
|
||||
target,
|
||||
}, ref adjust @ ..] = *cx
|
||||
if let [
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
|
||||
target,
|
||||
},
|
||||
ref adjust @ ..,
|
||||
] = *cx
|
||||
.typeck_results()
|
||||
.adjustments()
|
||||
.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) {
|
||||
match node {
|
||||
Node::Expr(
|
||||
e
|
||||
@
|
||||
Expr {
|
||||
e @ Expr {
|
||||
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>> {
|
||||
if let ExprKind::Call(
|
||||
_,
|
||||
&[Expr {
|
||||
kind: ExprKind::Closure(_, _, body, _, _),
|
||||
..
|
||||
}],
|
||||
&[
|
||||
Expr {
|
||||
kind: ExprKind::Closure(_, _, body, _, _),
|
||||
..
|
||||
},
|
||||
],
|
||||
) = body.value.kind
|
||||
{
|
||||
if let ExprKind::Block(
|
||||
|
@ -2123,7 +2126,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
|||
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.
|
||||
///
|
||||
/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
|
||||
|
|
230
clippy_utils/src/str_utils.rs
Normal file
230
clippy_utils/src/str_utils.rs
Normal 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));
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ because that's clearly a non-descriptive name.
|
|||
- [Edition 2018 tests](#edition-2018-tests)
|
||||
- [Testing manually](#testing-manually)
|
||||
- [Lint declaration](#lint-declaration)
|
||||
- [Lint registration](#lint-registration)
|
||||
- [Lint passes](#lint-passes)
|
||||
- [Emitting a lint](#emitting-a-lint)
|
||||
- [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
|
||||
--category=pedantic` (category will default to nursery if not provided). This
|
||||
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
|
||||
register the new lint. For cargo lints, two project hierarchies (fail/pass) will
|
||||
be created by default under `tests/ui-cargo`.
|
||||
`clippy_lints/src/foo_functions.rs`, as well as
|
||||
[registering the lint](#lint-registration). For cargo lints, two project
|
||||
hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
|
||||
|
||||
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 {}
|
||||
```
|
||||
|
||||
Normally after declaring the lint, we have to run `cargo dev update_lints`,
|
||||
which updates some files, so Clippy knows about the new lint. Since we used
|
||||
`cargo dev new_lint ...` to generate the lint declaration, this was done
|
||||
automatically. While `update_lints` automates most of the things, it doesn't
|
||||
automate everything. We will have to register our lint pass manually in the
|
||||
`register_plugins` function in `clippy_lints/src/lib.rs`:
|
||||
[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 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
|
||||
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
|
||||
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.
|
||||
|
||||
One reason that `cargo dev` does not automate this step is that multiple lints
|
||||
can use the same lint pass, so registering the lint pass may already be done
|
||||
when adding a new lint. Another reason that this step is not automated is that
|
||||
the order that the passes are registered determines the order the passes
|
||||
actually run, which in turn affects the order that any emitted lints 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
|
||||
One reason that `cargo dev update_lints` does not automate this step is that
|
||||
multiple lints can use the same lint pass, so registering the lint pass may
|
||||
already be done when adding a new lint. Another reason that this step is not
|
||||
automated is that the order that the passes are registered determines the order
|
||||
the passes actually run, which in turn affects the order that any emitted lints
|
||||
are output in.
|
||||
|
||||
## Lint passes
|
||||
|
||||
|
@ -564,7 +567,8 @@ in the following steps:
|
|||
/// <The configuration field doc comment>
|
||||
(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:
|
||||
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
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2021-10-21"
|
||||
channel = "nightly-2021-11-04"
|
||||
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
|
||||
|
|
|
@ -104,7 +104,10 @@ fn extern_flags() -> String {
|
|||
}
|
||||
|
||||
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") {
|
||||
config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
#![feature(path_file_prefix)]
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, DirEntry};
|
||||
use std::path::Path;
|
||||
|
||||
|
@ -21,29 +24,39 @@ fn test_missing_tests() {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
// Test for missing files.
|
||||
fn explore_directory(dir: &Path) -> Vec<String> {
|
||||
let mut missing_files: Vec<String> = Vec::new();
|
||||
let mut current_file = String::new();
|
||||
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 {
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
missing_files.extend(explore_directory(&path));
|
||||
} 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() {
|
||||
match ext.to_str().unwrap() {
|
||||
"rs" => current_file = file_stem.clone(),
|
||||
"rs" => current_file = file_prefix.clone(),
|
||||
"stderr" | "stdout" => {
|
||||
if file_stem != current_file {
|
||||
if file_prefix != current_file {
|
||||
missing_files.push(path.to_str().unwrap().to_string());
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// edition:2018
|
||||
|
||||
#![warn(clippy::too_many_lines)]
|
||||
|
||||
// This function should be considered one line.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 | | println!("This is bad.");
|
||||
|
@ -10,7 +10,7 @@ LL | | }
|
|||
= note: `-D clippy::too-many-lines` implied by `-D warnings`
|
||||
|
||||
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 | | println!("This is bad.");
|
||||
|
@ -19,7 +19,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | | let _ = {
|
||||
|
@ -30,7 +30,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | | let _ = "test";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
|
||||
#![allow(non_fmt_panics)]
|
||||
|
||||
macro_rules! assert_const {
|
||||
|
@ -6,7 +7,6 @@ macro_rules! assert_const {
|
|||
debug_assert!($len < 0);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(true);
|
||||
assert!(false);
|
||||
|
@ -14,7 +14,7 @@ fn main() {
|
|||
assert!(false, "false message");
|
||||
|
||||
let msg = "panic message";
|
||||
assert!(false, msg.to_uppercase());
|
||||
assert!(false, "{}", msg.to_uppercase());
|
||||
|
||||
const B: bool = true;
|
||||
assert!(B);
|
||||
|
|
|
@ -26,22 +26,13 @@ LL | assert!(true, "true message");
|
|||
= help: remove it
|
||||
= 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
|
||||
|
|
||||
LL | assert!(false, "false message");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `panic!("false message")` or `unreachable!("false message")`
|
||||
= 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())`
|
||||
= 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!(true)` will be optimized out by the compiler
|
||||
|
@ -62,13 +53,13 @@ LL | assert!(C);
|
|||
= help: use `panic!()` or `unreachable!()`
|
||||
= 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
|
||||
|
|
||||
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)
|
||||
|
||||
error: `debug_assert!(true)` will be optimized out by the compiler
|
||||
|
@ -80,5 +71,5 @@ LL | debug_assert!(true);
|
|||
= help: remove it
|
||||
= 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
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// run-rustfix
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_closure)]
|
||||
#![warn(clippy::async_yields_async)]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// run-rustfix
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_closure)]
|
||||
#![warn(clippy::async_yields_async)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 {
|
||||
| ____________________-
|
||||
|
@ -20,7 +20,7 @@ LL + }.await
|
|||
|
|
||||
|
||||
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 {
|
||||
| ____________________-
|
||||
|
@ -33,7 +33,7 @@ LL | | };
|
|||
| |_____- outer async construct
|
||||
|
||||
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 || {
|
||||
| _______________________-
|
||||
|
@ -53,7 +53,7 @@ LL + }.await
|
|||
|
|
||||
|
||||
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 || {
|
||||
| _______________________-
|
||||
|
@ -66,7 +66,7 @@ LL | | };
|
|||
| |_____- outer async construct
|
||||
|
||||
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;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
@ -76,7 +76,7 @@ LL | let _l = async || CustomFutureType;
|
|||
| help: consider awaiting this value: `CustomFutureType.await`
|
||||
|
||||
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 || {
|
||||
| _______________________-
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// edition:2018
|
||||
#![warn(clippy::await_holding_lock)]
|
||||
|
||||
use std::sync::Mutex;
|
||||
|
|
|
@ -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
|
||||
--> $DIR/await_holding_lock.rs:7:9
|
||||
--> $DIR/await_holding_lock.rs:6:9
|
||||
|
|
||||
LL | let guard = x.lock().unwrap();
|
||||
| ^^^^^
|
||||
|
|
||||
= note: `-D clippy::await-holding-lock` implied by `-D warnings`
|
||||
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 | | 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
|
||||
--> $DIR/await_holding_lock.rs:28:9
|
||||
--> $DIR/await_holding_lock.rs:27:9
|
||||
|
|
||||
LL | let guard = x.lock().unwrap();
|
||||
| ^^^^^
|
||||
|
|
||||
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 | |
|
||||
|
@ -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
|
||||
--> $DIR/await_holding_lock.rs:41:13
|
||||
--> $DIR/await_holding_lock.rs:40:13
|
||||
|
|
||||
LL | let guard = x.lock().unwrap();
|
||||
| ^^^^^
|
||||
|
|
||||
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 | | 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
|
||||
--> $DIR/await_holding_lock.rs:53:13
|
||||
--> $DIR/await_holding_lock.rs:52:13
|
||||
|
|
||||
LL | let guard = x.lock().unwrap();
|
||||
| ^^^^^
|
||||
|
|
||||
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 | | baz().await
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// edition:2018
|
||||
#![warn(clippy::await_holding_refcell_ref)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
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();
|
||||
| ^
|
||||
|
|
||||
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
|
||||
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 | | 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
|
||||
--> $DIR/await_holding_refcell_ref.rs:12:9
|
||||
--> $DIR/await_holding_refcell_ref.rs:11:9
|
||||
|
|
||||
LL | let b = x.borrow_mut();
|
||||
| ^
|
||||
|
|
||||
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 | | 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
|
||||
--> $DIR/await_holding_refcell_ref.rs:33:9
|
||||
--> $DIR/await_holding_refcell_ref.rs:32:9
|
||||
|
|
||||
LL | let b = x.borrow_mut();
|
||||
| ^
|
||||
|
|
||||
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 | |
|
||||
|
@ -46,13 +46,13 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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();
|
||||
| ^
|
||||
|
|
||||
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 | |
|
||||
|
@ -64,13 +64,13 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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();
|
||||
| ^
|
||||
|
|
||||
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 | | 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
|
||||
--> $DIR/await_holding_refcell_ref.rs:72:13
|
||||
--> $DIR/await_holding_refcell_ref.rs:71:13
|
||||
|
|
||||
LL | let b = x.borrow_mut();
|
||||
| ^
|
||||
|
|
||||
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 | | baz().await
|
||||
|
|
|
@ -92,4 +92,27 @@ fn main() {
|
|||
(1i64).checked_rem_euclid(-1i64).unwrap() as u64;
|
||||
(1i64).checked_rem_euclid(-1i64).unwrap() as u128;
|
||||
(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
|
||||
}
|
||||
|
|
|
@ -138,5 +138,17 @@ error: casting `isize` to `usize` may lose the sign of the value
|
|||
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
|
||||
|
||||
|
|
3
tests/ui/crashes/auxiliary/ice-7868-aux.rs
Normal file
3
tests/ui/crashes/auxiliary/ice-7868-aux.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn zero() {
|
||||
unsafe { 0 };
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
// in type inference.
|
||||
#![feature(trivial_bounds)]
|
||||
#![allow(unused)]
|
||||
|
||||
trait A {}
|
||||
|
||||
impl A for i32 {}
|
||||
|
@ -22,9 +21,9 @@ where
|
|||
|
||||
fn unsized_local()
|
||||
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
|
||||
|
|
|
@ -1,30 +1,34 @@
|
|||
error: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-3969.rs:25:17
|
||||
error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
|
||||
--> $DIR/ice-3969.rs:20:10
|
||||
|
|
||||
LL | for<'a> Dst<A + 'a>: Sized,
|
||||
| ^^^^^^ help: use `dyn`: `dyn A + 'a`
|
||||
LL | str: Sized;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: `-D bare-trait-objects` 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>
|
||||
= note: `-D trivial-bounds` implied by `-D warnings`
|
||||
|
||||
error: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-3969.rs:27:16
|
||||
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:24:30
|
||||
|
|
||||
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
|
||||
| ^ 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>
|
||||
LL | for<'a> Dst<dyn A + 'a>: Sized,
|
||||
| ^^^^^
|
||||
|
||||
error: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/ice-3969.rs:27:57
|
||||
error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
|
||||
--> $DIR/ice-3969.rs:31:10
|
||||
|
|
||||
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
|
||||
| ^ help: use `dyn`: `dyn A`
|
||||
LL | str: Sized,
|
||||
| ^^^^^
|
||||
|
||||
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!
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||
LL | String: ::std::ops::Neg<Output = String>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// edition:2018
|
||||
|
||||
// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
|
||||
|
||||
pub async fn bar<'a, T: 'a>(_: T) {}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// originally from glacier fixed/77919.rs
|
||||
// encountered errors resolving bounds after type-checking
|
||||
|
||||
trait TypeVal<T> {
|
||||
const VAL: T;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
error[E0412]: cannot find type `PhantomData` in this scope
|
||||
--> $DIR/ice-6252.rs:9:9
|
||||
--> $DIR/ice-6252.rs:8:9
|
||||
|
|
||||
LL | _n: PhantomData,
|
||||
| ^^^^^^^^^^^ 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;
|
||||
|
|
||||
|
||||
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> {}
|
||||
| - ^^^ 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`
|
||||
|
||||
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;
|
||||
| ------------- `VAL` from trait
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// edition:2018
|
||||
#![allow(clippy::never_loop)]
|
||||
|
||||
async fn f() {
|
||||
|
|
7
tests/ui/crashes/ice-7868.rs
Normal file
7
tests/ui/crashes/ice-7868.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#![warn(clippy::undocumented_unsafe_blocks)]
|
||||
#![allow(clippy::no_effect)]
|
||||
|
||||
#[path = "auxiliary/ice-7868-aux.rs"]
|
||||
mod zero;
|
||||
|
||||
fn main() {}
|
15
tests/ui/crashes/ice-7868.stderr
Normal file
15
tests/ui/crashes/ice-7868.stderr
Normal 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
|
||||
|
7
tests/ui/crashes/ice-7869.rs
Normal file
7
tests/ui/crashes/ice-7869.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
enum Tila {
|
||||
TyöAlkoi,
|
||||
TyöKeskeytyi,
|
||||
TyöValmis,
|
||||
}
|
||||
|
||||
fn main() {}
|
15
tests/ui/crashes/ice-7869.stderr
Normal file
15
tests/ui/crashes/ice-7869.stderr
Normal 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
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// edition:2018
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Tests that we do not lint for unused underscores in a `MacroAttribute`
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// compile-flags: --edition=2018
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![rustfmt::skip]
|
||||
#![warn(clippy::debug_assert_with_mut_call)]
|
||||
#![allow(clippy::redundant_closure_call)]
|
||||
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
#[warn(clippy::unstable_as_slice)]
|
||||
#[warn(clippy::unstable_as_mut_slice)]
|
||||
#[warn(clippy::misaligned_transmute)]
|
||||
#[warn(clippy::unused_collect)]
|
||||
#[warn(clippy::invalid_ref)]
|
||||
#[warn(clippy::into_iter_on_array)]
|
||||
#[warn(clippy::unused_label)]
|
||||
#[warn(clippy::regex_macro)]
|
||||
#[warn(clippy::drop_bounds)]
|
||||
#[warn(clippy::temporary_cstring_as_ptr)]
|
||||
#[warn(clippy::panic_params)]
|
||||
#[warn(clippy::unknown_clippy_lints)]
|
||||
#[warn(clippy::find_map)]
|
||||
#[warn(clippy::filter_map)]
|
||||
#[warn(clippy::pub_enum_variant_names)]
|
||||
#[warn(clippy::wrong_pub_self_convention)]
|
||||
#[warn(clippy::invalid_atomic_ordering)]
|
||||
#![warn(clippy::should_assert_eq)]
|
||||
#![warn(clippy::extend_from_slice)]
|
||||
#![warn(clippy::range_step_by_zero)]
|
||||
#![warn(clippy::unstable_as_slice)]
|
||||
#![warn(clippy::unstable_as_mut_slice)]
|
||||
#![warn(clippy::misaligned_transmute)]
|
||||
#![warn(clippy::assign_ops)]
|
||||
#![warn(clippy::if_let_redundant_pattern_matching)]
|
||||
#![warn(clippy::unsafe_vector_initialization)]
|
||||
#![warn(clippy::unused_collect)]
|
||||
#![warn(clippy::replace_consts)]
|
||||
#![warn(clippy::regex_macro)]
|
||||
#![warn(clippy::find_map)]
|
||||
#![warn(clippy::filter_map)]
|
||||
#![warn(clippy::pub_enum_variant_names)]
|
||||
#![warn(clippy::wrong_pub_self_convention)]
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,106 +1,100 @@
|
|||
error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
|
||||
--> $DIR/deprecated.rs:1:8
|
||||
error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
|
||||
--> $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`
|
||||
|
||||
error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
|
||||
--> $DIR/deprecated.rs:2:8
|
||||
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: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
|
||||
--> $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
|
||||
--> $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`
|
||||
--> $DIR/deprecated.rs:5:8
|
||||
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:11:9
|
||||
|
|
||||
LL | #[warn(clippy::invalid_ref)]
|
||||
| ^^^^^^^^^^^^^^^^^^^ 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`
|
||||
LL | #![warn(clippy::replace_consts)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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`
|
||||
LL | #![warn(clippy::regex_macro)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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`
|
||||
--> $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
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#![warn(clippy::diverging_sub_expression)]
|
||||
#![allow(clippy::match_same_arms, clippy::logic_bug)]
|
||||
|
||||
#[allow(clippy::empty_loop)]
|
||||
fn diverge() -> ! {
|
||||
loop {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: sub-expression diverges
|
||||
--> $DIR/diverging_sub_expression.rs:20:10
|
||||
--> $DIR/diverging_sub_expression.rs:19:10
|
||||
|
|
||||
LL | b || diverge();
|
||||
| ^^^^^^^^^
|
||||
|
@ -7,34 +7,42 @@ LL | b || diverge();
|
|||
= note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
|
||||
|
||||
error: sub-expression diverges
|
||||
--> $DIR/diverging_sub_expression.rs:21:10
|
||||
--> $DIR/diverging_sub_expression.rs:20:10
|
||||
|
|
||||
LL | b || A.foo();
|
||||
| ^^^^^^^
|
||||
|
||||
error: sub-expression diverges
|
||||
--> $DIR/diverging_sub_expression.rs:30:26
|
||||
--> $DIR/diverging_sub_expression.rs:29:26
|
||||
|
|
||||
LL | 6 => true || return,
|
||||
| ^^^^^^
|
||||
|
||||
error: sub-expression diverges
|
||||
--> $DIR/diverging_sub_expression.rs:31:26
|
||||
--> $DIR/diverging_sub_expression.rs:30:26
|
||||
|
|
||||
LL | 7 => true || continue,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: sub-expression diverges
|
||||
--> $DIR/diverging_sub_expression.rs:34:26
|
||||
--> $DIR/diverging_sub_expression.rs:33:26
|
||||
|
|
||||
LL | 3 => true || diverge(),
|
||||
| ^^^^^^^^^
|
||||
|
||||
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,
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
215
tests/ui/doc/doc-fixable.fixed
Normal file
215
tests/ui/doc/doc-fixable.fixed
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// run-rustfix
|
||||
//! This file tests for the `DOC_MARKDOWN` lint.
|
||||
|
||||
#![allow(dead_code, incomplete_features)]
|
||||
|
@ -8,7 +9,9 @@
|
|||
/// 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.
|
||||
/// 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() {
|
||||
|
@ -162,12 +165,6 @@ fn issue1073_alt() {
|
|||
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(not(feature = "a"), doc = " ```ignore")]
|
||||
/// fn main() {
|
||||
|
@ -183,14 +180,6 @@ fn issue_1469() {}
|
|||
*/
|
||||
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.
|
||||
/// It should not lint a `'static` lifetime in ticks.
|
||||
fn issue_2210() {}
|
184
tests/ui/doc/doc-fixable.stderr
Normal file
184
tests/ui/doc/doc-fixable.stderr
Normal 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
|
||||
|
|
@ -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
|
||||
|
9
tests/ui/doc/issue_1832.rs
Normal file
9
tests/ui/doc/issue_1832.rs
Normal 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() {}
|
7
tests/ui/doc/issue_902.rs
Normal file
7
tests/ui/doc/issue_902.rs
Normal 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() {}
|
|
@ -18,11 +18,11 @@ LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
|
|||
|
|
||||
= 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
|
||||
|
|
||||
LL | /// This paragraph is fine and should_be linted normally.
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: try: ``should_be``
|
||||
|
||||
error: backticks are unbalanced
|
||||
--> $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
|
||||
|
||||
error: you should put `not_fine` between ticks in the documentation
|
||||
error: item in documentation is missing backticks
|
||||
--> $DIR/unbalanced_ticks.rs:30:8
|
||||
|
|
||||
LL | /// ## not_fine
|
||||
| ^^^^^^^^
|
||||
| ^^^^^^^^ help: try: ``not_fine``
|
||||
|
||||
error: backticks are unbalanced
|
||||
--> $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
|
||||
|
||||
error: you should put `backticks_here` between ticks in the documentation
|
||||
error: item in documentation is missing backticks
|
||||
--> $DIR/unbalanced_ticks.rs:35:23
|
||||
|
|
||||
LL | /// - This item needs backticks_here
|
||||
| ^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^ help: try: ``backticks_here``
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// edition:2018
|
||||
#![warn(clippy::missing_errors_doc)]
|
||||
#![allow(clippy::result_unit_err)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 | | unimplemented!();
|
||||
|
@ -9,7 +9,7 @@ LL | | }
|
|||
= note: `-D clippy::missing-errors-doc` implied by `-D warnings`
|
||||
|
||||
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 | | unimplemented!();
|
||||
|
@ -17,7 +17,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | | unimplemented!();
|
||||
|
@ -25,7 +25,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | | unimplemented!();
|
||||
|
@ -33,7 +33,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
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 | | unimplemented!();
|
||||
|
@ -41,7 +41,7 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
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 | | unimplemented!();
|
||||
|
@ -49,7 +49,7 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
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<(), ()>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue