mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-22 12:43:18 +00:00
Merge commit '0eff589afc83e21a03a168497bbab6b4dfbb4ef6' into clippyup
This commit is contained in:
parent
01217f6f4c
commit
97ab44ca97
80 changed files with 1573 additions and 519 deletions
4
.github/workflows/clippy.yml
vendored
4
.github/workflows/clippy.yml
vendored
|
@ -58,6 +58,10 @@ jobs:
|
|||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
working-directory: clippy_lints
|
||||
|
||||
- name: Test clippy_utils
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
working-directory: clippy_utils
|
||||
|
||||
- name: Test rustc_tools_util
|
||||
run: cargo test --features deny-warnings
|
||||
working-directory: rustc_tools_util
|
||||
|
|
4
.github/workflows/clippy_bors.yml
vendored
4
.github/workflows/clippy_bors.yml
vendored
|
@ -121,6 +121,10 @@ jobs:
|
|||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
working-directory: clippy_lints
|
||||
|
||||
- name: Test clippy_utils
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
working-directory: clippy_utils
|
||||
|
||||
- name: Test rustc_tools_util
|
||||
run: cargo test --features deny-warnings
|
||||
working-directory: rustc_tools_util
|
||||
|
|
123
CHANGELOG.md
123
CHANGELOG.md
|
@ -6,13 +6,127 @@ document.
|
|||
|
||||
## Unreleased / In Rust Nightly
|
||||
|
||||
[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
|
||||
[e181011...master](https://github.com/rust-lang/rust-clippy/compare/e181011...master)
|
||||
|
||||
## Rust 1.58 (beta)
|
||||
|
||||
Current beta, release 2022-01-13
|
||||
|
||||
[00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011)
|
||||
|
||||
### New lints
|
||||
|
||||
* [`transmute_num_to_bytes`]
|
||||
[#7805](https://github.com/rust-lang/rust-clippy/pull/7805)
|
||||
* [`match_str_case_mismatch`]
|
||||
[#7806](https://github.com/rust-lang/rust-clippy/pull/7806)
|
||||
* [`format_in_format_args`], [`to_string_in_format_args`]
|
||||
[#7743](https://github.com/rust-lang/rust-clippy/pull/7743)
|
||||
* [`uninit_vec`]
|
||||
[#7682](https://github.com/rust-lang/rust-clippy/pull/7682)
|
||||
* [`fn_to_numeric_cast_any`]
|
||||
[#7705](https://github.com/rust-lang/rust-clippy/pull/7705)
|
||||
* [`undocumented_unsafe_blocks`]
|
||||
[#7748](https://github.com/rust-lang/rust-clippy/pull/7748)
|
||||
* [`trailing_empty_array`]
|
||||
[#7838](https://github.com/rust-lang/rust-clippy/pull/7838)
|
||||
* [`string_slice`]
|
||||
[#7878](https://github.com/rust-lang/rust-clippy/pull/7878)
|
||||
|
||||
### Moves or deprecations of lints
|
||||
|
||||
* Move [`non_send_fields_in_send_ty`] to `suspicious`
|
||||
[#7874](https://github.com/rust-lang/rust-clippy/pull/7874)
|
||||
* Move [`non_ascii_literal`] to `restriction`
|
||||
[#7907](https://github.com/rust-lang/rust-clippy/pull/7907)
|
||||
|
||||
### Changes that expand what code existing lints cover
|
||||
|
||||
* [`question_mark`] now covers `Result`
|
||||
[#7840](https://github.com/rust-lang/rust-clippy/pull/7840)
|
||||
* Make [`useless_format`] recognize bare `format!("")`
|
||||
[#7801](https://github.com/rust-lang/rust-clippy/pull/7801)
|
||||
* Lint on underscored variables with no side effects in [`no_effect`]
|
||||
[#7775](https://github.com/rust-lang/rust-clippy/pull/7775)
|
||||
* Expand [`match_ref_pats`] to check for multiple reference patterns
|
||||
[#7800](https://github.com/rust-lang/rust-clippy/pull/7800)
|
||||
|
||||
### False positive fixes
|
||||
|
||||
* Fix false positive of [`implicit_saturating_sub`] with `else` clause
|
||||
[#7832](https://github.com/rust-lang/rust-clippy/pull/7832)
|
||||
* Fix [`question_mark`] when there is call in conditional predicate
|
||||
[#7860](https://github.com/rust-lang/rust-clippy/pull/7860)
|
||||
* [`mut_mut`] no longer lints when type is defined in external macros
|
||||
[#7795](https://github.com/rust-lang/rust-clippy/pull/7795)
|
||||
* Avoid [`eq_op`] in test functions
|
||||
[#7811](https://github.com/rust-lang/rust-clippy/pull/7811)
|
||||
* [`cast_possible_truncation`] no longer lints when cast is coming from `signum`
|
||||
method call [#7850](https://github.com/rust-lang/rust-clippy/pull/7850)
|
||||
* [`match_str_case_mismatch`] no longer lints on uncased characters
|
||||
[#7865](https://github.com/rust-lang/rust-clippy/pull/7865)
|
||||
* [`ptr_arg`] no longer lints references to type aliases
|
||||
[#7890](https://github.com/rust-lang/rust-clippy/pull/7890)
|
||||
* [`missing_safety_doc`] now also accepts "implementation safety" headers
|
||||
[#7856](https://github.com/rust-lang/rust-clippy/pull/7856)
|
||||
* [`missing_safety_doc`] no longer lints if any parent has `#[doc(hidden)]`
|
||||
attribute [#7849](https://github.com/rust-lang/rust-clippy/pull/7849)
|
||||
* [`if_not_else`] now ignores else-if statements
|
||||
[#7895](https://github.com/rust-lang/rust-clippy/pull/7895)
|
||||
* Avoid linting [`cast_possible_truncation`] on bit-reducing operations
|
||||
[#7819](https://github.com/rust-lang/rust-clippy/pull/7819)
|
||||
* Avoid linting [`field_reassign_with_default`] when `Drop` and `Copy` are
|
||||
involved [#7794](https://github.com/rust-lang/rust-clippy/pull/7794)
|
||||
* [`unnecessary_sort_by`] now checks if argument implements `Ord` trait
|
||||
[#7824](https://github.com/rust-lang/rust-clippy/pull/7824)
|
||||
* Fix false positive in [`match_overlapping_arm`]
|
||||
[#7847](https://github.com/rust-lang/rust-clippy/pull/7847)
|
||||
* Prevent [`needless_lifetimes`] false positive in `async` function definition
|
||||
[#7901](https://github.com/rust-lang/rust-clippy/pull/7901)
|
||||
|
||||
### Suggestion fixes/improvements
|
||||
|
||||
* Keep an initial `::` when [`doc_markdown`] suggests to use ticks
|
||||
[#7916](https://github.com/rust-lang/rust-clippy/pull/7916)
|
||||
* Add a machine applicable suggestion for the [`doc_markdown`] missing backticks
|
||||
lint [#7904](https://github.com/rust-lang/rust-clippy/pull/7904)
|
||||
* [`equatable_if_let`] no longer expands macros in the suggestion
|
||||
[#7788](https://github.com/rust-lang/rust-clippy/pull/7788)
|
||||
* Make [`shadow_reuse`] suggestion less verbose
|
||||
[#7782](https://github.com/rust-lang/rust-clippy/pull/7782)
|
||||
|
||||
### ICE fixes
|
||||
|
||||
* Fix ICE in [`enum_variant_names`]
|
||||
[#7873](https://github.com/rust-lang/rust-clippy/pull/7873)
|
||||
* Fix ICE in [`undocumented_unsafe_blocks`]
|
||||
[#7891](https://github.com/rust-lang/rust-clippy/pull/7891)
|
||||
|
||||
### Documentation improvements
|
||||
|
||||
* Fixed naive doc formatting for `#[must_use]` lints ([`must_use_unit`],
|
||||
[`double_must_use`], [`must_use_candidate`], [`let_underscore_must_use`])
|
||||
[#7827](https://github.com/rust-lang/rust-clippy/pull/7827)
|
||||
* Fix typo in example for [`match_result_ok`]
|
||||
[#7815](https://github.com/rust-lang/rust-clippy/pull/7815)
|
||||
|
||||
### Others
|
||||
|
||||
* Allow giving reasons for [`disallowed_types`]
|
||||
[#7791](https://github.com/rust-lang/rust-clippy/pull/7791)
|
||||
* Fix [`manual_assert`] and [`match_wild_err_arm`] for `#![no_std]` and Rust
|
||||
2021. [#7851](https://github.com/rust-lang/rust-clippy/pull/7851)
|
||||
* Fix regression in [`semicolon_if_nothing_returned`] on macros containing while
|
||||
loops [#7789](https://github.com/rust-lang/rust-clippy/pull/7789)
|
||||
* Added a new configuration `literal-suffix-style` to enforce a certain style
|
||||
writing [`unseparated_literal_suffix`]
|
||||
[#7726](https://github.com/rust-lang/rust-clippy/pull/7726)
|
||||
|
||||
## Rust 1.57
|
||||
|
||||
Current beta, release 2021-12-02
|
||||
Current stable, released 2021-12-02
|
||||
|
||||
[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
|
||||
[7bfc26e...00e31fa](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...00e31fa)
|
||||
|
||||
### New Lints
|
||||
|
||||
|
@ -161,7 +275,7 @@ Current beta, release 2021-12-02
|
|||
|
||||
## Rust 1.56
|
||||
|
||||
Current stable, released 2021-10-21
|
||||
Released 2021-10-21
|
||||
|
||||
[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
|
||||
|
||||
|
@ -2912,6 +3026,7 @@ Released 2018-09-13
|
|||
[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
|
||||
[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
|
||||
[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
|
||||
[`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields
|
||||
[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
|
||||
[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
|
||||
[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
|
||||
|
|
|
@ -118,7 +118,7 @@ which `IntelliJ Rust` will be able to understand.
|
|||
Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo
|
||||
you just cloned.
|
||||
The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
|
||||
Clippys `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses.
|
||||
Clippy's `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses.
|
||||
Just make sure to remove the dependencies again before finally making a pull request!
|
||||
|
||||
[rustc_repo]: https://github.com/rust-lang/rust/
|
||||
|
@ -126,8 +126,8 @@ Just make sure to remove the dependencies again before finally making a pull req
|
|||
|
||||
### Rust Analyzer
|
||||
As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals
|
||||
using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippys `Cargo.toml.`
|
||||
You will required a `nightly` toolchain with the `rustc-dev` component installed.
|
||||
using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippy's `Cargo.toml.`
|
||||
You will require a `nightly` toolchain with the `rustc-dev` component installed.
|
||||
Make sure that in the `rust-analyzer` configuration, you set
|
||||
```
|
||||
{ "rust-analyzer.rustcSource": "discover" }
|
||||
|
@ -228,7 +228,7 @@ about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree].
|
|||
|
||||
### Patching git-subtree to work with big repos
|
||||
|
||||
Currently there's a bug in `git-subtree` that prevents it from working properly
|
||||
Currently, there's a bug in `git-subtree` that prevents it from working properly
|
||||
with the [`rust-lang/rust`] repo. There's an open PR to fix that, but it's stale.
|
||||
Before continuing with the following steps, we need to manually apply that fix to
|
||||
our local copy of `git-subtree`.
|
||||
|
|
10
README.md
10
README.md
|
@ -144,7 +144,7 @@ line. (You can swap `clippy::all` with the specific lint category you are target
|
|||
## Configuration
|
||||
|
||||
Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable =
|
||||
value` mapping eg.
|
||||
value` mapping e.g.
|
||||
|
||||
```toml
|
||||
avoid-breaking-exported-api = false
|
||||
|
@ -155,6 +155,10 @@ cognitive-complexity-threshold = 30
|
|||
See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which
|
||||
lints can be configured and the meaning of the variables.
|
||||
|
||||
Note that configuration changes will not apply for code that has already been compiled and cached under `./target/`;
|
||||
for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure that
|
||||
any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch.
|
||||
|
||||
To deactivate the “for further information visit *lint-link*” message you can
|
||||
define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
|
||||
|
||||
|
@ -193,7 +197,7 @@ And to warn on `lint_name`, run
|
|||
cargo clippy -- -W clippy::lint_name
|
||||
```
|
||||
|
||||
This also works with lint groups. For example you
|
||||
This also works with lint groups. For example, you
|
||||
can run Clippy with warnings for all lints enabled:
|
||||
```terminal
|
||||
cargo clippy -- -W clippy::pedantic
|
||||
|
@ -228,7 +232,7 @@ fn main() {
|
|||
You can also omit the patch version when specifying the MSRV, so `msrv = 1.30`
|
||||
is equivalent to `msrv = 1.30.0`.
|
||||
|
||||
Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly.
|
||||
Note: `custom_inner_attributes` is an unstable feature, so it has to be enabled explicitly.
|
||||
|
||||
Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv)
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ impl ApproxConstant {
|
|||
let s = s.as_str();
|
||||
if s.parse::<f64>().is_ok() {
|
||||
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
|
||||
if is_approx_const(constant, &s, min_digits)
|
||||
if is_approx_const(constant, s, min_digits)
|
||||
&& msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv))
|
||||
{
|
||||
span_lint_and_help(
|
||||
|
|
|
@ -310,8 +310,10 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
|
|||
|| is_word(lint, sym::deprecated)
|
||||
|| is_word(lint, sym!(unreachable_pub))
|
||||
|| is_word(lint, sym!(unused))
|
||||
|| extract_clippy_lint(lint).map_or(false, |s| s.as_str() == "wildcard_imports")
|
||||
|| extract_clippy_lint(lint).map_or(false, |s| s.as_str() == "enum_glob_use")
|
||||
|| extract_clippy_lint(lint)
|
||||
.map_or(false, |s| s.as_str() == "wildcard_imports")
|
||||
|| extract_clippy_lint(lint)
|
||||
.map_or(false, |s| s.as_str() == "enum_glob_use")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -49,8 +49,9 @@ pub(super) fn check(
|
|||
if cast_from.kind() == cast_to.kind() =>
|
||||
{
|
||||
if let Some(src) = snippet_opt(cx, lit.span) {
|
||||
let num_lit = NumericLiteral::from_lit_kind(&src, &lit.node).unwrap();
|
||||
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
|
||||
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
|
||||
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
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 clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
|
||||
use rustc_hir::{EnumDef, Item, ItemKind, Variant};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
|
@ -18,6 +18,12 @@ declare_clippy_lint! {
|
|||
/// Enumeration variant names should specify their variant,
|
||||
/// not repeat the enumeration name.
|
||||
///
|
||||
/// ### Limitations
|
||||
/// Characters with no casing will be considered when comparing prefixes/suffixes
|
||||
/// This applies to numbers and non-ascii characters without casing
|
||||
/// e.g. `Foo1` and `Foo2` is considered to have different prefixes
|
||||
/// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹`
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// enum Cake {
|
||||
|
@ -120,72 +126,73 @@ impl_lint_pass!(EnumVariantNames => [
|
|||
MODULE_INCEPTION
|
||||
]);
|
||||
|
||||
fn check_variant(
|
||||
cx: &LateContext<'_>,
|
||||
threshold: u64,
|
||||
def: &EnumDef<'_>,
|
||||
item_name: &str,
|
||||
item_name_chars: usize,
|
||||
span: Span,
|
||||
) {
|
||||
fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
|
||||
let name = variant.ident.name.as_str();
|
||||
let item_name_chars = item_name.chars().count();
|
||||
|
||||
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())
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
ENUM_VARIANT_NAMES,
|
||||
variant.span,
|
||||
"variant name starts with the enum's name",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
|
||||
let name = variant.ident.name.as_str();
|
||||
let item_name_chars = item_name.chars().count();
|
||||
|
||||
if count_match_end(item_name, name).char_count == item_name_chars {
|
||||
span_lint(
|
||||
cx,
|
||||
ENUM_VARIANT_NAMES,
|
||||
variant.span,
|
||||
"variant name ends with the enum's name",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_name: &str, span: Span) {
|
||||
if (def.variants.len() as u64) < threshold {
|
||||
return;
|
||||
}
|
||||
|
||||
let first = &def.variants[0].ident.name.as_str();
|
||||
let mut pre = camel_case_split(first);
|
||||
let mut post = pre.clone();
|
||||
post.reverse();
|
||||
for var in def.variants {
|
||||
let name = var.ident.name.as_str();
|
||||
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())
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
ENUM_VARIANT_NAMES,
|
||||
var.span,
|
||||
"variant name starts with the enum's name",
|
||||
);
|
||||
}
|
||||
if count_match_end(item_name, &name).char_count == item_name_chars {
|
||||
span_lint(
|
||||
cx,
|
||||
ENUM_VARIANT_NAMES,
|
||||
var.span,
|
||||
"variant name ends with the enum's name",
|
||||
);
|
||||
}
|
||||
}
|
||||
let first = def.variants[0].ident.name.as_str();
|
||||
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 {
|
||||
check_enum_start(cx, item_name, var);
|
||||
check_enum_end(cx, item_name, var);
|
||||
let name = var.ident.name.as_str();
|
||||
|
||||
let pre_match = count_match_start(pre, &name).byte_count;
|
||||
pre = &pre[..pre_match];
|
||||
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() {
|
||||
return;
|
||||
}
|
||||
if next.is_lowercase() {
|
||||
let last = pre.len() - last.len_utf8();
|
||||
let last_camel = str_utils::camel_case_until(&pre[..last]);
|
||||
pre = &pre[..last_camel.byte_index];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let variant_split = camel_case_split(name);
|
||||
|
||||
let post_match = count_match_end(post, &name);
|
||||
let post_end = post.len() - post_match.byte_count;
|
||||
post = &post[post_end..];
|
||||
let post_camel = str_utils::camel_case_start(post);
|
||||
post = &post[post_camel.byte_index..];
|
||||
pre = pre
|
||||
.iter()
|
||||
.zip(variant_split.iter())
|
||||
.take_while(|(a, b)| a == b)
|
||||
.map(|e| *e.0)
|
||||
.collect();
|
||||
post = post
|
||||
.iter()
|
||||
.zip(variant_split.iter().rev())
|
||||
.take_while(|(a, b)| a == b)
|
||||
.map(|e| *e.0)
|
||||
.collect();
|
||||
}
|
||||
let (what, value) = match (pre.is_empty(), post.is_empty()) {
|
||||
(true, true) => return,
|
||||
(false, _) => ("pre", pre),
|
||||
(true, false) => ("post", post),
|
||||
(false, _) => ("pre", pre.join("")),
|
||||
(true, false) => {
|
||||
post.reverse();
|
||||
("post", post.join(""))
|
||||
},
|
||||
};
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -233,8 +240,7 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
#[allow(clippy::similar_names)]
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
let item_name = item.ident.name.as_str();
|
||||
let item_name_chars = item_name.chars().count();
|
||||
let item_camel = to_camel_case(&item_name);
|
||||
let item_camel = to_camel_case(item_name);
|
||||
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
|
||||
if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
|
||||
// constants don't have surrounding modules
|
||||
|
@ -283,7 +289,7 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
}
|
||||
if let ItemKind::Enum(ref def, _) = item.kind {
|
||||
if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) {
|
||||
check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
|
||||
check_variant(cx, self.threshold, def, item_name, item.span);
|
||||
}
|
||||
}
|
||||
self.modules.push((item.ident.name, item_camel));
|
||||
|
|
|
@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
|||
// If its within the 2 decimal digits of being out of precision we
|
||||
// check if the parsed representation is the same as the string
|
||||
// since we'll need the truncated string anyway.
|
||||
let digits = count_digits(&sym_str);
|
||||
let digits = count_digits(sym_str);
|
||||
let max = max_digits(fty);
|
||||
let type_suffix = match lit_float_ty {
|
||||
LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
|
||||
|
|
|
@ -356,7 +356,7 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
|
|||
if eq_expr_value(cx, lmul_lhs, lmul_rhs);
|
||||
if eq_expr_value(cx, rmul_lhs, rmul_rhs);
|
||||
then {
|
||||
return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, ".."), Sugg::hir(cx, rmul_lhs, "..")));
|
||||
return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, "..")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
|
|||
if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1);
|
||||
if Int(2) == lvalue && Int(2) == rvalue;
|
||||
then {
|
||||
return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, ".."), Sugg::hir(cx, rargs_0, "..")));
|
||||
return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, "..")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -654,26 +654,52 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
|
||||
(F32(180_f32) == lvalue || F64(180_f64) == lvalue)
|
||||
{
|
||||
let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref literal) = mul_lhs.kind;
|
||||
if let ast::LitKind::Float(ref value, float_type) = literal.node;
|
||||
if float_type == ast::LitFloatType::Unsuffixed;
|
||||
then {
|
||||
if value.as_str().ends_with('.') {
|
||||
proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
|
||||
} else {
|
||||
proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
|
||||
}
|
||||
}
|
||||
}
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SUBOPTIMAL_FLOPS,
|
||||
expr.span,
|
||||
"conversion to degrees can be done more accurately",
|
||||
"consider using",
|
||||
format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")),
|
||||
proposal,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if
|
||||
(F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
|
||||
(F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
|
||||
{
|
||||
let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref literal) = mul_lhs.kind;
|
||||
if let ast::LitKind::Float(ref value, float_type) = literal.node;
|
||||
if float_type == ast::LitFloatType::Unsuffixed;
|
||||
then {
|
||||
if value.as_str().ends_with('.') {
|
||||
proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
|
||||
} else {
|
||||
proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
|
||||
}
|
||||
}
|
||||
}
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SUBOPTIMAL_FLOPS,
|
||||
expr.span,
|
||||
"conversion to radians can be done more accurately",
|
||||
"consider using",
|
||||
format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")),
|
||||
proposal,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -61,15 +61,18 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp {
|
|||
}
|
||||
|
||||
fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||
// `1 << 0` is a common pattern in bit manipulation code
|
||||
cmp.node == BinOpKind::Shl
|
||||
&& constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
|
||||
&& constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))
|
||||
// This lint applies to integers
|
||||
!cx.typeck_results().expr_ty(left).peel_refs().is_integral()
|
||||
|| !cx.typeck_results().expr_ty(right).peel_refs().is_integral()
|
||||
// `1 << 0` is a common pattern in bit manipulation code
|
||||
|| (cmp.node == BinOpKind::Shl
|
||||
&& constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
|
||||
&& constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
|
||||
}
|
||||
|
||||
fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
|
||||
if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
|
||||
let check = match *cx.typeck_results().expr_ty(e).kind() {
|
||||
if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
|
||||
let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
|
||||
ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
|
||||
ty::Uint(uty) => clip(cx.tcx, !0, uty),
|
||||
_ => return,
|
||||
|
|
|
@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
|||
if let LitKind::Int(0, _) = cond_lit.node {
|
||||
if cx.typeck_results().expr_ty(cond_left).is_signed() {
|
||||
} else {
|
||||
print_lint_and_sugg(cx, &var_name, expr);
|
||||
print_lint_and_sugg(cx, var_name, expr);
|
||||
};
|
||||
}
|
||||
},
|
||||
|
@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
|||
let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok());
|
||||
if int_ids.any(|int_id| int_id == impl_id);
|
||||
then {
|
||||
print_lint_and_sugg(cx, &var_name, expr)
|
||||
print_lint_and_sugg(cx, var_name, expr)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
|||
let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok());
|
||||
if int_ids.any(|int_id| int_id == impl_id);
|
||||
then {
|
||||
print_lint_and_sugg(cx, &var_name, expr)
|
||||
print_lint_and_sugg(cx, var_name, expr)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
80
clippy_lints/src/init_numbered_fields.rs
Normal file
80
clippy_lints/src/init_numbered_fields.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::in_macro;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::BinaryHeap;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for tuple structs initialized with field syntax.
|
||||
/// It will however not lint if a base initializer is present.
|
||||
/// The lint will also ignore code in macros.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This may be confusing to the uninitiated and adds no
|
||||
/// benefit as opposed to tuple initializers
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// struct TupleStruct(u8, u16);
|
||||
///
|
||||
/// let _ = TupleStruct {
|
||||
/// 0: 1,
|
||||
/// 1: 23,
|
||||
/// };
|
||||
///
|
||||
/// // should be written as
|
||||
/// let base = TupleStruct(1, 23);
|
||||
///
|
||||
/// // This is OK however
|
||||
/// let _ = TupleStruct { 0: 42, ..base };
|
||||
/// ```
|
||||
#[clippy::version = "1.59.0"]
|
||||
pub INIT_NUMBERED_FIELDS,
|
||||
style,
|
||||
"numbered fields in tuple struct initializer"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NumberedFields {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Struct(path, fields, None) = e.kind {
|
||||
if !fields.is_empty()
|
||||
&& !in_macro(e.span)
|
||||
&& fields
|
||||
.iter()
|
||||
.all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
|
||||
{
|
||||
let expr_spans = fields
|
||||
.iter()
|
||||
.map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
|
||||
.collect::<BinaryHeap<_>>();
|
||||
let mut appl = Applicability::MachineApplicable;
|
||||
let snippet = format!(
|
||||
"{}({})",
|
||||
snippet_with_applicability(cx, path.span(), "..", &mut appl),
|
||||
expr_spans
|
||||
.into_iter_sorted()
|
||||
.map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl))
|
||||
.intersperse(Cow::Borrowed(", "))
|
||||
.collect::<String>()
|
||||
);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
INIT_NUMBERED_FIELDS,
|
||||
e.span,
|
||||
"used a field initializer for a tuple struct",
|
||||
"try this instead",
|
||||
snippet,
|
||||
appl,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -441,7 +441,7 @@ fn is_empty_string(expr: &Expr<'_>) -> bool {
|
|||
if let ExprKind::Lit(ref lit) = expr.kind {
|
||||
if let LitKind::Str(lit, _) = lit.node {
|
||||
let lit = lit.as_str();
|
||||
return lit == "";
|
||||
return lit.is_empty();
|
||||
}
|
||||
}
|
||||
false
|
||||
|
|
|
@ -81,6 +81,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(infinite_iter::INFINITE_ITER),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
|
||||
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
|
||||
LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
|
||||
LintId::of(int_plus_one::INT_PLUS_ONE),
|
||||
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
|
||||
|
|
|
@ -178,6 +178,7 @@ store.register_lints(&[
|
|||
inherent_impl::MULTIPLE_INHERENT_IMPL,
|
||||
inherent_to_string::INHERENT_TO_STRING,
|
||||
inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
|
||||
init_numbered_fields::INIT_NUMBERED_FIELDS,
|
||||
inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
|
||||
int_plus_one::INT_PLUS_ONE,
|
||||
integer_division::INTEGER_DIVISION,
|
||||
|
|
|
@ -29,6 +29,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
|
|||
LintId::of(functions::MUST_USE_UNIT),
|
||||
LintId::of(functions::RESULT_UNIT_ERR),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
|
||||
LintId::of(len_zero::COMPARISON_TO_EMPTY),
|
||||
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
|
||||
LintId::of(len_zero::LEN_ZERO),
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
// error-pattern:cargo-clippy
|
||||
|
||||
#![feature(binary_heap_into_iter_sorted)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_else)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(let_else)]
|
||||
#![recursion_limit = "512"]
|
||||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
|
||||
|
@ -242,6 +244,7 @@ mod indexing_slicing;
|
|||
mod infinite_iter;
|
||||
mod inherent_impl;
|
||||
mod inherent_to_string;
|
||||
mod init_numbered_fields;
|
||||
mod inline_fn_without_body;
|
||||
mod int_plus_one;
|
||||
mod integer_division;
|
||||
|
@ -854,6 +857,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
|
||||
store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
|
||||
store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
|
||||
store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Pat, PatKind, StmtKind}
|
|||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::fmt::Display;
|
||||
use std::iter::Iterator;
|
||||
|
||||
/// Checks for for loops that sequentially copy items from one slice-like
|
||||
|
@ -108,7 +109,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
src: &IndexExpr<'_>,
|
||||
) -> String {
|
||||
fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
|
||||
if offset.as_str() == "0" {
|
||||
if offset.to_string() == "0" {
|
||||
sugg::EMPTY.into()
|
||||
} else {
|
||||
offset
|
||||
|
@ -123,7 +124,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
if let Some(arg) = len_args.get(0);
|
||||
if path_to_local(arg) == path_to_local(base);
|
||||
then {
|
||||
if sugg.as_str() == end_str {
|
||||
if sugg.to_string() == end_str {
|
||||
sugg::EMPTY.into()
|
||||
} else {
|
||||
sugg
|
||||
|
@ -147,7 +148,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
print_offset(apply_offset(&start_str, &idx_expr.idx_offset)).into_sugg(),
|
||||
print_limit(
|
||||
end,
|
||||
end_str.as_str(),
|
||||
end_str.to_string().as_str(),
|
||||
idx_expr.base,
|
||||
apply_offset(&end_str, &idx_expr.idx_offset),
|
||||
)
|
||||
|
@ -159,7 +160,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
print_offset(apply_offset(&counter_start, &idx_expr.idx_offset)).into_sugg(),
|
||||
print_limit(
|
||||
end,
|
||||
end_str.as_str(),
|
||||
end_str.to_string().as_str(),
|
||||
idx_expr.base,
|
||||
apply_offset(&end_str, &idx_expr.idx_offset) + &counter_start - &start_str,
|
||||
)
|
||||
|
@ -202,15 +203,13 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
#[derive(Clone)]
|
||||
struct MinifyingSugg<'a>(Sugg<'a>);
|
||||
|
||||
impl<'a> MinifyingSugg<'a> {
|
||||
fn as_str(&self) -> &str {
|
||||
// HACK: Don't sync to Clippy! Required because something with the `or_patterns` feature
|
||||
// changed and this would now require parentheses.
|
||||
match &self.0 {
|
||||
Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) => s.as_ref(),
|
||||
}
|
||||
impl Display for MinifyingSugg<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MinifyingSugg<'a> {
|
||||
fn into_sugg(self) -> Sugg<'a> {
|
||||
self.0
|
||||
}
|
||||
|
@ -225,7 +224,7 @@ impl<'a> From<Sugg<'a>> for MinifyingSugg<'a> {
|
|||
impl std::ops::Add for &MinifyingSugg<'static> {
|
||||
type Output = MinifyingSugg<'static>;
|
||||
fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
|
||||
match (self.as_str(), rhs.as_str()) {
|
||||
match (self.to_string().as_str(), rhs.to_string().as_str()) {
|
||||
("0", _) => rhs.clone(),
|
||||
(_, "0") => self.clone(),
|
||||
(_, _) => (&self.0 + &rhs.0).into(),
|
||||
|
@ -236,7 +235,7 @@ impl std::ops::Add for &MinifyingSugg<'static> {
|
|||
impl std::ops::Sub for &MinifyingSugg<'static> {
|
||||
type Output = MinifyingSugg<'static>;
|
||||
fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
|
||||
match (self.as_str(), rhs.as_str()) {
|
||||
match (self.to_string().as_str(), rhs.to_string().as_str()) {
|
||||
(_, "0") => self.clone(),
|
||||
("0", _) => (-rhs.0.clone()).into(),
|
||||
(x, y) if x == y => sugg::ZERO.into(),
|
||||
|
@ -248,7 +247,7 @@ impl std::ops::Sub for &MinifyingSugg<'static> {
|
|||
impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> {
|
||||
type Output = MinifyingSugg<'static>;
|
||||
fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
|
||||
match (self.as_str(), rhs.as_str()) {
|
||||
match (self.to_string().as_str(), rhs.to_string().as_str()) {
|
||||
("0", _) => rhs.clone(),
|
||||
(_, "0") => self,
|
||||
(_, _) => (self.0 + &rhs.0).into(),
|
||||
|
@ -259,7 +258,7 @@ impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> {
|
|||
impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> {
|
||||
type Output = MinifyingSugg<'static>;
|
||||
fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
|
||||
match (self.as_str(), rhs.as_str()) {
|
||||
match (self.to_string().as_str(), rhs.to_string().as_str()) {
|
||||
(_, "0") => self,
|
||||
("0", _) => (-rhs.0.clone()).into(),
|
||||
(x, y) if x == y => sugg::ZERO.into(),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::in_macro;
|
||||
use clippy_utils::source::snippet;
|
||||
use hir::def::{DefKind, Res};
|
||||
use if_chain::if_chain;
|
||||
|
@ -8,7 +9,6 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::hygiene::ExpnKind;
|
||||
use rustc_span::{edition::Edition, sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -213,7 +213,3 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn in_macro(span: Span) -> bool {
|
||||
span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
|
||||
}
|
||||
|
|
|
@ -94,8 +94,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
|||
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
match ex.kind {
|
||||
ExprKind::MethodCall(segment, _, [receiver], _)
|
||||
if self.case_altered(segment.ident.as_str(), receiver) => {},
|
||||
ExprKind::MethodCall(segment, _, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {
|
||||
},
|
||||
_ => walk_expr(self, ex),
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
|
|||
}) = arm.pat.kind;
|
||||
if let LitKind::Str(symbol, _) = lit.node;
|
||||
let input = symbol.as_str();
|
||||
if !case_check(&input);
|
||||
if !case_check(input);
|
||||
then {
|
||||
return Some((lit.span, symbol));
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::path_to_local;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{BindingAnnotation, Node, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
|
@ -11,14 +13,34 @@ use super::ITER_SKIP_NEXT;
|
|||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
|
||||
// lint if caller of skip is an Iterator
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
span_lint_and_sugg(
|
||||
let mut application = Applicability::MachineApplicable;
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
ITER_SKIP_NEXT,
|
||||
expr.span.trim_start(recv.span).unwrap(),
|
||||
"called `skip(..).next()` on an iterator",
|
||||
"use `nth` instead",
|
||||
format!(".nth({})", snippet(cx, arg.span, "..")),
|
||||
Applicability::MachineApplicable,
|
||||
|diag| {
|
||||
if_chain! {
|
||||
if let Some(id) = path_to_local(recv);
|
||||
if let Node::Binding(pat) = cx.tcx.hir().get(id);
|
||||
if let PatKind::Binding(ann, _, _, _) = pat.kind;
|
||||
if ann != BindingAnnotation::Mutable;
|
||||
then {
|
||||
application = Applicability::Unspecified;
|
||||
diag.span_help(
|
||||
pat.span,
|
||||
&format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diag.span_suggestion(
|
||||
expr.span.trim_start(recv.span).unwrap(),
|
||||
"use `nth` instead",
|
||||
format!(".nth({})", snippet(cx, arg.span, "..")),
|
||||
application,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2112,7 +2112,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
{
|
||||
wrong_self_convention::check(
|
||||
cx,
|
||||
&name,
|
||||
name,
|
||||
self_ty,
|
||||
first_arg_ty,
|
||||
first_arg.pat.span,
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use super::UNWRAP_OR_ELSE_DEFAULT;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item,
|
||||
diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
|
||||
ty::is_type_diagnostic_item,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
@ -24,7 +25,7 @@ pub(super) fn check<'tcx>(
|
|||
|
||||
if_chain! {
|
||||
if is_option || is_result;
|
||||
if is_trait_item(cx, u_arg, sym::Default);
|
||||
if is_default_equivalent_call(cx, u_arg);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ pub(super) fn get_hint_if_single_char_arg(
|
|||
let string = r.as_str();
|
||||
if string.chars().count() == 1;
|
||||
then {
|
||||
let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
|
||||
let snip = snippet_with_applicability(cx, arg.span, string, applicability);
|
||||
let ch = if let ast::StrStyle::Raw(nhash) = style {
|
||||
let nhash = nhash as usize;
|
||||
// for raw string: r##"a"##
|
||||
|
|
|
@ -187,14 +187,14 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
|
|||
BinOpKind::Eq => {
|
||||
let true_case = Some((|h| h, "equality checks against true are unnecessary"));
|
||||
let false_case = Some((
|
||||
|h: Sugg<'_>| !h,
|
||||
|h: Sugg<'tcx>| !h,
|
||||
"equality checks against false can be replaced by a negation",
|
||||
));
|
||||
check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
|
||||
},
|
||||
BinOpKind::Ne => {
|
||||
let true_case = Some((
|
||||
|h: Sugg<'_>| !h,
|
||||
|h: Sugg<'tcx>| !h,
|
||||
"inequality checks against true can be replaced by a negation",
|
||||
));
|
||||
let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
|
||||
|
@ -206,12 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
|
|||
ignore_case,
|
||||
Some((|h| h, "greater than checks against false are unnecessary")),
|
||||
Some((
|
||||
|h: Sugg<'_>| !h,
|
||||
|h: Sugg<'tcx>| !h,
|
||||
"less than comparison against true can be replaced by a negation",
|
||||
)),
|
||||
ignore_case,
|
||||
Some((
|
||||
|l: Sugg<'_>, r: Sugg<'_>| (!l).bit_and(&r),
|
||||
|l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r),
|
||||
"order comparisons between booleans can be simplified",
|
||||
)),
|
||||
),
|
||||
|
@ -219,14 +219,14 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
|
|||
cx,
|
||||
e,
|
||||
Some((
|
||||
|h: Sugg<'_>| !h,
|
||||
|h: Sugg<'tcx>| !h,
|
||||
"less than comparison against true can be replaced by a negation",
|
||||
)),
|
||||
ignore_case,
|
||||
ignore_case,
|
||||
Some((|h| h, "greater than checks against false are unnecessary")),
|
||||
Some((
|
||||
|l: Sugg<'_>, r: Sugg<'_>| l.bit_and(&(!r)),
|
||||
|l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)),
|
||||
"order comparisons between booleans can be simplified",
|
||||
)),
|
||||
),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use clippy_utils::consts::{self, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
@ -18,12 +20,16 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// ### Example
|
||||
/// ```ignore
|
||||
/// x * -1
|
||||
/// // Bad
|
||||
/// let a = x * -1;
|
||||
///
|
||||
/// // Good
|
||||
/// let b = -x;
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub NEG_MULTIPLY,
|
||||
style,
|
||||
"multiplying integers with `-1`"
|
||||
"multiplying integers by `-1`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
|
||||
|
@ -49,8 +55,19 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
|
|||
if let ExprKind::Lit(ref l) = lit.kind;
|
||||
if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
|
||||
if cx.typeck_results().expr_ty(exp).is_integral();
|
||||
|
||||
then {
|
||||
span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`");
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let suggestion = format!("-{}", snippet_with_applicability(cx, exp.span, "..", &mut applicability));
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEG_MULTIPLY,
|
||||
span,
|
||||
"this multiplication by -1 can be written more succinctly",
|
||||
"consider using",
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,20 +218,20 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
return;
|
||||
}
|
||||
for existing_name in &self.0.names {
|
||||
if allowed_to_be_similar(&interned_name, existing_name.exemptions) {
|
||||
if allowed_to_be_similar(interned_name, existing_name.exemptions) {
|
||||
continue;
|
||||
}
|
||||
match existing_name.len.cmp(&count) {
|
||||
Ordering::Greater => {
|
||||
if existing_name.len - count != 1
|
||||
|| levenstein_not_1(&interned_name, existing_name.interned.as_str())
|
||||
|| levenstein_not_1(interned_name, existing_name.interned.as_str())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
},
|
||||
Ordering::Less => {
|
||||
if count - existing_name.len != 1
|
||||
|| levenstein_not_1(existing_name.interned.as_str(), &interned_name)
|
||||
|| levenstein_not_1(existing_name.interned.as_str(), interned_name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
return;
|
||||
}
|
||||
self.0.names.push(ExistingName {
|
||||
exemptions: get_exemptions(&interned_name).unwrap_or(&[]),
|
||||
exemptions: get_exemptions(interned_name).unwrap_or(&[]),
|
||||
interned: ident.name,
|
||||
span: ident.span,
|
||||
len: count,
|
||||
|
|
|
@ -378,8 +378,8 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
span,
|
||||
"an inclusive range would be more readable",
|
||||
|diag| {
|
||||
let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string());
|
||||
let end = Sugg::hir(cx, y, "y");
|
||||
let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
|
||||
let end = Sugg::hir(cx, y, "y").maybe_par();
|
||||
if let Some(is_wrapped) = &snippet_opt(cx, span) {
|
||||
if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') {
|
||||
diag.span_suggestion(
|
||||
|
@ -415,8 +415,8 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
expr.span,
|
||||
"an exclusive range would be more readable",
|
||||
|diag| {
|
||||
let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string());
|
||||
let end = Sugg::hir(cx, y, "y");
|
||||
let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
|
||||
let end = Sugg::hir(cx, y, "y").maybe_par();
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"use",
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use clippy_utils::{diagnostics::span_lint, must_use_attr, nth_arg, return_ty};
|
||||
use clippy_utils::ty::is_must_use_ty;
|
||||
use clippy_utils::{diagnostics::span_lint, nth_arg, return_ty};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -50,9 +51,9 @@ fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalD
|
|||
if decl.implicit_self.has_implicit_self();
|
||||
// We only show this warning for public exported methods.
|
||||
if cx.access_levels.is_exported(fn_def);
|
||||
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
|
||||
if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
|
||||
if cx.tcx.visibility(fn_def.to_def_id()).is_public();
|
||||
// No need to warn if the attribute is already present.
|
||||
if must_use_attr(cx.tcx.hir().attrs(hir_id)).is_none();
|
||||
let ret_ty = return_ty(cx, hir_id);
|
||||
let self_arg = nth_arg(cx, hir_id, 0);
|
||||
// If `Self` has the same type as the returned type, then we want to warn.
|
||||
|
@ -60,6 +61,8 @@ fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalD
|
|||
// For this check, we don't want to remove the reference on the returned type because if
|
||||
// there is one, we shouldn't emit a warning!
|
||||
if self_arg.peel_refs() == ret_ty;
|
||||
// If `Self` is already marked as `#[must_use]`, no need for the attribute here.
|
||||
if !is_must_use_ty(cx, ret_ty);
|
||||
|
||||
then {
|
||||
span_lint(
|
||||
|
|
|
@ -73,6 +73,7 @@ declare_clippy_lint! {
|
|||
enum RetReplacement {
|
||||
Empty,
|
||||
Block,
|
||||
Unit,
|
||||
}
|
||||
|
||||
declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
|
||||
|
@ -212,7 +213,7 @@ fn check_final_expr<'tcx>(
|
|||
// (except for unit type functions) so we don't match it
|
||||
ExprKind::Match(_, arms, MatchSource::Normal) => {
|
||||
for arm in arms.iter() {
|
||||
check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block);
|
||||
check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Unit);
|
||||
}
|
||||
},
|
||||
ExprKind::DropTemps(expr) => check_final_expr(cx, expr, None, RetReplacement::Empty),
|
||||
|
@ -259,6 +260,17 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
RetReplacement::Unit => {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_RETURN,
|
||||
ret_span,
|
||||
"unneeded `return` statement",
|
||||
"replace `return` with a unit value",
|
||||
"()".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::hir_id::ItemLocalId;
|
||||
use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -220,14 +220,14 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
|
|||
}
|
||||
}
|
||||
|
||||
/// Finds the "init" expression for a pattern: `let <pat> = <init>;` or
|
||||
/// Finds the "init" expression for a pattern: `let <pat> = <init>;` (or `if let`) or
|
||||
/// `match <init> { .., <pat> => .., .. }`
|
||||
fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
|
||||
for (_, node) in cx.tcx.hir().parent_iter(hir_id) {
|
||||
let init = match node {
|
||||
Node::Arm(_) | Node::Pat(_) => continue,
|
||||
Node::Expr(expr) => match expr.kind {
|
||||
ExprKind::Match(e, _, _) => Some(e),
|
||||
ExprKind::Match(e, _, _) | ExprKind::Let(&Let { init: e, .. }) => Some(e),
|
||||
_ => None,
|
||||
},
|
||||
Node::Local(local) => local.init,
|
||||
|
|
|
@ -64,7 +64,7 @@ impl TabsInDocComments {
|
|||
if let ast::AttrKind::DocComment(_, comment) = attr.kind {
|
||||
let comment = comment.as_str();
|
||||
|
||||
for (lo, hi) in get_chunks_of_tabs(&comment) {
|
||||
for (lo, hi) in get_chunks_of_tabs(comment) {
|
||||
// +3 skips the opening delimiter
|
||||
let new_span = Span::new(
|
||||
attr.span.lo() + BytePos(3 + lo),
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::borrow::Cow;
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for `unsafe` blocks without a `// Safety: ` comment
|
||||
/// Checks for `unsafe` blocks without a `// SAFETY: ` comment
|
||||
/// explaining why the unsafe operations performed inside
|
||||
/// the block are safe.
|
||||
///
|
||||
|
@ -36,7 +36,7 @@ declare_clippy_lint! {
|
|||
/// use std::ptr::NonNull;
|
||||
/// let a = &mut 42;
|
||||
///
|
||||
/// // Safety: references are guaranteed to be non-null.
|
||||
/// // SAFETY: references are guaranteed to be non-null.
|
||||
/// let ptr = unsafe { NonNull::new_unchecked(a) };
|
||||
/// ```
|
||||
#[clippy::version = "1.58.0"]
|
||||
|
@ -213,7 +213,7 @@ impl UndocumentedUnsafeBlocks {
|
|||
);
|
||||
} else {
|
||||
let block_indent = indent_of(cx, span);
|
||||
let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
|
||||
let suggestion = format!("// SAFETY: ...\n{}", snippet(cx, span, ".."));
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
@ -60,7 +60,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
|
|||
fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, span: Span) {
|
||||
let old_str = old_name.name.as_str();
|
||||
let new_str = new_name.name.as_str();
|
||||
if contains_unsafe(&old_str) && !contains_unsafe(&new_str) {
|
||||
if contains_unsafe(old_str) && !contains_unsafe(new_str) {
|
||||
span_lint(
|
||||
cx,
|
||||
UNSAFE_REMOVED_FROM_NAME,
|
||||
|
|
|
@ -161,7 +161,7 @@ fn collect_unwrap_info<'tcx>(
|
|||
if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
|
||||
then {
|
||||
assert!(args.len() == 1);
|
||||
let unwrappable = match name.as_ref() {
|
||||
let unwrappable = match name {
|
||||
"is_some" | "is_ok" => true,
|
||||
"is_err" | "is_none" => false,
|
||||
_ => unreachable!(),
|
||||
|
|
|
@ -87,7 +87,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
|
|||
if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2)
|
||||
// otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive
|
||||
// upper-case-acronyms-aggressive config option enabled
|
||||
|| (be_aggressive && ident != &corrected)
|
||||
|| (be_aggressive && ident != corrected)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
@ -28,7 +28,7 @@ use rustc_middle::ty;
|
|||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{Symbol, SymbolStr};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
|
||||
|
@ -344,11 +344,11 @@ impl EarlyLintPass for ClippyLintsInternal {
|
|||
if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
|
||||
if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
|
||||
let mut last_name: Option<SymbolStr> = None;
|
||||
let mut last_name: Option<&str> = None;
|
||||
for item in items {
|
||||
let name = item.ident.as_str();
|
||||
if let Some(ref last_name) = last_name {
|
||||
if **last_name > *name {
|
||||
if let Some(last_name) = last_name {
|
||||
if *last_name > *name {
|
||||
span_lint(
|
||||
cx,
|
||||
CLIPPY_LINTS_INTERNAL,
|
||||
|
@ -608,8 +608,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
|
|||
}
|
||||
|
||||
let (method_names, arg_lists, spans) = method_calls(expr, 2);
|
||||
let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
|
||||
let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
|
||||
let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
|
||||
if_chain! {
|
||||
if let ["expn_data", "outer_expn"] = method_names.as_slice();
|
||||
let args = arg_lists[1];
|
||||
|
@ -839,7 +838,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
|
|||
if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
|
||||
// Extract the path to the matched type
|
||||
if let Some(segments) = path_to_matched_type(cx, ty_path);
|
||||
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
|
||||
let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect();
|
||||
if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
|
||||
// Check if the matched type is a diagnostic item
|
||||
if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
|
||||
|
@ -862,7 +861,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
|
|||
}
|
||||
}
|
||||
|
||||
fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> {
|
||||
fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<Symbol>> {
|
||||
use rustc_hir::ItemKind;
|
||||
|
||||
match &expr.kind {
|
||||
|
@ -887,12 +886,12 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
|
|||
_ => {},
|
||||
},
|
||||
ExprKind::Array(exprs) => {
|
||||
let segments: Vec<SymbolStr> = exprs
|
||||
let segments: Vec<Symbol> = exprs
|
||||
.iter()
|
||||
.filter_map(|expr| {
|
||||
if let ExprKind::Lit(lit) = &expr.kind {
|
||||
if let LitKind::Str(sym, _) = lit.node {
|
||||
return Some(sym.as_str());
|
||||
return Some(sym);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1076,7 +1075,6 @@ impl InterningDefinedSymbol {
|
|||
&paths::SYMBOL_TO_IDENT_STRING,
|
||||
&paths::TO_STRING_METHOD,
|
||||
];
|
||||
// SymbolStr might be de-referenced: `&*symbol.as_str()`
|
||||
let call = if_chain! {
|
||||
if let ExprKind::AddrOf(_, _, e) = expr.kind;
|
||||
if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
|
||||
|
|
|
@ -168,6 +168,14 @@ impl Constant {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn peel_refs(mut self) -> Self {
|
||||
while let Constant::Ref(r) = self {
|
||||
self = *r;
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a `LitKind` to a `Constant`.
|
||||
|
@ -320,7 +328,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
|
||||
if let Some(def_id) = res.opt_def_id();
|
||||
let def_path = self.lcx.get_def_path(def_id);
|
||||
let def_path: Vec<&str> = def_path.iter().take(4).map(|s| s.as_str()).collect();
|
||||
let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect();
|
||||
if let ["core", "num", int_impl, "max_value"] = *def_path;
|
||||
then {
|
||||
let value = match int_impl {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(let_else)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![recursion_limit = "512"]
|
||||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
|
||||
|
@ -60,9 +61,12 @@ pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, Spanl
|
|||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::lazy::SyncOnceCell;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, Attribute, LitKind};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unhash::UnhashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -87,6 +91,7 @@ use rustc_middle::ty::binding::BindingMode;
|
|||
use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::source_map::original_sp;
|
||||
use rustc_span::sym;
|
||||
|
@ -142,6 +147,13 @@ macro_rules! extract_msrv_attr {
|
|||
};
|
||||
}
|
||||
|
||||
/// Returns `true` if the span comes from a macro expansion, no matter if from a
|
||||
/// macro by example or from a procedural macro
|
||||
#[must_use]
|
||||
pub fn in_macro(span: Span) -> bool {
|
||||
span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
|
||||
}
|
||||
|
||||
/// Returns `true` if the two spans come from differing expansions (i.e., one is
|
||||
/// from a macro and one isn't).
|
||||
#[must_use]
|
||||
|
@ -156,18 +168,18 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
|
|||
/// instead.
|
||||
///
|
||||
/// Examples:
|
||||
/// ```ignore
|
||||
/// ```
|
||||
/// let abc = 1;
|
||||
/// // ^ output
|
||||
/// let def = abc;
|
||||
/// dbg!(def)
|
||||
/// dbg!(def);
|
||||
/// // ^^^ input
|
||||
///
|
||||
/// // or...
|
||||
/// let abc = 1;
|
||||
/// let def = abc + 2;
|
||||
/// // ^^^^^^^ output
|
||||
/// dbg!(def)
|
||||
/// dbg!(def);
|
||||
/// // ^^^ input
|
||||
/// ```
|
||||
pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
|
||||
|
@ -664,6 +676,22 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
|
|||
false
|
||||
}
|
||||
|
||||
/// Return true if the expr is equal to `Default::default` when evaluated.
|
||||
pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
|
||||
if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
|
||||
if is_diag_trait_item(cx, repl_def_id, sym::Default)
|
||||
|| is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
|
||||
then {
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
|
||||
/// It doesn't cover all cases, for example indirect function calls (some of std
|
||||
/// functions are supported) but it is the best we have.
|
||||
|
@ -686,18 +714,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||
false
|
||||
}
|
||||
},
|
||||
ExprKind::Call(repl_func, _) => if_chain! {
|
||||
if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
|
||||
if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
|
||||
if is_diag_trait_item(cx, repl_def_id, sym::Default)
|
||||
|| is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
|
||||
then {
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
},
|
||||
ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func),
|
||||
ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone),
|
||||
ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
|
||||
_ => false,
|
||||
|
@ -1136,7 +1153,7 @@ pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
|
|||
|
||||
/// Extends the span to the beginning of the spans line, incl. whitespaces.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```rust
|
||||
/// let x = ();
|
||||
/// // ^^
|
||||
/// // will be converted to
|
||||
|
@ -1337,7 +1354,7 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||
cx.typeck_results().adjustments().get(e.hir_id).is_some()
|
||||
}
|
||||
|
||||
/// Returns the pre-expansion span if is this comes from an expansion of the
|
||||
/// Returns the pre-expansion span if this comes from an expansion of the
|
||||
/// macro `name`.
|
||||
/// See also [`is_direct_expn_of`].
|
||||
#[must_use]
|
||||
|
@ -1364,7 +1381,8 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
|
|||
/// of the macro `name`.
|
||||
/// The difference with [`is_expn_of`] is that in
|
||||
/// ```rust
|
||||
/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } }
|
||||
/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
|
||||
/// # macro_rules! bar { ($e:expr) => { $e } }
|
||||
/// foo!(bar!(42));
|
||||
/// ```
|
||||
/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
|
||||
|
@ -1905,7 +1923,9 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
|
|||
|
||||
/// Check if parent of a hir node is a trait implementation block.
|
||||
/// For example, `f` in
|
||||
/// ```rust,ignore
|
||||
/// ```rust
|
||||
/// # struct S;
|
||||
/// # trait Trait { fn f(); }
|
||||
/// impl Trait for S {
|
||||
/// fn f() {}
|
||||
/// }
|
||||
|
@ -2124,17 +2144,16 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
struct VisitConstTestStruct<'tcx> {
|
||||
struct TestItemNamesVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
names: Vec<Symbol>,
|
||||
found: bool,
|
||||
}
|
||||
impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
|
||||
|
||||
impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> {
|
||||
fn visit_item(&mut self, item: &Item<'_>) {
|
||||
if let ItemKind::Const(ty, _body) = item.kind {
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
|
||||
// We could also check for the type name `test::TestDescAndFn`
|
||||
// and the `#[rustc_test_marker]` attribute?
|
||||
if let Res::Def(DefKind::Struct, _) = path.res {
|
||||
let has_test_marker = self
|
||||
.tcx
|
||||
|
@ -2142,8 +2161,8 @@ impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
|
|||
.attrs(item.hir_id())
|
||||
.iter()
|
||||
.any(|a| a.has_name(sym::rustc_test_marker));
|
||||
if has_test_marker && self.names.contains(&item.ident.name) {
|
||||
self.found = true;
|
||||
if has_test_marker {
|
||||
self.names.push(item.ident.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2154,32 +2173,42 @@ impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
|
|||
fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
|
||||
}
|
||||
|
||||
static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
|
||||
|
||||
fn with_test_item_names(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
|
||||
let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
|
||||
let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
|
||||
match map.entry(module) {
|
||||
Entry::Occupied(entry) => f(entry.get()),
|
||||
Entry::Vacant(entry) => {
|
||||
let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() };
|
||||
tcx.hir().visit_item_likes_in_module(module, &mut visitor);
|
||||
visitor.names.sort_unstable();
|
||||
f(&*entry.insert(visitor.names))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the function containing the given `HirId` is a `#[test]` function
|
||||
///
|
||||
/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
|
||||
pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||
let names: Vec<_> = tcx
|
||||
.hir()
|
||||
.parent_iter(id)
|
||||
// Since you can nest functions we need to collect all until we leave
|
||||
// function scope
|
||||
.filter_map(|(_id, node)| {
|
||||
if let Node::Item(item) = node {
|
||||
if let ItemKind::Fn(_, _, _) = item.kind {
|
||||
return Some(item.ident.name);
|
||||
with_test_item_names(tcx, tcx.parent_module(id), |names| {
|
||||
tcx.hir()
|
||||
.parent_iter(id)
|
||||
// Since you can nest functions we need to collect all until we leave
|
||||
// function scope
|
||||
.any(|(_id, node)| {
|
||||
if let Node::Item(item) = node {
|
||||
if let ItemKind::Fn(_, _, _) = item.kind {
|
||||
// Note that we have sorted the item names in the visitor,
|
||||
// so the binary_search gets the same as `contains`, but faster.
|
||||
return names.binary_search(&item.ident.name).is_ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
let parent_mod = tcx.parent_module(id);
|
||||
let mut vis = VisitConstTestStruct {
|
||||
tcx,
|
||||
names,
|
||||
found: false,
|
||||
};
|
||||
tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis);
|
||||
vis.found
|
||||
false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks whether item either has `test` attribute applied, or
|
||||
|
|
|
@ -15,6 +15,7 @@ impl StrIndex {
|
|||
/// Returns the index of the character after the first camel-case component of `s`.
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{camel_case_until, StrIndex};
|
||||
/// 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));
|
||||
|
@ -55,9 +56,10 @@ pub fn camel_case_until(s: &str) -> StrIndex {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns index of the last camel-case component of `s`.
|
||||
/// Returns index of the first camel-case component of `s`.
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{camel_case_start, StrIndex};
|
||||
/// 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));
|
||||
|
@ -66,19 +68,37 @@ pub fn camel_case_until(s: &str) -> StrIndex {
|
|||
/// ```
|
||||
#[must_use]
|
||||
pub fn camel_case_start(s: &str) -> StrIndex {
|
||||
camel_case_start_from_idx(s, 0)
|
||||
}
|
||||
|
||||
/// Returns `StrIndex` of the last camel-case component of `s[idx..]`.
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex};
|
||||
/// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0));
|
||||
/// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3));
|
||||
/// assert_eq!(camel_case_start_from_idx("AbcDefGhi", 0), StrIndex::new(0, 0));
|
||||
/// assert_eq!(camel_case_start_from_idx("AbcDefGhi", 1), StrIndex::new(3, 3));
|
||||
/// assert_eq!(camel_case_start_from_idx("Abcdefg", 1), StrIndex::new(7, 7));
|
||||
/// ```
|
||||
pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> 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 let Some((_, (_, first))) = iter.next() {
|
||||
if !first.is_lowercase() {
|
||||
return StrIndex::new(char_index, s.len());
|
||||
return StrIndex::new(char_count, 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 byte_index < start_idx {
|
||||
break;
|
||||
}
|
||||
if down {
|
||||
if c.is_uppercase() {
|
||||
down = false;
|
||||
|
@ -96,9 +116,55 @@ pub fn camel_case_start(s: &str) -> StrIndex {
|
|||
return last_index;
|
||||
}
|
||||
}
|
||||
|
||||
last_index
|
||||
}
|
||||
|
||||
/// Get the indexes of camel case components of a string `s`
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{camel_case_indices, StrIndex};
|
||||
/// assert_eq!(
|
||||
/// camel_case_indices("AbcDef"),
|
||||
/// vec![StrIndex::new(0, 0), StrIndex::new(3, 3), StrIndex::new(6, 6)]
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// camel_case_indices("abcDef"),
|
||||
/// vec![StrIndex::new(3, 3), StrIndex::new(6, 6)]
|
||||
/// );
|
||||
/// ```
|
||||
pub fn camel_case_indices(s: &str) -> Vec<StrIndex> {
|
||||
let mut result = Vec::new();
|
||||
let mut str_idx = camel_case_start(s);
|
||||
|
||||
while str_idx.byte_index < s.len() {
|
||||
let next_idx = str_idx.byte_index + 1;
|
||||
result.push(str_idx);
|
||||
str_idx = camel_case_start_from_idx(s, next_idx);
|
||||
}
|
||||
result.push(str_idx);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Split camel case string into a vector of its components
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{camel_case_split, StrIndex};
|
||||
/// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
|
||||
/// ```
|
||||
pub fn camel_case_split(s: &str) -> Vec<&str> {
|
||||
let mut offsets = camel_case_indices(s)
|
||||
.iter()
|
||||
.map(|e| e.byte_index)
|
||||
.collect::<Vec<usize>>();
|
||||
if offsets[0] != 0 {
|
||||
offsets.insert(0, 0);
|
||||
}
|
||||
|
||||
offsets.windows(2).map(|w| &s[w[0]..w[1]]).collect()
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
|
@ -116,6 +182,7 @@ impl StrCount {
|
|||
/// Returns the number of chars that match from the start
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{count_match_start, StrCount};
|
||||
/// 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));
|
||||
|
@ -141,6 +208,7 @@ pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
|
|||
/// Returns the number of chars and bytes that match from the end
|
||||
///
|
||||
/// ```
|
||||
/// # use clippy_utils::str_utils::{count_match_end, StrCount};
|
||||
/// 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));
|
||||
|
@ -227,4 +295,31 @@ mod test {
|
|||
fn until_caps() {
|
||||
assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn camel_case_start_from_idx_full() {
|
||||
assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0));
|
||||
assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3));
|
||||
assert_eq!(camel_case_start_from_idx("AbcDef", 4), StrIndex::new(6, 6));
|
||||
assert_eq!(camel_case_start_from_idx("AbcDefGhi", 0), StrIndex::new(0, 0));
|
||||
assert_eq!(camel_case_start_from_idx("AbcDefGhi", 1), StrIndex::new(3, 3));
|
||||
assert_eq!(camel_case_start_from_idx("Abcdefg", 1), StrIndex::new(7, 7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn camel_case_indices_full() {
|
||||
assert_eq!(camel_case_indices("Abc\u{f6}\u{f6}DD"), vec![StrIndex::new(7, 9)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn camel_case_split_full() {
|
||||
assert_eq!(camel_case_split("A"), vec!["A"]);
|
||||
assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
|
||||
assert_eq!(camel_case_split("Abc"), vec!["Abc"]);
|
||||
assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]);
|
||||
assert_eq!(
|
||||
camel_case_split("\u{f6}\u{f6}AabABcd"),
|
||||
vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
//! Contains utility functions to generate suggestions.
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
|
||||
use crate::source::{
|
||||
snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
|
||||
};
|
||||
use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite};
|
||||
use crate::{get_parent_expr_for_hir, higher};
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast::{ast, token};
|
||||
|
@ -33,7 +31,7 @@ pub enum Sugg<'a> {
|
|||
MaybeParen(Cow<'a, str>),
|
||||
/// A binary operator expression, including `as`-casts and explicit type
|
||||
/// coercion.
|
||||
BinOp(AssocOp, Cow<'a, str>),
|
||||
BinOp(AssocOp, Cow<'a, str>, Cow<'a, str>),
|
||||
}
|
||||
|
||||
/// Literal constant `0`, for convenience.
|
||||
|
@ -46,7 +44,8 @@ pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed(""));
|
|||
impl Display for Sugg<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match *self {
|
||||
Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => s.fmt(f),
|
||||
Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) => s.fmt(f),
|
||||
Sugg::BinOp(op, ref lhs, ref rhs) => binop_to_string(op, lhs, rhs).fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,10 +54,8 @@ impl Display for Sugg<'_> {
|
|||
impl<'a> Sugg<'a> {
|
||||
/// Prepare a suggestion from an expression.
|
||||
pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
|
||||
snippet_opt(cx, expr.span).map(|snippet| {
|
||||
let snippet = Cow::Owned(snippet);
|
||||
Self::hir_from_snippet(expr, snippet)
|
||||
})
|
||||
let get_snippet = |span| snippet(cx, span, "");
|
||||
snippet_opt(cx, expr.span).map(|_| Self::hir_from_snippet(expr, get_snippet))
|
||||
}
|
||||
|
||||
/// Convenience function around `hir_opt` for suggestions with a default
|
||||
|
@ -93,9 +90,8 @@ impl<'a> Sugg<'a> {
|
|||
|
||||
/// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro.
|
||||
pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
|
||||
let snippet = snippet_with_macro_callsite(cx, expr.span, default);
|
||||
|
||||
Self::hir_from_snippet(expr, snippet)
|
||||
let get_snippet = |span| snippet_with_macro_callsite(cx, span, default);
|
||||
Self::hir_from_snippet(expr, get_snippet)
|
||||
}
|
||||
|
||||
/// Same as `hir`, but first walks the span up to the given context. This will result in the
|
||||
|
@ -112,24 +108,26 @@ impl<'a> Sugg<'a> {
|
|||
default: &'a str,
|
||||
applicability: &mut Applicability,
|
||||
) -> Self {
|
||||
let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
|
||||
|
||||
if in_macro {
|
||||
Sugg::NonParen(snippet)
|
||||
if expr.span.ctxt() == ctxt {
|
||||
Self::hir_from_snippet(expr, |span| snippet(cx, span, default))
|
||||
} else {
|
||||
Self::hir_from_snippet(expr, snippet)
|
||||
let snip = snippet_with_applicability(cx, expr.span, default, applicability);
|
||||
Sugg::NonParen(snip)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
|
||||
/// function variants of `Sugg`, since these use different snippet functions.
|
||||
fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
|
||||
fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a, str>) -> Self {
|
||||
if let Some(range) = higher::Range::hir(expr) {
|
||||
let op = match range.limits {
|
||||
ast::RangeLimits::HalfOpen => AssocOp::DotDot,
|
||||
ast::RangeLimits::Closed => AssocOp::DotDotEq,
|
||||
};
|
||||
return Sugg::BinOp(op, snippet);
|
||||
let start = range.start.map_or("".into(), |expr| get_snippet(expr.span));
|
||||
let end = range.end.map_or("".into(), |expr| get_snippet(expr.span));
|
||||
|
||||
return Sugg::BinOp(op, start, end);
|
||||
}
|
||||
|
||||
match expr.kind {
|
||||
|
@ -139,7 +137,7 @@ impl<'a> Sugg<'a> {
|
|||
| hir::ExprKind::Let(..)
|
||||
| hir::ExprKind::Closure(..)
|
||||
| hir::ExprKind::Unary(..)
|
||||
| hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
|
||||
| hir::ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)),
|
||||
hir::ExprKind::Continue(..)
|
||||
| hir::ExprKind::Yield(..)
|
||||
| hir::ExprKind::Array(..)
|
||||
|
@ -160,12 +158,20 @@ impl<'a> Sugg<'a> {
|
|||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Tup(..)
|
||||
| hir::ExprKind::DropTemps(_)
|
||||
| hir::ExprKind::Err => Sugg::NonParen(snippet),
|
||||
hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
|
||||
hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
|
||||
hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node.into()), snippet),
|
||||
hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
|
||||
hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
|
||||
| hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)),
|
||||
hir::ExprKind::Assign(lhs, rhs, _) => {
|
||||
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
|
||||
},
|
||||
hir::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span))
|
||||
},
|
||||
hir::ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp(
|
||||
AssocOp::from_ast_binop(op.node.into()),
|
||||
get_snippet(lhs.span),
|
||||
get_snippet(rhs.span),
|
||||
),
|
||||
hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
|
||||
hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Colon, get_snippet(lhs.span), get_snippet(ty.span)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,10 +179,12 @@ impl<'a> Sugg<'a> {
|
|||
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
|
||||
let snippet = if expr.span.from_expansion() {
|
||||
snippet_with_macro_callsite(cx, expr.span, default)
|
||||
} else {
|
||||
snippet(cx, expr.span, default)
|
||||
let get_whole_snippet = || {
|
||||
if expr.span.from_expansion() {
|
||||
snippet_with_macro_callsite(cx, expr.span, default)
|
||||
} else {
|
||||
snippet(cx, expr.span, default)
|
||||
}
|
||||
};
|
||||
|
||||
match expr.kind {
|
||||
|
@ -186,7 +194,7 @@ impl<'a> Sugg<'a> {
|
|||
| ast::ExprKind::If(..)
|
||||
| ast::ExprKind::Let(..)
|
||||
| ast::ExprKind::Unary(..)
|
||||
| ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
|
||||
| ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()),
|
||||
ast::ExprKind::Async(..)
|
||||
| ast::ExprKind::Block(..)
|
||||
| ast::ExprKind::Break(..)
|
||||
|
@ -215,14 +223,42 @@ impl<'a> Sugg<'a> {
|
|||
| ast::ExprKind::Array(..)
|
||||
| ast::ExprKind::While(..)
|
||||
| ast::ExprKind::Await(..)
|
||||
| ast::ExprKind::Err => Sugg::NonParen(snippet),
|
||||
ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
|
||||
ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet),
|
||||
ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
|
||||
ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet),
|
||||
ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet),
|
||||
ast::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
|
||||
ast::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
|
||||
| ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()),
|
||||
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
|
||||
AssocOp::DotDot,
|
||||
lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
|
||||
rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
|
||||
),
|
||||
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
|
||||
AssocOp::DotDotEq,
|
||||
lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
|
||||
rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
|
||||
),
|
||||
ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
|
||||
AssocOp::Assign,
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, rhs.span, default),
|
||||
),
|
||||
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
|
||||
astbinop2assignop(op),
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, rhs.span, default),
|
||||
),
|
||||
ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
|
||||
AssocOp::from_ast_binop(op.node),
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, rhs.span, default),
|
||||
),
|
||||
ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
|
||||
AssocOp::As,
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, ty.span, default),
|
||||
),
|
||||
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
|
||||
AssocOp::Colon,
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, ty.span, default),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,17 +342,51 @@ impl<'a> Sugg<'a> {
|
|||
Sugg::NonParen(format!("({})", sugg).into())
|
||||
}
|
||||
},
|
||||
Sugg::BinOp(_, sugg) => {
|
||||
if has_enclosing_paren(&sugg) {
|
||||
Sugg::NonParen(sugg)
|
||||
} else {
|
||||
Sugg::NonParen(format!("({})", sugg).into())
|
||||
}
|
||||
Sugg::BinOp(op, lhs, rhs) => {
|
||||
let sugg = binop_to_string(op, &lhs, &rhs);
|
||||
Sugg::NonParen(format!("({})", sugg).into())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a string from the operator and both sides.
|
||||
fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
|
||||
match op {
|
||||
AssocOp::Add
|
||||
| AssocOp::Subtract
|
||||
| AssocOp::Multiply
|
||||
| AssocOp::Divide
|
||||
| AssocOp::Modulus
|
||||
| AssocOp::LAnd
|
||||
| AssocOp::LOr
|
||||
| AssocOp::BitXor
|
||||
| AssocOp::BitAnd
|
||||
| AssocOp::BitOr
|
||||
| AssocOp::ShiftLeft
|
||||
| AssocOp::ShiftRight
|
||||
| AssocOp::Equal
|
||||
| AssocOp::Less
|
||||
| AssocOp::LessEqual
|
||||
| AssocOp::NotEqual
|
||||
| AssocOp::Greater
|
||||
| AssocOp::GreaterEqual => format!(
|
||||
"{} {} {}",
|
||||
lhs,
|
||||
op.to_ast_binop().expect("Those are AST ops").to_string(),
|
||||
rhs
|
||||
),
|
||||
AssocOp::Assign => format!("{} = {}", lhs, rhs),
|
||||
AssocOp::AssignOp(op) => {
|
||||
format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
|
||||
},
|
||||
AssocOp::As => format!("{} as {}", lhs, rhs),
|
||||
AssocOp::DotDot => format!("{}..{}", lhs, rhs),
|
||||
AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
|
||||
AssocOp::Colon => format!("{}: {}", lhs, rhs),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if `sugg` is enclosed in parenthesis.
|
||||
fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
|
||||
let mut chars = sugg.as_ref().chars();
|
||||
|
@ -391,10 +461,25 @@ impl Neg for Sugg<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Not for Sugg<'_> {
|
||||
type Output = Sugg<'static>;
|
||||
fn not(self) -> Sugg<'static> {
|
||||
make_unop("!", self)
|
||||
impl Not for Sugg<'a> {
|
||||
type Output = Sugg<'a>;
|
||||
fn not(self) -> Sugg<'a> {
|
||||
use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual};
|
||||
|
||||
if let Sugg::BinOp(op, lhs, rhs) = self {
|
||||
let to_op = match op {
|
||||
Equal => NotEqual,
|
||||
NotEqual => Equal,
|
||||
Less => GreaterEqual,
|
||||
GreaterEqual => Less,
|
||||
Greater => LessEqual,
|
||||
LessEqual => Greater,
|
||||
_ => return make_unop("!", Sugg::BinOp(op, lhs, rhs)),
|
||||
};
|
||||
Sugg::BinOp(to_op, lhs, rhs)
|
||||
} else {
|
||||
make_unop("!", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,53 +548,21 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static>
|
|||
|| is_shift(other) && is_arith(op)
|
||||
}
|
||||
|
||||
let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs {
|
||||
let lhs_paren = if let Sugg::BinOp(lop, _, _) = *lhs {
|
||||
needs_paren(op, lop, Associativity::Left)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs {
|
||||
let rhs_paren = if let Sugg::BinOp(rop, _, _) = *rhs {
|
||||
needs_paren(op, rop, Associativity::Right)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let lhs = ParenHelper::new(lhs_paren, lhs);
|
||||
let rhs = ParenHelper::new(rhs_paren, rhs);
|
||||
let sugg = match op {
|
||||
AssocOp::Add
|
||||
| AssocOp::BitAnd
|
||||
| AssocOp::BitOr
|
||||
| AssocOp::BitXor
|
||||
| AssocOp::Divide
|
||||
| AssocOp::Equal
|
||||
| AssocOp::Greater
|
||||
| AssocOp::GreaterEqual
|
||||
| AssocOp::LAnd
|
||||
| AssocOp::LOr
|
||||
| AssocOp::Less
|
||||
| AssocOp::LessEqual
|
||||
| AssocOp::Modulus
|
||||
| AssocOp::Multiply
|
||||
| AssocOp::NotEqual
|
||||
| AssocOp::ShiftLeft
|
||||
| AssocOp::ShiftRight
|
||||
| AssocOp::Subtract => format!(
|
||||
"{} {} {}",
|
||||
lhs,
|
||||
op.to_ast_binop().expect("Those are AST ops").to_string(),
|
||||
rhs
|
||||
),
|
||||
AssocOp::Assign => format!("{} = {}", lhs, rhs),
|
||||
AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs),
|
||||
AssocOp::As => format!("{} as {}", lhs, rhs),
|
||||
AssocOp::DotDot => format!("{}..{}", lhs, rhs),
|
||||
AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
|
||||
AssocOp::Colon => format!("{}: {}", lhs, rhs),
|
||||
};
|
||||
|
||||
Sugg::BinOp(op, sugg.into())
|
||||
let lhs = ParenHelper::new(lhs_paren, lhs).to_string();
|
||||
let rhs = ParenHelper::new(rhs_paren, rhs).to_string();
|
||||
Sugg::BinOp(op, lhs.into(), rhs.into())
|
||||
}
|
||||
|
||||
/// Convenience wrapper around `make_assoc` and `AssocOp::from_ast_binop`.
|
||||
|
@ -1007,10 +1060,32 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn binop_maybe_par() {
|
||||
let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into());
|
||||
let sugg = Sugg::BinOp(AssocOp::Add, "1".into(), "1".into());
|
||||
assert_eq!("(1 + 1)", sugg.maybe_par().to_string());
|
||||
|
||||
let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1) + (1 + 1)".into());
|
||||
let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into(), "(1 + 1)".into());
|
||||
assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string());
|
||||
}
|
||||
#[test]
|
||||
fn not_op() {
|
||||
use AssocOp::{Add, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, NotEqual};
|
||||
|
||||
fn test_not(op: AssocOp, correct: &str) {
|
||||
let sugg = Sugg::BinOp(op, "x".into(), "y".into());
|
||||
assert_eq!((!sugg).to_string(), correct);
|
||||
}
|
||||
|
||||
// Invert the comparison operator.
|
||||
test_not(Equal, "x != y");
|
||||
test_not(NotEqual, "x == y");
|
||||
test_not(Less, "x >= y");
|
||||
test_not(LessEqual, "x > y");
|
||||
test_not(Greater, "x <= y");
|
||||
test_not(GreaterEqual, "x < y");
|
||||
|
||||
// Other operators are inverted like !(..).
|
||||
test_not(Add, "!(x + y)");
|
||||
test_not(LAnd, "!(x && y)");
|
||||
test_not(LOr, "!(x || y)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2021-12-17"
|
||||
channel = "nightly-2021-12-30"
|
||||
components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
|
|
|
@ -7,7 +7,7 @@ LL | unsafe { 0 };
|
|||
= note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL ~ unsafe { 0 };
|
||||
|
|
||||
|
||||
|
|
|
@ -145,4 +145,10 @@ enum HIDataRequest {
|
|||
DeleteUnpubHIData(String),
|
||||
}
|
||||
|
||||
enum North {
|
||||
Normal,
|
||||
NoLeft,
|
||||
NoRight,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -6,6 +6,18 @@ LL | cFoo,
|
|||
|
|
||||
= note: `-D clippy::enum-variant-names` implied by `-D warnings`
|
||||
|
||||
error: all variants have the same prefix: `c`
|
||||
--> $DIR/enum_variants.rs:14:1
|
||||
|
|
||||
LL | / enum Foo {
|
||||
LL | | cFoo,
|
||||
LL | | cBar,
|
||||
LL | | cBaz,
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
||||
|
||||
error: variant name starts with the enum's name
|
||||
--> $DIR/enum_variants.rs:26:5
|
||||
|
|
||||
|
@ -60,6 +72,18 @@ LL | | }
|
|||
|
|
||||
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
||||
|
||||
error: all variants have the same prefix: `C`
|
||||
--> $DIR/enum_variants.rs:59:1
|
||||
|
|
||||
LL | / enum Something {
|
||||
LL | | CCall,
|
||||
LL | | CCreate,
|
||||
LL | | CCryogenize,
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
||||
|
||||
error: all variants have the same prefix: `WithOut`
|
||||
--> $DIR/enum_variants.rs:81:1
|
||||
|
|
||||
|
@ -72,18 +96,6 @@ LL | | }
|
|||
|
|
||||
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
||||
|
||||
error: all variants have the same prefix: `Prefix`
|
||||
--> $DIR/enum_variants.rs:87:1
|
||||
|
|
||||
LL | / enum NonCaps {
|
||||
LL | | Prefix的,
|
||||
LL | | PrefixTea,
|
||||
LL | | PrefixCake,
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
||||
|
||||
error: all variants have the same postfix: `IData`
|
||||
--> $DIR/enum_variants.rs:136:1
|
||||
|
|
||||
|
@ -108,5 +120,5 @@ LL | | }
|
|||
|
|
||||
= help: remove the postfixes and use full paths to the variants instead of glob imports
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
|
@ -11,7 +11,12 @@ pub const fn const_context() {
|
|||
fn main() {
|
||||
let x = 3f32;
|
||||
let _ = x.to_degrees();
|
||||
let _ = 90.0_f64.to_degrees();
|
||||
let _ = 90.5_f64.to_degrees();
|
||||
let _ = x.to_radians();
|
||||
let _ = 90.0_f64.to_radians();
|
||||
let _ = 90.5_f64.to_radians();
|
||||
// let _ = 90.5 * 80. * std::f32::consts::PI / 180f32;
|
||||
// Cases where the lint shouldn't be applied
|
||||
let _ = x * 90f32 / std::f32::consts::PI;
|
||||
let _ = x * std::f32::consts::PI / 90f32;
|
||||
|
|
|
@ -11,7 +11,12 @@ pub const fn const_context() {
|
|||
fn main() {
|
||||
let x = 3f32;
|
||||
let _ = x * 180f32 / std::f32::consts::PI;
|
||||
let _ = 90. * 180f64 / std::f64::consts::PI;
|
||||
let _ = 90.5 * 180f64 / std::f64::consts::PI;
|
||||
let _ = x * std::f32::consts::PI / 180f32;
|
||||
let _ = 90. * std::f32::consts::PI / 180f32;
|
||||
let _ = 90.5 * std::f32::consts::PI / 180f32;
|
||||
// let _ = 90.5 * 80. * std::f32::consts::PI / 180f32;
|
||||
// Cases where the lint shouldn't be applied
|
||||
let _ = x * 90f32 / std::f32::consts::PI;
|
||||
let _ = x * std::f32::consts::PI / 90f32;
|
||||
|
|
|
@ -6,11 +6,35 @@ LL | let _ = x * 180f32 / std::f32::consts::PI;
|
|||
|
|
||||
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
|
||||
|
||||
error: conversion to radians can be done more accurately
|
||||
error: conversion to degrees can be done more accurately
|
||||
--> $DIR/floating_point_rad.rs:14:13
|
||||
|
|
||||
LL | let _ = 90. * 180f64 / std::f64::consts::PI;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()`
|
||||
|
||||
error: conversion to degrees can be done more accurately
|
||||
--> $DIR/floating_point_rad.rs:15:13
|
||||
|
|
||||
LL | let _ = 90.5 * 180f64 / std::f64::consts::PI;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()`
|
||||
|
||||
error: conversion to radians can be done more accurately
|
||||
--> $DIR/floating_point_rad.rs:16:13
|
||||
|
|
||||
LL | let _ = x * std::f32::consts::PI / 180f32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: conversion to radians can be done more accurately
|
||||
--> $DIR/floating_point_rad.rs:17:13
|
||||
|
|
||||
LL | let _ = 90. * std::f32::consts::PI / 180f32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()`
|
||||
|
||||
error: conversion to radians can be done more accurately
|
||||
--> $DIR/floating_point_rad.rs:18:13
|
||||
|
|
||||
LL | let _ = 90.5 * std::f32::consts::PI / 180f32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
@ -2,10 +2,20 @@ const ONE: i64 = 1;
|
|||
const NEG_ONE: i64 = -1;
|
||||
const ZERO: i64 = 0;
|
||||
|
||||
struct A(String);
|
||||
|
||||
impl std::ops::Shl<i32> for A {
|
||||
type Output = A;
|
||||
fn shl(mut self, other: i32) -> Self {
|
||||
self.0.push_str(&format!("{}", other));
|
||||
self
|
||||
}
|
||||
}
|
||||
#[allow(
|
||||
clippy::eq_op,
|
||||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::op_ref,
|
||||
clippy::double_parens
|
||||
)]
|
||||
#[warn(clippy::identity_op)]
|
||||
|
@ -38,4 +48,9 @@ fn main() {
|
|||
42 << 0;
|
||||
1 >> 0;
|
||||
42 >> 0;
|
||||
&x >> 0;
|
||||
x >> &0;
|
||||
|
||||
let mut a = A("".into());
|
||||
let b = a << 0; // no error: non-integer
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:16:5
|
||||
--> $DIR/identity_op.rs:26:5
|
||||
|
|
||||
LL | x + 0;
|
||||
| ^^^^^
|
||||
|
@ -7,64 +7,76 @@ LL | x + 0;
|
|||
= note: `-D clippy::identity-op` implied by `-D warnings`
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:17:5
|
||||
--> $DIR/identity_op.rs:27:5
|
||||
|
|
||||
LL | x + (1 - 1);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:19:5
|
||||
--> $DIR/identity_op.rs:29:5
|
||||
|
|
||||
LL | 0 + x;
|
||||
| ^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:22:5
|
||||
--> $DIR/identity_op.rs:32:5
|
||||
|
|
||||
LL | x | (0);
|
||||
| ^^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:25:5
|
||||
--> $DIR/identity_op.rs:35:5
|
||||
|
|
||||
LL | x * 1;
|
||||
| ^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:26:5
|
||||
--> $DIR/identity_op.rs:36:5
|
||||
|
|
||||
LL | 1 * x;
|
||||
| ^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:32:5
|
||||
--> $DIR/identity_op.rs:42:5
|
||||
|
|
||||
LL | -1 & x;
|
||||
| ^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `u`
|
||||
--> $DIR/identity_op.rs:35:5
|
||||
--> $DIR/identity_op.rs:45:5
|
||||
|
|
||||
LL | u & 255;
|
||||
| ^^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `42`
|
||||
--> $DIR/identity_op.rs:38:5
|
||||
--> $DIR/identity_op.rs:48:5
|
||||
|
|
||||
LL | 42 << 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `1`
|
||||
--> $DIR/identity_op.rs:39:5
|
||||
--> $DIR/identity_op.rs:49:5
|
||||
|
|
||||
LL | 1 >> 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `42`
|
||||
--> $DIR/identity_op.rs:40:5
|
||||
--> $DIR/identity_op.rs:50:5
|
||||
|
|
||||
LL | 42 >> 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: the operation is ineffective. Consider reducing it to `&x`
|
||||
--> $DIR/identity_op.rs:51:5
|
||||
|
|
||||
LL | &x >> 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: the operation is ineffective. Consider reducing it to `x`
|
||||
--> $DIR/identity_op.rs:52:5
|
||||
|
|
||||
LL | x >> &0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#![warn(clippy::iter_skip_next)]
|
||||
#![allow(clippy::blacklisted_name)]
|
||||
#![allow(clippy::iter_nth)]
|
||||
#![allow(unused_mut, dead_code)]
|
||||
|
||||
extern crate option_helpers;
|
||||
|
||||
|
@ -19,4 +20,18 @@ fn main() {
|
|||
let foo = IteratorFalsePositives { foo: 0 };
|
||||
let _ = foo.skip(42).next();
|
||||
let _ = foo.filter().skip(42).next();
|
||||
|
||||
// fix #8128
|
||||
let test_string = "1|1 2";
|
||||
let mut sp = test_string.split('|').map(|s| s.trim());
|
||||
let _: Vec<&str> = sp.nth(1).unwrap().split(' ').collect();
|
||||
if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) {
|
||||
let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect();
|
||||
};
|
||||
fn check<T>(mut s: T)
|
||||
where
|
||||
T: Iterator<Item = String>,
|
||||
{
|
||||
let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#![warn(clippy::iter_skip_next)]
|
||||
#![allow(clippy::blacklisted_name)]
|
||||
#![allow(clippy::iter_nth)]
|
||||
#![allow(unused_mut, dead_code)]
|
||||
|
||||
extern crate option_helpers;
|
||||
|
||||
|
@ -19,4 +20,18 @@ fn main() {
|
|||
let foo = IteratorFalsePositives { foo: 0 };
|
||||
let _ = foo.skip(42).next();
|
||||
let _ = foo.filter().skip(42).next();
|
||||
|
||||
// fix #8128
|
||||
let test_string = "1|1 2";
|
||||
let mut sp = test_string.split('|').map(|s| s.trim());
|
||||
let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
|
||||
if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) {
|
||||
let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
};
|
||||
fn check<T>(mut s: T)
|
||||
where
|
||||
T: Iterator<Item = String>,
|
||||
{
|
||||
let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:15:28
|
||||
--> $DIR/iter_skip_next.rs:16:28
|
||||
|
|
||||
LL | let _ = some_vec.iter().skip(42).next();
|
||||
| ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
|
||||
|
@ -7,22 +7,40 @@ LL | let _ = some_vec.iter().skip(42).next();
|
|||
= note: `-D clippy::iter-skip-next` implied by `-D warnings`
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:16:36
|
||||
--> $DIR/iter_skip_next.rs:17:36
|
||||
|
|
||||
LL | let _ = some_vec.iter().cycle().skip(42).next();
|
||||
| ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:17:20
|
||||
--> $DIR/iter_skip_next.rs:18:20
|
||||
|
|
||||
LL | let _ = (1..10).skip(10).next();
|
||||
| ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)`
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:18:33
|
||||
--> $DIR/iter_skip_next.rs:19:33
|
||||
|
|
||||
LL | let _ = &some_vec[..].iter().skip(3).next();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:27:26
|
||||
|
|
||||
LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:29:29
|
||||
|
|
||||
LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next.rs:35:29
|
||||
|
|
||||
LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
19
tests/ui/iter_skip_next_unfixable.rs
Normal file
19
tests/ui/iter_skip_next_unfixable.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
#![warn(clippy::iter_skip_next)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
/// Checks implementation of `ITER_SKIP_NEXT` lint
|
||||
fn main() {
|
||||
// fix #8128
|
||||
let test_string = "1|1 2";
|
||||
let sp = test_string.split('|').map(|s| s.trim());
|
||||
let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
|
||||
if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) {
|
||||
let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
};
|
||||
fn check<T>(s: T)
|
||||
where
|
||||
T: Iterator<Item = String>,
|
||||
{
|
||||
let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
}
|
||||
}
|
39
tests/ui/iter_skip_next_unfixable.stderr
Normal file
39
tests/ui/iter_skip_next_unfixable.stderr
Normal file
|
@ -0,0 +1,39 @@
|
|||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next_unfixable.rs:9:26
|
||||
|
|
||||
LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
||||
|
|
||||
= note: `-D clippy::iter-skip-next` implied by `-D warnings`
|
||||
help: for this change `sp` has to be mutable
|
||||
--> $DIR/iter_skip_next_unfixable.rs:8:9
|
||||
|
|
||||
LL | let sp = test_string.split('|').map(|s| s.trim());
|
||||
| ^^
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next_unfixable.rs:11:29
|
||||
|
|
||||
LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
||||
|
|
||||
help: for this change `s` has to be mutable
|
||||
--> $DIR/iter_skip_next_unfixable.rs:10:17
|
||||
|
|
||||
LL | if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) {
|
||||
| ^
|
||||
|
||||
error: called `skip(..).next()` on an iterator
|
||||
--> $DIR/iter_skip_next_unfixable.rs:17:29
|
||||
|
|
||||
LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
|
||||
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
||||
|
|
||||
help: for this change `s` has to be mutable
|
||||
--> $DIR/iter_skip_next_unfixable.rs:13:17
|
||||
|
|
||||
LL | fn check<T>(s: T)
|
||||
| ^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -43,7 +43,7 @@ LL | / for i in 3..(3 + src.len()) {
|
|||
LL | | dst[i] = src[count];
|
||||
LL | | count += 1;
|
||||
LL | | }
|
||||
| |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..((3 + src.len()) - 3)]);`
|
||||
| |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..(3 + src.len() - 3)]);`
|
||||
|
||||
error: it looks like you're manually copying between slices
|
||||
--> $DIR/with_loop_counters.rs:35:5
|
||||
|
|
|
@ -41,6 +41,15 @@ fn main() {
|
|||
x;
|
||||
!x;
|
||||
!(x && y);
|
||||
let a = 0;
|
||||
let b = 1;
|
||||
|
||||
a != b;
|
||||
a == b;
|
||||
a >= b;
|
||||
a > b;
|
||||
a <= b;
|
||||
a < b;
|
||||
if x {
|
||||
x
|
||||
} else {
|
||||
|
|
|
@ -53,6 +53,39 @@ fn main() {
|
|||
} else {
|
||||
true
|
||||
};
|
||||
let a = 0;
|
||||
let b = 1;
|
||||
|
||||
if a == b {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if a != b {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if a < b {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if a <= b {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if a > b {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if a >= b {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if x {
|
||||
x
|
||||
} else {
|
||||
|
|
|
@ -31,7 +31,67 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `!(x && y)`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:72:5
|
||||
--> $DIR/fixable.rs:59:5
|
||||
|
|
||||
LL | / if a == b {
|
||||
LL | | false
|
||||
LL | | } else {
|
||||
LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `a != b`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:64:5
|
||||
|
|
||||
LL | / if a != b {
|
||||
LL | | false
|
||||
LL | | } else {
|
||||
LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `a == b`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:69:5
|
||||
|
|
||||
LL | / if a < b {
|
||||
LL | | false
|
||||
LL | | } else {
|
||||
LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `a >= b`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:74:5
|
||||
|
|
||||
LL | / if a <= b {
|
||||
LL | | false
|
||||
LL | | } else {
|
||||
LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `a > b`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:79:5
|
||||
|
|
||||
LL | / if a > b {
|
||||
LL | | false
|
||||
LL | | } else {
|
||||
LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `a <= b`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:84:5
|
||||
|
|
||||
LL | / if a >= b {
|
||||
LL | | false
|
||||
LL | | } else {
|
||||
LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `a < b`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:105:5
|
||||
|
|
||||
LL | / if x {
|
||||
LL | | return true;
|
||||
|
@ -41,7 +101,7 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `return x`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:80:5
|
||||
--> $DIR/fixable.rs:113:5
|
||||
|
|
||||
LL | / if x {
|
||||
LL | | return false;
|
||||
|
@ -51,7 +111,7 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `return !x`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:88:5
|
||||
--> $DIR/fixable.rs:121:5
|
||||
|
|
||||
LL | / if x && y {
|
||||
LL | | return true;
|
||||
|
@ -61,7 +121,7 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `return x && y`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:96:5
|
||||
--> $DIR/fixable.rs:129:5
|
||||
|
|
||||
LL | / if x && y {
|
||||
LL | | return false;
|
||||
|
@ -71,7 +131,7 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `return !(x && y)`
|
||||
|
||||
error: equality checks against true are unnecessary
|
||||
--> $DIR/fixable.rs:104:8
|
||||
--> $DIR/fixable.rs:137:8
|
||||
|
|
||||
LL | if x == true {};
|
||||
| ^^^^^^^^^ help: try simplifying it as shown: `x`
|
||||
|
@ -79,25 +139,25 @@ LL | if x == true {};
|
|||
= note: `-D clippy::bool-comparison` implied by `-D warnings`
|
||||
|
||||
error: equality checks against false can be replaced by a negation
|
||||
--> $DIR/fixable.rs:108:8
|
||||
--> $DIR/fixable.rs:141:8
|
||||
|
|
||||
LL | if x == false {};
|
||||
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
|
||||
|
||||
error: equality checks against true are unnecessary
|
||||
--> $DIR/fixable.rs:118:8
|
||||
--> $DIR/fixable.rs:151:8
|
||||
|
|
||||
LL | if x == true {};
|
||||
| ^^^^^^^^^ help: try simplifying it as shown: `x`
|
||||
|
||||
error: equality checks against false can be replaced by a negation
|
||||
--> $DIR/fixable.rs:119:8
|
||||
--> $DIR/fixable.rs:152:8
|
||||
|
|
||||
LL | if x == false {};
|
||||
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:128:12
|
||||
--> $DIR/fixable.rs:161:12
|
||||
|
|
||||
LL | } else if returns_bool() {
|
||||
| ____________^
|
||||
|
@ -108,7 +168,7 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `{ !returns_bool() }`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:141:5
|
||||
--> $DIR/fixable.rs:174:5
|
||||
|
|
||||
LL | / if unsafe { no(4) } & 1 != 0 {
|
||||
LL | | true
|
||||
|
@ -118,16 +178,16 @@ LL | | };
|
|||
| |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:146:30
|
||||
--> $DIR/fixable.rs:179:30
|
||||
|
|
||||
LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:149:9
|
||||
--> $DIR/fixable.rs:182:9
|
||||
|
|
||||
LL | if unsafe { no(4) } & 1 != 0 { true } else { false }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 21 previous errors
|
||||
|
||||
|
|
|
@ -71,7 +71,18 @@ fn test_void_if_fun(b: bool) {
|
|||
fn test_void_match(x: u32) {
|
||||
match x {
|
||||
0 => (),
|
||||
_ => {},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_nested_match(x: u32) {
|
||||
match x {
|
||||
0 => (),
|
||||
1 => {
|
||||
let _ = 42;
|
||||
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +193,7 @@ async fn async_test_void_if_fun(b: bool) {
|
|||
async fn async_test_void_match(x: u32) {
|
||||
match x {
|
||||
0 => (),
|
||||
_ => {},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,17 @@ fn test_void_match(x: u32) {
|
|||
}
|
||||
}
|
||||
|
||||
fn test_nested_match(x: u32) {
|
||||
match x {
|
||||
0 => (),
|
||||
1 => {
|
||||
let _ = 42;
|
||||
return;
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_line() -> String {
|
||||
use std::io::BufRead;
|
||||
let stdin = ::std::io::stdin();
|
||||
|
|
|
@ -70,127 +70,139 @@ error: unneeded `return` statement
|
|||
--> $DIR/needless_return.rs:74:14
|
||||
|
|
||||
LL | _ => return,
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
| ^^^^^^ help: replace `return` with a unit value: `()`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:89:9
|
||||
|
|
||||
LL | return String::from("test");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:91:9
|
||||
|
|
||||
LL | return String::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:113:32
|
||||
|
|
||||
LL | bar.unwrap_or_else(|_| return)
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:118:13
|
||||
--> $DIR/needless_return.rs:83:13
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:120:20
|
||||
|
|
||||
LL | let _ = || return;
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:126:32
|
||||
|
|
||||
LL | res.unwrap_or_else(|_| return Foo)
|
||||
| ^^^^^^^^^^ help: remove `return`: `Foo`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:135:5
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:139:5
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:144:9
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:146:9
|
||||
|
|
||||
LL | return false;
|
||||
| ^^^^^^^^^^^^^ help: remove `return`: `false`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:152:17
|
||||
|
|
||||
LL | true => return false,
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `false`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:154:13
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:161:9
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:163:16
|
||||
|
|
||||
LL | let _ = || return true;
|
||||
| ^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:171:5
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:176:9
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:178:9
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:185:14
|
||||
--> $DIR/needless_return.rs:85:14
|
||||
|
|
||||
LL | _ => return,
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
| ^^^^^^ help: replace `return` with a unit value: `()`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:200:9
|
||||
--> $DIR/needless_return.rs:100:9
|
||||
|
|
||||
LL | return String::from("test");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:202:9
|
||||
--> $DIR/needless_return.rs:102:9
|
||||
|
|
||||
LL | return String::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
|
||||
|
||||
error: aborting due to 32 previous errors
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:124:32
|
||||
|
|
||||
LL | bar.unwrap_or_else(|_| return)
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:129:13
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:131:20
|
||||
|
|
||||
LL | let _ = || return;
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:137:32
|
||||
|
|
||||
LL | res.unwrap_or_else(|_| return Foo)
|
||||
| ^^^^^^^^^^ help: remove `return`: `Foo`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:146:5
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:150:5
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:155:9
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:157:9
|
||||
|
|
||||
LL | return false;
|
||||
| ^^^^^^^^^^^^^ help: remove `return`: `false`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:163:17
|
||||
|
|
||||
LL | true => return false,
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `false`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:165:13
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:172:9
|
||||
|
|
||||
LL | return true;
|
||||
| ^^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:174:16
|
||||
|
|
||||
LL | let _ = || return true;
|
||||
| ^^^^^^^^^^^ help: remove `return`: `true`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:182:5
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:187:9
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:189:9
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:196:14
|
||||
|
|
||||
LL | _ => return,
|
||||
| ^^^^^^ help: replace `return` with a unit value: `()`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:211:9
|
||||
|
|
||||
LL | return String::from("test");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:213:9
|
||||
|
|
||||
LL | return String::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
|
||||
|
||||
error: aborting due to 34 previous errors
|
||||
|
||||
|
|
45
tests/ui/neg_multiply.fixed
Normal file
45
tests/ui/neg_multiply.fixed
Normal file
|
@ -0,0 +1,45 @@
|
|||
// run-rustfix
|
||||
#![warn(clippy::neg_multiply)]
|
||||
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)]
|
||||
#![allow(unused)]
|
||||
|
||||
use std::ops::Mul;
|
||||
|
||||
struct X;
|
||||
|
||||
impl Mul<isize> for X {
|
||||
type Output = X;
|
||||
|
||||
fn mul(self, _r: isize) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<X> for isize {
|
||||
type Output = X;
|
||||
|
||||
fn mul(self, _r: X) -> X {
|
||||
X
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 0;
|
||||
|
||||
-x;
|
||||
|
||||
-x;
|
||||
|
||||
100 + -x;
|
||||
|
||||
-(100 + x);
|
||||
|
||||
-17;
|
||||
|
||||
0xcafe | -0xff00;
|
||||
|
||||
-1 * -1; // should be ok
|
||||
|
||||
X * -1; // should be ok
|
||||
-1 * X; // should also be ok
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
// run-rustfix
|
||||
#![warn(clippy::neg_multiply)]
|
||||
#![allow(clippy::no_effect, clippy::unnecessary_operation)]
|
||||
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)]
|
||||
#![allow(unused)]
|
||||
|
||||
use std::ops::Mul;
|
||||
|
||||
|
@ -28,6 +30,14 @@ fn main() {
|
|||
|
||||
-1 * x;
|
||||
|
||||
100 + x * -1;
|
||||
|
||||
(100 + x) * -1;
|
||||
|
||||
-1 * 17;
|
||||
|
||||
0xcafe | 0xff00 * -1;
|
||||
|
||||
-1 * -1; // should be ok
|
||||
|
||||
X * -1; // should be ok
|
||||
|
|
|
@ -1,16 +1,40 @@
|
|||
error: negation by multiplying with `-1`
|
||||
--> $DIR/neg_multiply.rs:27:5
|
||||
error: this multiplication by -1 can be written more succinctly
|
||||
--> $DIR/neg_multiply.rs:29:5
|
||||
|
|
||||
LL | x * -1;
|
||||
| ^^^^^^
|
||||
| ^^^^^^ help: consider using: `-x`
|
||||
|
|
||||
= note: `-D clippy::neg-multiply` implied by `-D warnings`
|
||||
|
||||
error: negation by multiplying with `-1`
|
||||
--> $DIR/neg_multiply.rs:29:5
|
||||
error: this multiplication by -1 can be written more succinctly
|
||||
--> $DIR/neg_multiply.rs:31:5
|
||||
|
|
||||
LL | -1 * x;
|
||||
| ^^^^^^
|
||||
| ^^^^^^ help: consider using: `-x`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: this multiplication by -1 can be written more succinctly
|
||||
--> $DIR/neg_multiply.rs:33:11
|
||||
|
|
||||
LL | 100 + x * -1;
|
||||
| ^^^^^^ help: consider using: `-x`
|
||||
|
||||
error: this multiplication by -1 can be written more succinctly
|
||||
--> $DIR/neg_multiply.rs:35:5
|
||||
|
|
||||
LL | (100 + x) * -1;
|
||||
| ^^^^^^^^^^^^^^ help: consider using: `-(100 + x)`
|
||||
|
||||
error: this multiplication by -1 can be written more succinctly
|
||||
--> $DIR/neg_multiply.rs:37:5
|
||||
|
|
||||
LL | -1 * 17;
|
||||
| ^^^^^^^ help: consider using: `-17`
|
||||
|
||||
error: this multiplication by -1 can be written more succinctly
|
||||
--> $DIR/neg_multiply.rs:39:14
|
||||
|
|
||||
LL | 0xcafe | 0xff00 * -1;
|
||||
| ^^^^^^^^^^^ help: consider using: `-0xff00`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
33
tests/ui/numbered_fields.fixed
Normal file
33
tests/ui/numbered_fields.fixed
Normal file
|
@ -0,0 +1,33 @@
|
|||
//run-rustfix
|
||||
#![warn(clippy::init_numbered_fields)]
|
||||
|
||||
#[derive(Default)]
|
||||
struct TupleStruct(u32, u32, u8);
|
||||
|
||||
// This shouldn't lint because it's in a macro
|
||||
macro_rules! tuple_struct_init {
|
||||
() => {
|
||||
TupleStruct { 0: 0, 1: 1, 2: 2 }
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let tuple_struct = TupleStruct::default();
|
||||
|
||||
// This should lint
|
||||
let _ = TupleStruct(1u32, 42, 23u8);
|
||||
|
||||
// This should also lint and order the fields correctly
|
||||
let _ = TupleStruct(1u32, 3u32, 2u8);
|
||||
|
||||
// Ok because of default initializer
|
||||
let _ = TupleStruct { 0: 42, ..tuple_struct };
|
||||
|
||||
let _ = TupleStruct {
|
||||
1: 23,
|
||||
..TupleStruct::default()
|
||||
};
|
||||
|
||||
// Ok because it's in macro
|
||||
let _ = tuple_struct_init!();
|
||||
}
|
41
tests/ui/numbered_fields.rs
Normal file
41
tests/ui/numbered_fields.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
//run-rustfix
|
||||
#![warn(clippy::init_numbered_fields)]
|
||||
|
||||
#[derive(Default)]
|
||||
struct TupleStruct(u32, u32, u8);
|
||||
|
||||
// This shouldn't lint because it's in a macro
|
||||
macro_rules! tuple_struct_init {
|
||||
() => {
|
||||
TupleStruct { 0: 0, 1: 1, 2: 2 }
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let tuple_struct = TupleStruct::default();
|
||||
|
||||
// This should lint
|
||||
let _ = TupleStruct {
|
||||
0: 1u32,
|
||||
1: 42,
|
||||
2: 23u8,
|
||||
};
|
||||
|
||||
// This should also lint and order the fields correctly
|
||||
let _ = TupleStruct {
|
||||
0: 1u32,
|
||||
2: 2u8,
|
||||
1: 3u32,
|
||||
};
|
||||
|
||||
// Ok because of default initializer
|
||||
let _ = TupleStruct { 0: 42, ..tuple_struct };
|
||||
|
||||
let _ = TupleStruct {
|
||||
1: 23,
|
||||
..TupleStruct::default()
|
||||
};
|
||||
|
||||
// Ok because it's in macro
|
||||
let _ = tuple_struct_init!();
|
||||
}
|
26
tests/ui/numbered_fields.stderr
Normal file
26
tests/ui/numbered_fields.stderr
Normal file
|
@ -0,0 +1,26 @@
|
|||
error: used a field initializer for a tuple struct
|
||||
--> $DIR/numbered_fields.rs:18:13
|
||||
|
|
||||
LL | let _ = TupleStruct {
|
||||
| _____________^
|
||||
LL | | 0: 1u32,
|
||||
LL | | 1: 42,
|
||||
LL | | 2: 23u8,
|
||||
LL | | };
|
||||
| |_____^ help: try this instead: `TupleStruct(1u32, 42, 23u8)`
|
||||
|
|
||||
= note: `-D clippy::init-numbered-fields` implied by `-D warnings`
|
||||
|
||||
error: used a field initializer for a tuple struct
|
||||
--> $DIR/numbered_fields.rs:25:13
|
||||
|
|
||||
LL | let _ = TupleStruct {
|
||||
| _____________^
|
||||
LL | | 0: 1u32,
|
||||
LL | | 2: 2u8,
|
||||
LL | | 1: 3u32,
|
||||
LL | | };
|
||||
| |_____^ help: try this instead: `TupleStruct(1u32, 3u32, 2u8)`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -5,12 +5,12 @@ pub struct Bar;
|
|||
|
||||
pub trait Whatever {
|
||||
fn what(&self) -> Self;
|
||||
// There should be no warning here!
|
||||
// There should be no warning here! (returns a reference)
|
||||
fn what2(&self) -> &Self;
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
// There should be no warning here!
|
||||
// There should be no warning here! (note taking a self argument)
|
||||
pub fn not_new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
@ -20,23 +20,38 @@ impl Bar {
|
|||
pub fn bar(self) -> Self {
|
||||
self
|
||||
}
|
||||
// There should be no warning here!
|
||||
// There should be no warning here! (private method)
|
||||
fn foo2(&self) -> Self {
|
||||
Self
|
||||
}
|
||||
// There should be no warning here!
|
||||
// There should be no warning here! (returns a reference)
|
||||
pub fn foo3(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
// There should be no warning here! (already a `must_use` attribute)
|
||||
#[must_use]
|
||||
pub fn foo4(&self) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Whatever for Bar {
|
||||
// There should be no warning here!
|
||||
// There should be no warning here! (comes from the trait)
|
||||
fn what(&self) -> Self {
|
||||
self.foo2()
|
||||
}
|
||||
// There should be no warning here!
|
||||
// There should be no warning here! (comes from the trait)
|
||||
fn what2(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub struct Foo;
|
||||
|
||||
impl Foo {
|
||||
// There should be no warning here! (`Foo` already implements `#[must_use]`)
|
||||
fn foo(&self) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ fn syntax() {
|
|||
let _ = |[x]: [u32; 1]| {
|
||||
let x = 1;
|
||||
};
|
||||
let y = Some(1);
|
||||
if let Some(y) = y {}
|
||||
}
|
||||
|
||||
fn negative() {
|
||||
|
|
|
@ -241,17 +241,29 @@ note: previous binding is here
|
|||
LL | let _ = |[x]: [u32; 1]| {
|
||||
| ^
|
||||
|
||||
error: `y` is shadowed
|
||||
--> $DIR/shadow.rs:51:17
|
||||
|
|
||||
LL | if let Some(y) = y {}
|
||||
| ^
|
||||
|
|
||||
note: previous binding is here
|
||||
--> $DIR/shadow.rs:50:9
|
||||
|
|
||||
LL | let y = Some(1);
|
||||
| ^
|
||||
|
||||
error: `_b` shadows a previous, unrelated binding
|
||||
--> $DIR/shadow.rs:85:9
|
||||
--> $DIR/shadow.rs:87:9
|
||||
|
|
||||
LL | let _b = _a;
|
||||
| ^^
|
||||
|
|
||||
note: previous binding is here
|
||||
--> $DIR/shadow.rs:84:28
|
||||
--> $DIR/shadow.rs:86:28
|
||||
|
|
||||
LL | pub async fn foo2(_a: i32, _b: i64) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 21 previous errors
|
||||
error: aborting due to 22 previous errors
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
fn main() {
|
||||
if f() { g(); }
|
||||
if !f() { g(); }
|
||||
if !(1 == 2) { g(); }
|
||||
if 1 != 2 { g(); }
|
||||
}
|
||||
|
||||
fn f() -> bool {
|
||||
|
|
|
@ -16,7 +16,7 @@ error: boolean short circuit operator in statement may be clearer using an expli
|
|||
--> $DIR/short_circuit_statement.rs:9:5
|
||||
|
|
||||
LL | 1 == 2 || g();
|
||||
| ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }`
|
||||
| ^^^^^^^^^^^^^^ help: replace it with: `if 1 != 2 { g(); }`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
fn nested_local() {
|
||||
let _ = {
|
||||
let _ = {
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
let _ = unsafe {};
|
||||
};
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ fn nested_local() {
|
|||
fn deep_nest() {
|
||||
let _ = {
|
||||
let _ = {
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
let _ = unsafe {};
|
||||
|
||||
// Safety:
|
||||
|
@ -28,7 +28,7 @@ fn deep_nest() {
|
|||
// Safety:
|
||||
let _ = unsafe {};
|
||||
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
unsafe {};
|
||||
};
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ fn deep_nest() {
|
|||
unsafe {};
|
||||
};
|
||||
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
unsafe {};
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ fn line_comment() {
|
|||
}
|
||||
|
||||
fn line_comment_newlines() {
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
|
||||
unsafe {}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ fn block_comment() {
|
|||
}
|
||||
|
||||
fn block_comment_newlines() {
|
||||
/* Safety: */
|
||||
/* SAFETY: */
|
||||
|
||||
unsafe {}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ fn inline_block_comment() {
|
|||
|
||||
fn block_comment_with_extras() {
|
||||
/* This is a description
|
||||
* Safety:
|
||||
* SAFETY:
|
||||
*/
|
||||
unsafe {}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ fn buried_safety() {
|
|||
}
|
||||
|
||||
fn safety_with_prepended_text() {
|
||||
// This is a test. Safety:
|
||||
// This is a test. safety:
|
||||
unsafe {}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ fn local_line_comment() {
|
|||
}
|
||||
|
||||
fn local_block_comment() {
|
||||
/* Safety: */
|
||||
/* SAFETY: */
|
||||
let _ = unsafe {};
|
||||
}
|
||||
|
||||
|
@ -142,18 +142,18 @@ fn comment_array() {
|
|||
}
|
||||
|
||||
fn comment_tuple() {
|
||||
// Safety:
|
||||
// sAFETY:
|
||||
let _ = (42, unsafe {}, "test", unsafe {});
|
||||
}
|
||||
|
||||
fn comment_unary() {
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
let _ = *unsafe { &42 };
|
||||
}
|
||||
|
||||
#[allow(clippy::match_single_binding)]
|
||||
fn comment_match() {
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
let _ = match unsafe {} {
|
||||
_ => {},
|
||||
};
|
||||
|
@ -177,7 +177,7 @@ fn comment_macro_call() {
|
|||
}
|
||||
|
||||
t!(
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
unsafe {}
|
||||
);
|
||||
}
|
||||
|
@ -194,18 +194,18 @@ fn comment_macro_def() {
|
|||
}
|
||||
|
||||
fn non_ascii_comment() {
|
||||
// ॐ᧻໒ Safety: ௵∰
|
||||
// ॐ᧻໒ SaFeTy: ௵∰
|
||||
unsafe {};
|
||||
}
|
||||
|
||||
fn local_commented_block() {
|
||||
let _ =
|
||||
// Safety:
|
||||
// safety:
|
||||
unsafe {};
|
||||
}
|
||||
|
||||
fn local_nest() {
|
||||
// Safety:
|
||||
// safety:
|
||||
let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})];
|
||||
}
|
||||
|
||||
|
@ -267,17 +267,17 @@ fn no_comment_macro_def() {
|
|||
}
|
||||
|
||||
fn trailing_comment() {
|
||||
unsafe {} // Safety:
|
||||
unsafe {} // SAFETY:
|
||||
}
|
||||
|
||||
fn internal_comment() {
|
||||
unsafe {
|
||||
// Safety:
|
||||
// SAFETY:
|
||||
}
|
||||
}
|
||||
|
||||
fn interference() {
|
||||
// Safety
|
||||
// SAFETY
|
||||
|
||||
let _ = 42;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ LL | unsafe {}
|
|||
= note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + unsafe {}
|
||||
|
|
||||
|
||||
|
@ -19,7 +19,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
|
||||
|
|
||||
|
||||
|
@ -31,7 +31,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {});
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = (42, unsafe {}, "test", unsafe {});
|
||||
|
|
||||
|
||||
|
@ -43,7 +43,7 @@ LL | let _ = *unsafe { &42 };
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = *unsafe { &42 };
|
||||
|
|
||||
|
||||
|
@ -55,7 +55,7 @@ LL | let _ = match unsafe {} {
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = match unsafe {} {
|
||||
|
|
||||
|
||||
|
@ -67,7 +67,7 @@ LL | let _ = &unsafe {};
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = &unsafe {};
|
||||
|
|
||||
|
||||
|
@ -79,7 +79,7 @@ LL | let _ = [unsafe {}; 5];
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = [unsafe {}; 5];
|
||||
|
|
||||
|
||||
|
@ -91,7 +91,7 @@ LL | let _ = unsafe {};
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + let _ = unsafe {};
|
||||
|
|
||||
|
||||
|
@ -103,7 +103,7 @@ LL | t!(unsafe {});
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ t!(// Safety: ...
|
||||
LL ~ t!(// SAFETY: ...
|
||||
LL ~ unsafe {});
|
||||
|
|
||||
|
||||
|
@ -122,13 +122,13 @@ LL | t!();
|
|||
error: unsafe block missing a safety comment
|
||||
--> $DIR/undocumented_unsafe_blocks.rs:270:5
|
||||
|
|
||||
LL | unsafe {} // Safety:
|
||||
LL | unsafe {} // SAFETY:
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ unsafe {} // Safety:
|
||||
LL ~ // SAFETY: ...
|
||||
LL ~ unsafe {} // SAFETY:
|
||||
|
|
||||
|
||||
error: unsafe block missing a safety comment
|
||||
|
@ -139,7 +139,7 @@ LL | unsafe {
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL + unsafe {
|
||||
|
|
||||
|
||||
|
@ -151,7 +151,7 @@ LL | unsafe {};
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ // Safety: ...
|
||||
LL ~ // SAFETY: ...
|
||||
LL ~ unsafe {};
|
||||
|
|
||||
|
||||
|
@ -163,7 +163,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
|
|||
|
|
||||
help: consider adding a safety comment
|
||||
|
|
||||
LL ~ println!("{}", // Safety: ...
|
||||
LL ~ println!("{}", // SAFETY: ...
|
||||
LL ~ unsafe { String::from_utf8_unchecked(vec![]) });
|
||||
|
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ fn unwrap_or_else_default() {
|
|||
with_enum.unwrap_or_else(Enum::A);
|
||||
|
||||
let with_new = Some(vec![1]);
|
||||
with_new.unwrap_or_else(Vec::new);
|
||||
with_new.unwrap_or_default();
|
||||
|
||||
let with_err: Result<_, ()> = Ok(vec![1]);
|
||||
with_err.unwrap_or_else(make);
|
||||
|
@ -66,6 +66,9 @@ fn unwrap_or_else_default() {
|
|||
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_default();
|
||||
|
||||
let with_default_type: Option<Vec<u64>> = None;
|
||||
with_default_type.unwrap_or_default();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -66,6 +66,9 @@ fn unwrap_or_else_default() {
|
|||
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_else(u64::default);
|
||||
|
||||
let with_default_type: Option<Vec<u64>> = None;
|
||||
with_default_type.unwrap_or_else(Vec::new);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:48:5
|
||||
|
|
||||
LL | with_new.unwrap_or_else(Vec::new);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()`
|
||||
|
|
||||
= note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:62:5
|
||||
|
|
||||
LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
|
||||
|
|
||||
= note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:65:5
|
||||
|
@ -18,5 +24,11 @@ error: use of `.unwrap_or_else(..)` to construct default value
|
|||
LL | with_default_type.unwrap_or_else(u64::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:71:5
|
||||
|
|
||||
LL | with_default_type.unwrap_or_else(Vec::new);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
Loading…
Reference in a new issue