+++ /dev/null
----
-name: Blank Issue
-about: Create a blank issue.
----
-
-
-<!--
-Additional labels can be added to this issue by including the following command
-(without the space after the @ symbol):
-
-@ rustbot label +<label>
-
-Common labels for this issue type are:
-* C-an-interesting-project
-* C-enhancement
-* C-question
-* C-tracking-issue
--->
--- /dev/null
+name: Blank Issue
+description: Create a blank issue.
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing an issue!
+ - type: textarea
+ id: problem
+ attributes:
+ label: Description
+ description: >
+ Please provide a discription of the issue, along with any information
+ you feel relevant to replicate it.
+ validations:
+ required: true
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: labels
+ attributes:
+ label: Additional Labels
+ description: >
+ Additional labels can be added to this issue by including the following
+ command
+ placeholder: |
+ @rustbot label +<label>
+
+ Common labels for this issue type are:
+ * C-an-interesting-project
+ * C-enhancement
+ * C-question
+ * C-tracking-issue
+++ /dev/null
----
-name: Bug Report
-about: Create a bug report for Clippy
-labels: C-bug
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
--->
-
-I tried this code:
-
-```rust
-<code>
-```
-
-I expected to see this happen: *explanation*
-
-Instead, this happened: *explanation*
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
-
-<!--
-Additional labels can be added to this issue by including the following command
-(without the space after the @ symbol):
-
-@ rustbot label +<label>
-
-Common labels for this issue type are:
-* `I-suggestion-causes-error`
--->
--- /dev/null
+name: Bug Report
+description: Create a bug report for Clippy
+labels: ["C-bug"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing a bug report! 🐛
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: >
+ Please provide a short summary of the bug, along with any information
+ you feel relevant to replicate the bug.
+ validations:
+ required: true
+ - type: textarea
+ id: reproducer
+ attributes:
+ label: Reproducer
+ description: Please provide the code and steps to repoduce the bug
+ value: |
+ I tried this code:
+
+ ```rust
+ <code>
+ ```
+
+ I expected to see this happen:
+
+ Instead, this happened:
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: labels
+ attributes:
+ label: Additional Labels
+ description: >
+ Additional labels can be added to this issue by including the following
+ command
+ placeholder: |
+ @rustbot label +<label>
+
+ Common labels for this issue type are:
+ * `I-suggestion-causes-error`
+++ /dev/null
----
-name: Bug Report (False Negative)
-about: Create a bug report about missing warnings from a lint
-labels: C-bug, I-false-negative
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
--->
-Lint name:
-
-
-I tried this code:
-
-```rust
-<code>
-```
-
-I expected to see this happen: *explanation*
-
-Instead, this happened: *explanation*
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
--- /dev/null
+name: Bug Report (False Negative)
+description: Create a bug report about missing warnings from a lint
+labels: ["C-bug", "I-false-negative"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing a bug report! 🐛
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: >
+ Please provide a short summary of the bug, along with any information
+ you feel relevant to replicate the bug.
+ validations:
+ required: true
+ - type: input
+ id: lint-name
+ attributes:
+ label: Lint Name
+ description: Please provide the lint name.
+ - type: textarea
+ id: reproducer
+ attributes:
+ label: Reproducer
+ description: Please provide the code and steps to repoduce the bug
+ value: |
+ I tried this code:
+
+ ```rust
+ <code>
+ ```
+
+ I expected to see this happen:
+
+ Instead, this happened:
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+++ /dev/null
----
-name: Bug Report (False Positive)
-about: Create a bug report about a wrongly emitted lint warning
-labels: C-bug, I-false-positive
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
--->
-Lint name:
-
-
-I tried this code:
-
-```rust
-<code>
-```
-
-I expected to see this happen: *explanation*
-
-Instead, this happened: *explanation*
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
-
-<!--
-Additional labels can be added to this issue by including the following command
-(without the space after the @ symbol):
-
-@ rustbot label +<label>
-
-Common labels for this issue type are:
-* I-suggestion-causes-error
--->
--- /dev/null
+name: Bug Report (False Positive)
+description: Create a bug report about a wrongly emitted lint warning
+labels: ["C-bug", "I-false-positive"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing a bug report! 🐛
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: >
+ Please provide a short summary of the bug, along with any information
+ you feel relevant to replicate the bug.
+ validations:
+ required: true
+ - type: input
+ id: lint-name
+ attributes:
+ label: Lint Name
+ description: Please provide the lint name.
+ - type: textarea
+ id: reproducer
+ attributes:
+ label: Reproducer
+ description: >
+ Please provide the code and steps to repoduce the bug together with the
+ output from Clippy.
+ value: |
+ I tried this code:
+
+ ```rust
+ <code>
+ ```
+
+ I saw this happen:
+
+ ```
+ <output>
+ ```
+
+ I expected to see this happen:
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: labels
+ attributes:
+ label: Additional Labels
+ description: >
+ Additional labels can be added to this issue by including the following
+ command
+ placeholder: |
+ @rustbot label +<label>
+
+ Common labels for this issue type are:
+ * `I-suggestion-causes-error`
+++ /dev/null
----
-name: Internal Compiler Error
-about: Create a report for an internal compiler error in Clippy.
-labels: C-bug, I-ICE
----
-<!--
-Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
-a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
-how to create smaller examples.
-
-http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-
--->
-
-### Code
-
-```rust
-<code>
-```
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
-
-### Error output
-
-```
-<output>
-```
-
-<!--
-Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
-environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
--->
-<details><summary>Backtrace</summary>
- <p>
-
- ```
- <backtrace>
- ```
-
- </p>
-</details>
--- /dev/null
+name: Internal Compiler Error
+description: Create a report for an internal compiler error (ICE) in Clippy.
+labels: ["C-bug", "I-ICE"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for finding an Internal Compiler Error! 🧊
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: |
+ If possible, try to provide a minimal verifiable example. You can read ["Rust Bug Minimization Patterns"][mve] for how to create smaller examples. Otherwise, provide the crate where the ICE occured.
+
+ [mve]: http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
+ validations:
+ required: true
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: error
+ attributes:
+ label: Error output
+ description: >
+ Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in
+ your environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+ value: |
+ <details><summary>Backtrace</summary>
+ <p>
+
+ ```
+ <backtrace>
+ ```
+
+ </p>
+ </details>
+++ /dev/null
----
-name: New lint suggestion
-about: Suggest a new Clippy lint.
-labels: A-lint
----
-
-### What it does
-
-*What does this lint do?*
-
-### Categories (optional)
-
-- Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
-
-*What is the advantage of the recommended code over the original code*
-
-For example:
-- Remove bounds check inserted by ...
-- Remove the need to duplicate/store ...
-- Remove typo ...
-
-### Drawbacks
-
-None.
-
-### Example
-
-```rust
-<code>
-```
-
-Could be written as:
-
-```rust
-<code>
-```
--- /dev/null
+name: New lint suggestion
+description: Suggest a new Clippy lint.
+labels: ["A-lint"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for your lint idea!
+ - type: textarea
+ id: what
+ attributes:
+ label: What it does
+ description: What does this lint do?
+ validations:
+ required: true
+ - type: input
+ id: lint-name
+ attributes:
+ label: Lint Name
+ description: Please provide the lint name.
+ - type: dropdown
+ id: category
+ attributes:
+ label: Category
+ description: >
+ What category should this lint go into? If you're unsure you can select
+ multiple categories. You can find a category description in the
+ `README`.
+ multiple: true
+ options:
+ - correctness
+ - suspicious
+ - style
+ - complexity
+ - perf
+ - pedantic
+ - restriction
+ - cargo
+ - type: textarea
+ id: advantage
+ attributes:
+ label: Advantage
+ description: >
+ What is the advantage of the recommended code over the original code?
+ placeholder: |
+ - Remove bounds check inserted by ...
+ - Remove the need to duplicate/store ...
+ - Remove typo ...
+ - type: textarea
+ id: drawbacks
+ attributes:
+ label: Drawbacks
+ description: What might be possible drawbacks of such a lint?
+ - type: textarea
+ id: example
+ attributes:
+ label: Example
+ description: >
+ Include a short example showing when the lint should trigger together
+ with the improved code.
+ value: |
+ ```rust
+ <code>
+ ```
+
+ Could be written as:
+
+ ```rust
+ <code>
+ ```
+ validations:
+ required: true
[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
+[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
[package]
name = "clippy"
-version = "0.1.58"
+version = "0.1.59"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
[package]
name = "clippy_lints"
-version = "0.1.58"
+version = "0.1.59"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::higher;
use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
+use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks};
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
// bind the first argument of the `assert!` macro
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
- // block
- if let ExprKind::Block(block, _) = then.kind;
- if block.stmts.is_empty();
- if let Some(block_expr) = &block.expr;
- // inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
- if let Some(begin_panic_call) = match block_expr.kind {
- ExprKind::Block(inner_block, _) => &inner_block.expr,
- _ => &block.expr,
- };
+ let begin_panic_call = peel_blocks(then);
// function call
if let Some(arg) = match_panic_call(cx, begin_panic_call);
// bind the second argument of the `assert!` macro if it exists
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::match_type;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_ref_operators, remove_blocks, strip_pat_refs};
+use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
&paths::SLICE_ITER);
let operand_is_arg = |expr| {
- let expr = peel_ref_operators(cx, remove_blocks(expr));
+ let expr = peel_ref_operators(cx, peel_blocks(expr));
path_to_local_id(expr, arg_id)
};
let needle = if operand_is_arg(l) {
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_ref_operators, SpanlessEq};
+use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq};
use if_chain::if_chain;
use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
+use rustc_hir::{Arm, Expr, Guard, HirId, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{MultiSpan, Span};
outer_guard: Option<&'tcx Guard<'tcx>>,
outer_else_body: Option<&'tcx Expr<'tcx>>,
) {
- let inner_expr = strip_singleton_blocks(outer_then_body);
+ let inner_expr = peel_blocks_with_stmt(outer_then_body);
if_chain! {
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr);
if let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
}
}
-fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
- while let ExprKind::Block(block, _) = expr.kind {
- match (block.stmts, block.expr) {
- ([stmt], None) => match stmt.kind {
- StmtKind::Expr(e) | StmtKind::Semi(e) => expr = e,
- _ => break,
- },
- ([], Some(e)) => expr = e,
- _ => break,
- }
- }
- expr
-}
-
/// A "wild-like" arm has a wild (`_`) or `None` pattern and no guard. Such arms can be "collapsed"
/// into a single wild arm without any significant loss in semantics or readability.
fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
/// `dbg!` macro is intended as a debugging tool. It
/// should not be in version control.
///
+ /// ### Known problems
+ /// * The lint level is unaffected by crate attributes. The level can still
+ /// be set for functions, modules and other items. To change the level for
+ /// the entire crate, please use command line flags. More information and a
+ /// configuration example can be found in [clippy#6610].
+ ///
+ /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+ ///
/// ### Example
/// ```rust,ignore
/// // Bad
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{is_automatically_derived, is_default_equivalent, remove_blocks};
+use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks};
use rustc_hir::{
def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
}
}
}
- let should_emit = match remove_blocks(func_expr).kind {
+ let should_emit = match peel_blocks(func_expr).kind {
ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
ExprKind::Call(callee, args)
if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path};
use if_chain::if_chain;
-use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{
BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
trait_ref: &TraitRef<'_>,
ty: Ty<'tcx>,
) {
- fn item_from_def_id<'tcx>(cx: &LateContext<'tcx>, def_id: DefId) -> &'tcx Item<'tcx> {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- cx.tcx.hir().expect_item(hir_id)
- }
-
fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
walk_item(&mut visitor, item);
if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
if cx.tcx.inherent_impls(def.did)
.iter()
- .map(|imp_did| item_from_def_id(cx, *imp_did))
+ .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
.any(|imp| has_unsafe(cx, imp));
then {
span_lint_and_help(
};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
-use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, sugg};
+use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
- if let ExprKind::Block(block, _) = then.kind;
- if block.stmts.is_empty();
- if let Some(if_body_expr) = block.expr;
- if let Some(ExprKind::Block(else_block, _)) = r#else.map(|el| &el.kind);
- if else_block.stmts.is_empty();
- if let Some(else_body_expr) = else_block.expr;
+ if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr);
+ let if_body_expr = peel_blocks(then);
+ let else_body_expr = peel_blocks(r#else);
if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
then {
let positive_abs_sugg = (
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs};
+use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks};
use if_chain::if_chain;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
if is_lang_ctor(cx, then_call_qpath, OptionSome);
- if let ExprKind::Block(els_block, _) = els.kind;
- if els_block.stmts.is_empty();
- if let Some(els_expr) = els_block.expr;
- if let ExprKind::Path(ref qpath) = els_expr.kind;
+ if let ExprKind::Path(ref qpath) = peel_blocks(els).kind;
if is_lang_ctor(cx, qpath, OptionNone);
if !stmts_contains_early_return(then_block.stmts);
then {
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::SpanlessEq;
+use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath, StmtKind};
+use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
// Ensure that the binary operator is >, != and <
if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node;
- // Check if the true condition block has only one statement
- if let ExprKind::Block(block, _) = then.kind;
- if block.stmts.len() == 1 && block.expr.is_none();
-
// Check if assign operation is done
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let Some(target) = subtracts_one(cx, e);
+ if let Some(target) = subtracts_one(cx, then);
// Extracting out the variable name
if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind;
}
}
-fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'a>> {
- match expr.kind {
+fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
+ match peel_blocks_with_stmt(expr).kind {
ExprKind::AssignOp(ref op1, target, value) => {
if_chain! {
if BinOpKind::Sub == op1.node;
LintId::of(methods::MANUAL_SPLIT_ONCE),
LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+ LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
+ LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
LintId::of(needless_update::NEEDLESS_UPDATE),
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SPLIT_ONCE),
+ LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::OPTION_AS_REF_DEREF),
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
needless_continue::NEEDLESS_CONTINUE,
needless_for_each::NEEDLESS_FOR_EACH,
+ needless_late_init::NEEDLESS_LATE_INIT,
needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
needless_question_mark::NEEDLESS_QUESTION_MARK,
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_INTEGER),
+ LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
LintId::of(methods::IMPLICIT_CLONE),
LintId::of(methods::INEFFICIENT_TO_STRING),
- LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(misc::FLOAT_CMP),
LintId::of(misc::USED_UNDERSCORE_BINDING),
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+ LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(neg_multiply::NEG_MULTIPLY),
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
mod needless_borrowed_ref;
mod needless_continue;
mod needless_for_each;
+mod needless_late_init;
mod needless_option_as_deref;
mod needless_pass_by_value;
mod needless_question_mark;
store.register_late_pass(move || Box::new(format_args::FormatArgs));
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
+ store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
// add lints here, do not remove this comment, it's used in `new_lint`
}
///
/// ### Known problems
/// - We bail out if the function has a `where` clause where lifetimes
- /// are mentioned due to potenial false positives.
+ /// are mentioned due to potential false positives.
/// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
/// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
///
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_lang_ctor, path_to_local_id};
+use clippy_utils::{is_lang_ctor, path_to_local_id, peel_blocks_with_stmt};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionSome, ResultOk};
-use rustc_hir::{Expr, ExprKind, Pat, PatKind, StmtKind};
+use rustc_hir::{Expr, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::source_map::Span;
body: &'tcx Expr<'_>,
span: Span,
) {
- if let ExprKind::Block(block, _) = body.kind {
- // Ensure the `if let` statement is the only expression or statement in the for-loop
- let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() {
- let match_stmt = &block.stmts[0];
- if let StmtKind::Semi(inner_expr) = match_stmt.kind {
- Some(inner_expr)
- } else {
- None
- }
- } else if block.stmts.is_empty() {
- block.expr
- } else {
- None
- };
+ let inner_expr = peel_blocks_with_stmt(body);
+ if_chain! {
+ if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
+ = higher::IfLet::hir(cx, inner_expr);
+ // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
+ if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
+ if path_to_local_id(let_expr, pat_hir_id);
+ // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
+ if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
+ let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
+ let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
+ if some_ctor || ok_ctor;
+ // Ensure expr in `if let` is not used afterwards
+ if !is_local_used(cx, if_then, pat_hir_id);
+ then {
+ let if_let_type = if some_ctor { "Some" } else { "Ok" };
+ // Prepare the error message
+ let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
- if_chain! {
- if let Some(inner_expr) = inner_expr;
- if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
- = higher::IfLet::hir(cx, inner_expr);
- // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
- if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
- if path_to_local_id(let_expr, pat_hir_id);
- // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
- if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
- let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
- let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
- if some_ctor || ok_ctor;
- // Ensure epxr in `if let` is not used afterwards
- if !is_local_used(cx, if_then, pat_hir_id);
- then {
- let if_let_type = if some_ctor { "Some" } else { "Ok" };
- // Prepare the error message
- let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
-
- // Prepare the help message
- let mut applicability = Applicability::MaybeIncorrect;
- let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
- let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
- ty::Ref(_, inner, _) => match inner.kind() {
- ty::Ref(..) => ".copied()",
- _ => ""
- }
+ // Prepare the help message
+ let mut applicability = Applicability::MaybeIncorrect;
+ let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
+ let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
+ ty::Ref(_, inner, _) => match inner.kind() {
+ ty::Ref(..) => ".copied()",
_ => ""
- };
+ }
+ _ => ""
+ };
- span_lint_and_then(
- cx,
- MANUAL_FLATTEN,
- span,
- &msg,
- |diag| {
- let sugg = format!("{}{}.flatten()", arg_snippet, copied);
- diag.span_suggestion(
- arg.span,
- "try",
- sugg,
- Applicability::MaybeIncorrect,
- );
- diag.span_help(
- inner_expr.span,
- "...and remove the `if let` statement in the for loop",
- );
- }
- );
- }
+ span_lint_and_then(
+ cx,
+ MANUAL_FLATTEN,
+ span,
+ &msg,
+ |diag| {
+ let sugg = format!("{}{}.flatten()", arg_snippet, copied);
+ diag.span_suggestion(
+ arg.span,
+ "try",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ diag.span_help(
+ inner_expr.span,
+ "...and remove the `if let` statement in the for loop",
+ );
+ }
+ );
}
}
}
}
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
- let stmts = block.stmts.iter().map(stmt_to_expr);
- let expr = once(block.expr);
- let mut iter = stmts.chain(expr).flatten();
+ let mut iter = block.stmts.iter().filter_map(stmt_to_expr).chain(block.expr);
never_loop_expr_seq(&mut iter, main_loop_id)
}
use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
use clippy_utils::{
can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id,
- peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
+ peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
};
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::Applicability;
// Checks for the `None` value.
fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
- match expr.kind {
- ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
- ExprKind::Block(
- Block {
- stmts: [],
- expr: Some(expr),
- ..
- },
- _,
- ) => is_none_expr(cx, expr),
- _ => false,
- }
+ matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
}
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
-use clippy_utils::remove_blocks;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::{is_trait_method, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
then {
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
match closure_body.params[0].pat.kind {
hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated, .., name, None
/// Anything else will return `a`.
fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String {
match &var_arg.kind {
- hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
+ hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace('.', "_"),
hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
_ => "a".to_string(),
}
use clippy_utils::visitors::is_local_used;
use clippy_utils::{
get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
- path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks,
+ path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
strip_pat_refs,
};
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
if args.len() == 1;
if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
- let body = remove_blocks(arms[0].body);
+ let body = peel_blocks(arms[0].body);
if path_to_local_id(body, arg);
then {
return;
}
let els = arms[1].body;
- let els = if is_unit_expr(remove_blocks(els)) {
+ let els = if is_unit_expr(peel_blocks(els)) {
None
} else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
let matched_vars = ex.span;
let bind_names = arms[0].pat.span;
- let match_body = remove_blocks(arms[0].body);
+ let match_body = peel_blocks(arms[0].body);
let mut snippet_body = if match_body.span.from_expansion() {
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
} else {
if is_lang_ctor(cx, qpath, OptionSome);
if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
- if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
+ if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
if let ExprKind::Path(ref some_path) = e.kind;
if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
use super::{contains_return, BIND_INSTEAD_OF_MAP};
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
-use clippy_utils::{remove_blocks, visitors::find_all_ret_expressions};
+use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
match arg.kind {
hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
true
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq};
+use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
},
hir::ExprKind::Closure(_, _, c, _, _) => {
let body = cx.tcx.hir().body(*c);
- let closure_expr = remove_blocks(&body.value);
+ let closure_expr = peel_blocks(&body.value);
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, args, _) => {
use super::ITER_CLONED_COLLECT;
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
if_chain! {
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec);
if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv));
cx,
ITER_CLONED_COLLECT,
to_replace,
- "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
- more readable",
+ &format!("called `iter().{}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
+ more readable", method_name),
"try",
".to_vec()".to_string(),
Applicability::MachineApplicable,
/// ```
#[clippy::version = "1.31.0"]
pub MAP_FLATTEN,
- pedantic,
+ complexity,
"using combinations of `flatten` and `map` which can usually be written as a single method call"
}
return;
}
let name = impl_item.ident.name.as_str();
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
("collect", []) => match method_call!(recv) {
- Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
+ Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+ iter_cloned_collect::check(cx, name, expr, recv2);
+ },
Some(("map", [m_recv, m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks};
+use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
}),
hir::ExprKind::Closure(_, _, body_id, _, _) => {
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
match &closure_expr.kind {
hir::ExprKind::MethodCall(_, _, args, _) => {
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
+use clippy_utils::sugg::deref_closure_args;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_trait_method, strip_pat_refs};
use if_chain::if_chain;
if search_snippet.lines().count() <= 1 {
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
+ let mut applicability = Applicability::MachineApplicable;
let any_search_snippet = if_chain! {
if search_method == "find";
if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind;
then {
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
Some(search_snippet.replacen('&', "", 1))
- } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(closure_arg.pat).kind {
- let name = &*ident.name.as_str();
- Some(search_snippet.replace(&format!("*{}", name), name))
+ } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
+ // `find()` provides a reference to the item, but `any` does not,
+ // so we should fix item usages for suggestion
+ if let Some(closure_sugg) = deref_closure_args(cx, search_arg) {
+ applicability = closure_sugg.applicability;
+ Some(closure_sugg.suggestion)
+ } else {
+ Some(search_snippet.to_string())
+ }
} else {
None
}
"any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
- Applicability::MachineApplicable,
+ applicability,
);
} else {
let iter = snippet(cx, search_recv.span, "..");
iter,
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
- Applicability::MachineApplicable,
+ applicability,
);
}
} else {
use super::SINGLE_CHAR_PATTERN;
-const PATTERN_METHODS: [(&str, usize); 19] = [
+const PATTERN_METHODS: [(&str, usize); 24] = [
("contains", 1),
("starts_with", 1),
("ends_with", 1),
("find", 1),
("rfind", 1),
("split", 1),
+ ("split_inclusive", 1),
("rsplit", 1),
("split_terminator", 1),
("rsplit_terminator", 1),
("splitn", 2),
("rsplitn", 2),
+ ("split_once", 1),
+ ("rsplit_once", 1),
("matches", 1),
("rmatches", 1),
("match_indices", 1),
("strip_suffix", 1),
("trim_start_matches", 1),
("trim_end_matches", 1),
+ ("replace", 1),
+ ("replacen", 1),
];
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs};
+use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs};
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
// Extract the body of the closure passed to fold
if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind;
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
// Check if the closure body is of the form `acc <op> some_expr(x)`
if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
// for regular string: "a"
&snip[1..(snip.len() - 1)]
};
- let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
+
+ let hint = format!("'{}'", match ch {
+ "'" => "\\'" ,
+ r"\" => "\\\\",
+ _ => ch,
+ });
+
Some(hint)
} else {
None
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_else_clause, is_expn_of};
+use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
+fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
+ let mut inner = e;
+ while let ExprKind::Binary(_, i, _)
+ | ExprKind::Call(i, _)
+ | ExprKind::Cast(i, _)
+ | ExprKind::Type(i, _)
+ | ExprKind::Index(i, _) = inner.kind
+ {
+ if matches!(
+ i.kind,
+ ExprKind::Block(..)
+ | ExprKind::ConstBlock(..)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ ) {
+ return true;
+ }
+ inner = i;
+ }
+ false
+}
+
+fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
+ matches!(
+ get_parent_node(cx.tcx, id),
+ Some(Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }))
+ )
+}
+
impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
use self::Expression::{Bool, RetBool};
snip = snip.blockify();
}
+ if condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id) {
+ snip = snip.maybe_par();
+ }
+
span_lint_and_sugg(
cx,
NEEDLESS_BOOL,
applicability,
);
};
- if let ExprKind::Block(then, _) = then.kind {
- match (fetch_bool_block(then), fetch_bool_expr(r#else)) {
+ if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(r#else)?))) {
+ match (a, b) {
(RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
span_lint(
cx,
(Bool(false), Bool(true)) => reduce(false, true),
_ => (),
}
- } else {
- panic!("IfExpr `then` node is not an `ExprKind::Block`");
}
}
}
right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
) {
- use self::Expression::{Bool, Other};
-
if let ExprKind::Binary(op, left_side, right_side) = e.kind {
let (l_ty, r_ty) = (
cx.typeck_results().expr_ty(left_side),
}
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
- (Bool(true), Other) => left_true.map_or((), |(h, m)| {
+ (Some(true), None) => left_true.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
- (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
+ (None, Some(true)) => right_true.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
- (Bool(false), Other) => left_false.map_or((), |(h, m)| {
+ (Some(false), None) => left_false.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
- (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
+ (None, Some(false)) => right_false.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
- (Other, Other) => no_literal.map_or((), |(h, m)| {
+ (None, None) => no_literal.map_or((), |(h, m)| {
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
span_lint_and_sugg(
enum Expression {
Bool(bool),
RetBool(bool),
- Other,
}
-fn fetch_bool_block(block: &Block<'_>) -> Expression {
- match (&*block.stmts, block.expr.as_ref()) {
- (&[], Some(e)) => fetch_bool_expr(&**e),
- (&[ref e], None) => {
- if let StmtKind::Semi(e) = e.kind {
- if let ExprKind::Ret(_) = e.kind {
- fetch_bool_expr(e)
- } else {
- Expression::Other
- }
- } else {
- Expression::Other
- }
- },
- _ => Expression::Other,
+fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
+ match peel_blocks_with_stmt(expr).kind {
+ ExprKind::Ret(Some(ret)) => Some(Expression::RetBool(fetch_bool_expr(ret)?)),
+ _ => Some(Expression::Bool(fetch_bool_expr(expr)?)),
}
}
-fn fetch_bool_expr(expr: &Expr<'_>) -> Expression {
- match expr.kind {
- ExprKind::Block(block, _) => fetch_bool_block(block),
- ExprKind::Lit(ref lit_ptr) => {
- if let LitKind::Bool(value) = lit_ptr.node {
- Expression::Bool(value)
- } else {
- Expression::Other
- }
- },
- ExprKind::Ret(Some(expr)) => match fetch_bool_expr(expr) {
- Expression::Bool(value) => Expression::RetBool(value),
- _ => Expression::Other,
- },
- _ => Expression::Other,
+fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
+ if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
+ if let LitKind::Bool(value) = lit_ptr.node {
+ return Some(value);
+ }
}
+ None
}
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::visitors::{expr_visitor, is_local_used};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for late initializations that can be replaced by a `let` statement
+ /// with an initializer.
+ ///
+ /// ### Why is this bad?
+ /// Assigning in the `let` statement is less repetitive.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let a;
+ /// a = 1;
+ ///
+ /// let b;
+ /// match 3 {
+ /// 0 => b = "zero",
+ /// 1 => b = "one",
+ /// _ => b = "many",
+ /// }
+ ///
+ /// let c;
+ /// if true {
+ /// c = 1;
+ /// } else {
+ /// c = -1;
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let a = 1;
+ ///
+ /// let b = match 3 {
+ /// 0 => "zero",
+ /// 1 => "one",
+ /// _ => "many",
+ /// };
+ ///
+ /// let c = if true {
+ /// 1
+ /// } else {
+ /// -1
+ /// };
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub NEEDLESS_LATE_INIT,
+ style,
+ "late initializations that can be replaced by a `let` statement with an initializer"
+}
+declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);
+
+fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool {
+ let mut seen = false;
+ expr_visitor(cx, |expr| {
+ if let ExprKind::Assign(..) = expr.kind {
+ seen = true;
+ }
+
+ !seen
+ })
+ .visit_stmt(stmt);
+
+ seen
+}
+
+#[derive(Debug)]
+struct LocalAssign {
+ lhs_id: HirId,
+ lhs_span: Span,
+ rhs_span: Span,
+ span: Span,
+}
+
+impl LocalAssign {
+ fn from_expr(expr: &Expr<'_>, span: Span) -> Option<Self> {
+ if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
+ if lhs.span.from_expansion() {
+ return None;
+ }
+
+ Some(Self {
+ lhs_id: path_to_local(lhs)?,
+ lhs_span: lhs.span,
+ rhs_span: rhs.span.source_callsite(),
+ span,
+ })
+ } else {
+ None
+ }
+ }
+
+ fn new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, binding_id: HirId) -> Option<LocalAssign> {
+ let assign = match expr.kind {
+ ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span),
+ ExprKind::Block(block, _) => {
+ if_chain! {
+ if let Some((last, other_stmts)) = block.stmts.split_last();
+ if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind;
+
+ let assign = Self::from_expr(expr, last.span)?;
+
+ // avoid visiting if not needed
+ if assign.lhs_id == binding_id;
+ if other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt));
+
+ then {
+ Some(assign)
+ } else {
+ None
+ }
+ }
+ },
+ ExprKind::Assign(..) => Self::from_expr(expr, expr.span),
+ _ => None,
+ }?;
+
+ if assign.lhs_id == binding_id {
+ Some(assign)
+ } else {
+ None
+ }
+ }
+}
+
+fn assignment_suggestions<'tcx>(
+ cx: &LateContext<'tcx>,
+ binding_id: HirId,
+ exprs: impl IntoIterator<Item = &'tcx Expr<'tcx>>,
+) -> Option<(Applicability, Vec<(Span, String)>)> {
+ let mut assignments = Vec::new();
+
+ for expr in exprs {
+ let ty = cx.typeck_results().expr_ty(expr);
+
+ if ty.is_never() {
+ continue;
+ }
+ if !ty.is_unit() {
+ return None;
+ }
+
+ let assign = LocalAssign::new(cx, expr, binding_id)?;
+
+ assignments.push(assign);
+ }
+
+ let suggestions = assignments
+ .into_iter()
+ .map(|assignment| Some((assignment.span, snippet_opt(cx, assignment.rhs_span)?)))
+ .collect::<Option<Vec<(Span, String)>>>()?;
+
+ let applicability = if suggestions.len() > 1 {
+ // multiple suggestions don't work with rustfix in multipart_suggest
+ // https://github.com/rust-lang/rustfix/issues/141
+ Applicability::Unspecified
+ } else {
+ Applicability::MachineApplicable
+ };
+ Some((applicability, suggestions))
+}
+
+struct Usage<'tcx> {
+ stmt: &'tcx Stmt<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ needs_semi: bool,
+}
+
+fn first_usage<'tcx>(
+ cx: &LateContext<'tcx>,
+ binding_id: HirId,
+ local_stmt_id: HirId,
+ block: &'tcx Block<'tcx>,
+) -> Option<Usage<'tcx>> {
+ block
+ .stmts
+ .iter()
+ .skip_while(|stmt| stmt.hir_id != local_stmt_id)
+ .skip(1)
+ .find(|&stmt| is_local_used(cx, stmt, binding_id))
+ .and_then(|stmt| match stmt.kind {
+ StmtKind::Expr(expr) => Some(Usage {
+ stmt,
+ expr,
+ needs_semi: true,
+ }),
+ StmtKind::Semi(expr) => Some(Usage {
+ stmt,
+ expr,
+ needs_semi: false,
+ }),
+ _ => None,
+ })
+}
+
+fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> Option<String> {
+ let span = local.span.with_hi(match local.ty {
+ // let <pat>: <ty>;
+ // ~~~~~~~~~~~~~~~
+ Some(ty) => ty.span.hi(),
+ // let <pat>;
+ // ~~~~~~~~~
+ None => local.pat.span.hi(),
+ });
+
+ snippet_opt(cx, span)
+}
+
+fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ local: &'tcx Local<'tcx>,
+ local_stmt: &'tcx Stmt<'tcx>,
+ block: &'tcx Block<'tcx>,
+ binding_id: HirId,
+) -> Option<()> {
+ let usage = first_usage(cx, binding_id, local_stmt.hir_id, block)?;
+ let binding_name = cx.tcx.hir().opt_name(binding_id)?;
+ let let_snippet = local_snippet_without_semicolon(cx, local)?;
+
+ match usage.expr.kind {
+ ExprKind::Assign(..) => {
+ let assign = LocalAssign::new(cx, usage.expr, binding_id)?;
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_LATE_INIT,
+ local_stmt.span,
+ "unneeded late initalization",
+ |diag| {
+ diag.tool_only_span_suggestion(
+ local_stmt.span,
+ "remove the local",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+
+ diag.span_suggestion(
+ assign.lhs_span,
+ &format!("declare `{}` here", binding_name),
+ let_snippet,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ },
+ ExprKind::If(_, then_expr, Some(else_expr)) => {
+ let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_LATE_INIT,
+ local_stmt.span,
+ "unneeded late initalization",
+ |diag| {
+ diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
+
+ diag.span_suggestion_verbose(
+ usage.stmt.span.shrink_to_lo(),
+ &format!("declare `{}` here", binding_name),
+ format!("{} = ", let_snippet),
+ applicability,
+ );
+
+ diag.multipart_suggestion("remove the assignments from the branches", suggestions, applicability);
+
+ if usage.needs_semi {
+ diag.span_suggestion(
+ usage.stmt.span.shrink_to_hi(),
+ "add a semicolon after the `if` expression",
+ ";".to_string(),
+ applicability,
+ );
+ }
+ },
+ );
+ },
+ ExprKind::Match(_, arms, MatchSource::Normal) => {
+ let (applicability, suggestions) = assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_LATE_INIT,
+ local_stmt.span,
+ "unneeded late initalization",
+ |diag| {
+ diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
+
+ diag.span_suggestion_verbose(
+ usage.stmt.span.shrink_to_lo(),
+ &format!("declare `{}` here", binding_name),
+ format!("{} = ", let_snippet),
+ applicability,
+ );
+
+ diag.multipart_suggestion(
+ "remove the assignments from the `match` arms",
+ suggestions,
+ applicability,
+ );
+
+ if usage.needs_semi {
+ diag.span_suggestion(
+ usage.stmt.span.shrink_to_hi(),
+ "add a semicolon after the `match` expression",
+ ";".to_string(),
+ applicability,
+ );
+ }
+ },
+ );
+ },
+ _ => {},
+ };
+
+ Some(())
+}
+
+impl LateLintPass<'tcx> for NeedlessLateInit {
+ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+ let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
+
+ if_chain! {
+ if let Local {
+ init: None,
+ pat: &Pat {
+ kind: PatKind::Binding(_, binding_id, _, None),
+ ..
+ },
+ source: LocalSource::Normal,
+ ..
+ } = local;
+ if let Some((_, Node::Stmt(local_stmt))) = parents.next();
+ if let Some((_, Node::Block(block))) = parents.next();
+
+ then {
+ check(cx, local, local_stmt, block, binding_id);
+ }
+ }
+ }
+}
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::is_lint_allowed;
+use clippy_utils::peel_blocks;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
if expr.span.from_expansion() {
return false;
}
- match expr.kind {
+ match peel_blocks(expr).kind {
ExprKind::Lit(..) | ExprKind::Closure(..) => true,
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
false
}
},
- ExprKind::Block(block, _) => {
- block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| has_no_effect(cx, expr))
- },
_ => false,
}
}
if !&reduced.iter().any(|e| e.span.from_expansion());
then {
if let ExprKind::Index(..) = &expr.kind {
- let snippet;
- if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
- snippet = format!("assert!({}.len() > {});", &arr, &func);
+ let snippet = if let (Some(arr), Some(func)) =
+ (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span))
+ {
+ format!("assert!({}.len() > {});", &arr, &func)
} else {
return;
- }
+ };
span_lint_hir_and_then(
cx,
UNNECESSARY_OPERATION,
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
- let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id());
- let item = cx.tcx.hir().expect_item(item_hir_id);
+ let item_def_id = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+ let item = cx.tcx.hir().expect_item(item_def_id);
match &item.kind {
ItemKind::Impl(Impl {
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_lint_allowed;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
+use clippy_utils::{is_lint_allowed, match_def_path, paths};
use rustc_ast::ImplPolarity;
use rustc_hir::def_id::DefId;
use rustc_hir::{FieldDef, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
- /// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`.
+ /// This lint warns about a `Send` implementation for a type that
+ /// contains fields that are not safe to be sent across threads.
+ /// It tries to detect fields that can cause a soundness issue
+ /// when sent to another thread (e.g., `Rc`) while allowing `!Send` fields
+ /// that are expected to exist in a `Send` type, such as raw pointers.
///
/// ### Why is this bad?
- /// Sending the struct to another thread will transfer the ownership to
- /// the new thread by dropping in the current thread during the transfer.
- /// This causes soundness issues for non-`Send` fields, as they are also
- /// dropped and might not be set up to handle this.
+ /// Sending the struct to another thread effectively sends all of its fields,
+ /// and the fields that do not implement `Send` can lead to soundness bugs
+ /// such as data races when accessed in a thread
+ /// that is different from the thread that created it.
///
/// See:
/// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
/// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
///
/// ### Known Problems
- /// Data structures that contain raw pointers may cause false positives.
- /// They are sometimes safe to be sent across threads but do not implement
- /// the `Send` trait. This lint has a heuristic to filter out basic cases
- /// such as `Vec<*const T>`, but it's not perfect. Feel free to create an
- /// issue if you have a suggestion on how this heuristic can be improved.
+ /// This lint relies on heuristics to distinguish types that are actually
+ /// unsafe to be sent across threads and `!Send` types that are expected to
+ /// exist in `Send` type. Its rule can filter out basic cases such as
+ /// `Vec<*const T>`, but it's not perfect. Feel free to create an issue if
+ /// you have a suggestion on how this heuristic can be improved.
///
/// ### Example
/// ```rust,ignore
/// or specify correct bounds on generic type parameters (`T: Send`).
#[clippy::version = "1.57.0"]
pub NON_SEND_FIELDS_IN_SEND_TY,
- suspicious,
- "there is field that does not implement `Send` in a `Send` struct"
+ nursery,
+ "there is a field that is not safe to be sent to another thread in a `Send` struct"
}
#[derive(Copy, Clone)]
// single `AdtDef` may have multiple `Send` impls due to generic
// parameters, and the lint is much easier to implement in this way.
if_chain! {
+ if !in_external_macro(cx.tcx.sess, item.span);
if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send);
if let ItemKind::Impl(hir_impl) = &item.kind;
if let Some(trait_ref) = &hir_impl.of_trait;
NON_SEND_FIELDS_IN_SEND_TY,
item.span,
&format!(
- "this implementation is unsound, as some fields in `{}` are `!Send`",
+ "some fields in `{}` are not safe to be sent to another thread",
snippet(cx, hir_impl.self_ty.span, "Unknown")
),
|diag| {
for field in non_send_fields {
diag.span_note(
field.def.span,
- &format!("the type of field `{}` is `!Send`", field.def.ident.name),
+ &format!("it is not safe to send field `{}` to another thread", field.def.ident.name),
);
match field.generic_params.len() {
return true;
}
- if is_copy(cx, ty) && !contains_raw_pointer(cx, ty) {
+ if is_copy(cx, ty) && !contains_pointer_like(cx, ty) {
return true;
}
.all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
ty::Adt(_, substs) => {
- if contains_raw_pointer(cx, ty) {
+ if contains_pointer_like(cx, ty) {
// descends only if ADT contains any raw pointers
substs.iter().all(|generic_arg| match generic_arg.unpack() {
GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
}
}
-/// Checks if the type contains any raw pointers in substs (including nested ones).
-fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
+/// Checks if the type contains any pointer-like types in substs (including nested ones)
+fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
for ty_node in target_ty.walk(cx.tcx) {
- if_chain! {
- if let GenericArgKind::Type(inner_ty) = ty_node.unpack();
- if let ty::RawPtr(_) = inner_ty.kind();
- then {
- return true;
+ if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
+ match inner_ty.kind() {
+ ty::RawPtr(_) => {
+ return true;
+ },
+ ty::Adt(adt_def, _) => {
+ if match_def_path(cx, adt_def.did, &paths::PTR_NON_NULL) {
+ return true;
+ }
+ },
+ _ => (),
}
}
}
if snip.starts_with(&format!("{}!", name));
if unnested_or_local();
// make formatting consistent
- let c = snip.replace(" ", "");
+ let c = snip.replace(' ', "");
if !c.starts_with(&format!("{}!{}", name, braces.0));
if !mac_braces.done.contains(&span.ctxt().outer_expn_data().call_site);
then {
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
- can_move_expr_to_closure, eager_or_lazy, in_constant, is_else_clause, is_lang_ctor, peel_hir_expr_while,
- CaptureKind,
+ can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
+ peel_hir_expr_while, CaptureKind,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionSome;
-use rustc_hir::{def::Res, BindingAnnotation, Block, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
+use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
none_expr: String,
}
-/// Extracts the body of a given arm. If the arm contains only an expression,
-/// then it returns the expression. Otherwise, it returns the entire block
-fn extract_body_from_expr<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
- if let ExprKind::Block(
- Block {
- stmts: block_stmts,
- expr: Some(block_expr),
- ..
- },
- _,
- ) = expr.kind
- {
- if let [] = block_stmts {
- Some(block_expr)
- } else {
- Some(expr)
- }
- } else {
- None
- }
-}
-
fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
format!(
"{}{}",
if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
if is_lang_ctor(cx, struct_qpath, OptionSome);
- if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
+ if let PatKind::Binding(bind_annotation, _, id, None) = &inner_pat.kind;
if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
if some_captures
then {
let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
- let some_body = extract_body_from_expr(if_then)?;
- let none_body = extract_body_from_expr(if_else)?;
+ let some_body = peel_blocks(if_then);
+ let none_body = peel_blocks(if_else);
let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
let capture_name = id.name.to_ident_string();
let (as_ref, as_mut) = match &let_expr.kind {
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
-use clippy_utils::is_lang_ctor;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
+use clippy_utils::{eq_expr_value, is_lang_ctor, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
let mut replacement: Option<String> = None;
if let Some(else_inner) = r#else {
- if_chain! {
- if let ExprKind::Block(block, None) = &else_inner.kind;
- if block.stmts.is_empty();
- if let Some(block_expr) = &block.expr;
- if eq_expr_value(cx, subject, block_expr);
- then {
- replacement = Some(format!("Some({}?)", receiver_str));
- }
+ if eq_expr_value(cx, subject, peel_blocks(else_inner)) {
+ replacement = Some(format!("Some({}?)", receiver_str));
}
} else if Self::moves_by_default(cx, subject)
&& !matches!(subject.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
- if let ExprKind::Block(block, None) = if_then.kind;
- if block.stmts.is_empty();
- if let Some(trailing_expr) = &block.expr;
- if path_to_local_id(trailing_expr, bind_id);
+ if path_to_local_id(peel_blocks(if_then), bind_id);
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
}
fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
- match expression.kind {
- ExprKind::Block(block, _) => {
- if let Some(return_expression) = Self::return_expression(block) {
- return Self::expression_returns_none(cx, return_expression);
- }
-
- false
- },
+ match peel_blocks_with_stmt(expression).kind {
ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr),
ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
_ => false,
}
fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
- match expr.kind {
- ExprKind::Block(block, _) => {
- if let Some(return_expression) = Self::return_expression(block) {
- return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
- }
-
- false
- },
+ match peel_blocks_with_stmt(expr).kind {
ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
- ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
+ ExprKind::Path(_) => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr),
_ => false,
}
}
-
- fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- // Check if last expression is a return statement. Then, return the expression
- if_chain! {
- if block.stmts.len() == 1;
- if let Some(expr) = block.stmts.iter().last();
- if let StmtKind::Semi(expr) = expr.kind;
- if let ExprKind::Ret(Some(ret_expr)) = expr.kind;
-
- then {
- return Some(ret_expr);
- }
- }
-
- // Check for `return` without a semicolon.
- if_chain! {
- if block.stmts.is_empty();
- if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.kind);
- then {
- return Some(ret_expr);
- }
- }
-
- None
- }
}
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
declare_clippy_lint! {
/// ### What it does
- /// It lints if a struct has two method with same time:
+ /// It lints if a struct has two methods with the same name:
/// one from a trait, another not from trait.
///
/// ### Why is this bad?
cx,
SAME_NAME_METHOD,
*impl_span,
- "method's name is same to an existing method in a trait",
+ "method's name is the same as an existing method in a trait",
|diag| {
diag.span_note(
trait_method_span,
cx,
SAME_NAME_METHOD,
impl_span,
- "method's name is same to an existing method in a trait",
+ "method's name is the same as an existing method in a trait",
|diag| {
// TODO should we `span_note` on every trait?
// iterate on trait_spans?
_ => return,
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
let ret_ty = return_ty(cx, impl_item.hir_id());
let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
let type_name = x.ident.name.as_str().to_lowercase();
- if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace("_", "") == type_name;
+ if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name;
then {
span_lint(
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::SpanlessEq;
use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
+use clippy_utils::{peel_blocks, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
}
fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
- match src.kind {
+ match peel_blocks(src).kind {
ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
left,
_,
) => SpanlessEq::new(cx).eq_expr(target, left),
- ExprKind::Block(block, _) => {
- block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
- },
_ => false,
}
}
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::paths;
-use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_ref_to_diagnostic_item};
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::is_expr_unsafe;
+use clippy_utils::{get_parent_node, match_libc_symbol};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
impl LateLintPass<'tcx> for StrlenOnCStrings {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if expr.span.from_expansion() {
- return;
- }
-
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if let hir::ExprKind::Call(func, [recv]) = expr.kind;
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = func.kind;
-
- if (&paths::LIBC_STRLEN).iter().map(|x| Symbol::intern(x)).eq(
- path.segments.iter().map(|seg| seg.ident.name));
- if let hir::ExprKind::MethodCall(path, _, args, _) = recv.kind;
- if args.len() == 1;
- if !args.iter().any(|e| e.span.from_expansion());
+ if !expr.span.from_expansion();
+ if let ExprKind::Call(func, [recv]) = expr.kind;
+ if let ExprKind::Path(path) = &func.kind;
+ if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
+ if match_libc_symbol(cx, did, "strlen");
+ if let ExprKind::MethodCall(path, _, [self_arg], _) = recv.kind;
+ if !recv.span.from_expansion();
if path.ident.name == sym::as_ptr;
then {
- let cstring = &args[0];
- let ty = cx.typeck_results().expr_ty(cstring);
- let val_name = snippet_with_macro_callsite(cx, cstring.span, "..");
- let sugg = if is_type_diagnostic_item(cx, ty, sym::cstring_type){
- format!("{}.as_bytes().len()", val_name)
- } else if is_type_ref_to_diagnostic_item(cx, ty, sym::CStr){
- format!("{}.to_bytes().len()", val_name)
+ let ctxt = expr.span.ctxt();
+ let span = match get_parent_node(cx.tcx, expr.hir_id) {
+ Some(Node::Block(&Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), span, ..
+ }))
+ if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => {
+ span
+ }
+ _ => expr.span,
+ };
+
+ let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+ let mut app = Applicability::MachineApplicable;
+ let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
+ let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
+ "as_bytes"
+ } else if is_type_diagnostic_item(cx, ty, sym::CStr) {
+ "to_bytes"
} else {
return;
};
span_lint_and_sugg(
cx,
STRLEN_ON_C_STRINGS,
- expr.span,
+ span,
"using `libc::strlen` on a `CString` or `CStr` value",
- "try this (you might also need to get rid of `unsafe` block in some cases):",
- sugg,
- Applicability::Unspecified // Sometimes unnecessary `unsafe` block
+ "try this",
+ format!("{}.{}().len()", val_name, method_name),
+ app,
);
}
}
declare_clippy_lint! {
/// ### What it does
- /// Checks for non-ASCII characters in string literals.
+ /// Checks for non-ASCII characters in string and char literals.
///
/// ### Why is this bad?
/// Yeah, we know, the 90's called and wanted their charset
impl LateLintPass<'_> for Unicode {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Lit(ref lit) = expr.kind {
- if let LitKind::Str(_, _) = lit.node {
+ if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
check_str(cx, lit.span, expr.hir_id);
}
}
"invisible character detected",
"consider replacing the string with",
string
- .replace("\u{200B}", "\\u{200B}")
- .replace("\u{ad}", "\\u{AD}")
- .replace("\u{2060}", "\\u{2060}"),
+ .replace('\u{200B}', "\\u{200B}")
+ .replace('\u{ad}', "\\u{AD}")
+ .replace('\u{2060}', "\\u{2060}"),
Applicability::MachineApplicable,
);
}
if impl_item.span.from_expansion() {
return;
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let parent_item = cx.tcx.hir().expect_item(parent);
let assoc_item = cx.tcx.associated_item(impl_item.def_id);
if_chain! {
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::higher;
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
use clippy_utils::{
- is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls, path_to_res,
- paths, SpanlessEq,
+ higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls,
+ path_to_res, paths, peel_blocks_with_stmt, SpanlessEq,
};
use if_chain::if_chain;
use rustc_ast as ast;
if and_then_args.len() == 5;
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
let body = cx.tcx.hir().body(*body_id);
- if let ExprKind::Block(block, _) = &body.value.kind;
- let stmts = &block.stmts;
- if stmts.len() == 1 && block.expr.is_none();
- if let StmtKind::Semi(only_expr) = &stmts[0].kind;
+ let only_expr = peel_blocks_with_stmt(&body.value);
if let ExprKind::MethodCall(ps, _, span_call_args, _) = &only_expr.kind;
then {
let and_then_snippets = get_and_then_snippets(cx, and_then_args);
//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
//! a simple mistake)
+use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
+use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
use if_chain::if_chain;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use std::io::prelude::*;
use std::path::Path;
-use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
-use clippy_utils::{
- diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type,
- ty::walk_ptrs_ty_depth,
-};
-
/// This is the output file of the lint collector.
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
/// These lints are excluded from the export.
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
- /// Only catches `print!` and `println!` calls.
+ /// * Only catches `print!` and `println!` calls.
+ /// * The lint level is unaffected by crate attributes. The level can still
+ /// be set for functions, modules and other items. To change the level for
+ /// the entire crate, please use command line flags. More information and a
+ /// configuration example can be found in [clippy#6610].
+ ///
+ /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
///
/// ### Example
/// ```rust
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
- /// Only catches `eprint!` and `eprintln!` calls.
+ /// * Only catches `eprint!` and `eprintln!` calls.
+ /// * The lint level is unaffected by crate attributes. The level can still
+ /// be set for functions, modules and other items. To change the level for
+ /// the entire crate, please use command line flags. More information and a
+ /// configuration example can be found in [clippy#6610].
+ ///
+ /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
///
/// ### Example
/// ```rust
let replacement: String = match lit.token.kind {
LitKind::Integer | LitKind::Float | LitKind::Err => continue,
LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => {
- lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}")
+ lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
},
LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => {
- lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}")
+ lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
},
LitKind::StrRaw(_) | LitKind::Str | LitKind::ByteStrRaw(_) | LitKind::ByteStr => continue,
LitKind::Byte | LitKind::Char => match &*lit.token.symbol.as_str() {
[package]
name = "clippy_utils"
-version = "0.1.58"
+version = "0.1.59"
edition = "2021"
publish = false
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
use rustc_hir::{
- def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs,
- HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
- Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
- UnOp,
+ def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
+ ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
+ MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem,
+ TraitItemKind, TraitRef, TyKind, UnOp,
};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::exports::Export;
}
}
+/// Removes blocks around an expression, only if the block contains just one expression
+/// and no statements. Unsafe blocks are not removed.
+///
+/// Examples:
+/// * `{}` -> `{}`
+/// * `{ x }` -> `x`
+/// * `{{ x }}` -> `x`
+/// * `{ x; }` -> `{ x; }`
+/// * `{ x; y }` -> `{ x; y }`
+/// * `{ unsafe { x } }` -> `unsafe { x }`
+pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
+ while let ExprKind::Block(
+ Block {
+ stmts: [],
+ expr: Some(inner),
+ rules: BlockCheckMode::DefaultBlock,
+ ..
+ },
+ _,
+ ) = expr.kind
+ {
+ expr = inner;
+ }
+ expr
+}
+
+/// Removes blocks around an expression, only if the block contains just one expression
+/// or just one expression statement with a semicolon. Unsafe blocks are not removed.
+///
+/// Examples:
+/// * `{}` -> `{}`
+/// * `{ x }` -> `x`
+/// * `{ x; }` -> `x`
+/// * `{{ x; }}` -> `x`
+/// * `{ x; y }` -> `{ x; y }`
+/// * `{ unsafe { x } }` -> `unsafe { x }`
+pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
+ while let ExprKind::Block(
+ Block {
+ stmts: [],
+ expr: Some(inner),
+ rules: BlockCheckMode::DefaultBlock,
+ ..
+ }
+ | Block {
+ stmts:
+ [
+ Stmt {
+ kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
+ ..
+ },
+ ],
+ expr: None,
+ rules: BlockCheckMode::DefaultBlock,
+ ..
+ },
+ _,
+ ) = expr.kind
+ {
+ expr = inner;
+ }
+ expr
+}
+
/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
let mut iter = tcx.hir().parent_iter(expr.hir_id);
has_attr(attrs, sym::automatically_derived)
}
-/// Remove blocks around an expression.
-///
-/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
-/// themselves.
-pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
- while let ExprKind::Block(block, ..) = expr.kind {
- match (block.stmts.is_empty(), block.expr.as_ref()) {
- (true, Some(e)) => expr = e,
- _ => break,
- }
- }
- expr
-}
-
pub fn is_self(slf: &Param<'_>) -> bool {
if let PatKind::Binding(.., name, _) = slf.pat.kind {
name.name == kw::SelfLower
syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
}
+/// Checks if the given `DefId` matches the `libc` item.
+pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
+ let path = cx.get_def_path(did);
+ // libc is meant to be used as a flat list of names, but they're all actually defined in different
+ // modules based on the target platform. Ignore everything but crate name and the item name.
+ path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
+}
+
pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(func, [arg]) = expr.kind {
expr_path_res(cx, func)
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
#[cfg(feature = "internal-lints")]
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
-pub const LIBC_STRLEN: [&str; 2] = ["libc", "strlen"];
#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"];
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"];
+pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
//! Contains utility functions to generate suggestions.
#![deny(clippy::missing_docs_in_private_items)]
-use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
+use crate::source::{
+ snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
+};
+use crate::{get_parent_expr_for_hir, higher};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{ast, token};
use rustc_ast_pretty::pprust::token_kind_to_string;
use rustc_errors::Applicability;
use rustc_hir as hir;
+use rustc_hir::{ExprKind, HirId, MutTy, TyKind};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{EarlyContext, LateContext, LintContext};
-use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos, SyntaxContext};
+use rustc_middle::hir::place::ProjectionKind;
+use rustc_middle::mir::{FakeReadCause, Mutability};
+use rustc_middle::ty;
+use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
+use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use std::borrow::Cow;
use std::convert::TryInto;
use std::fmt::Display;
+use std::iter;
use std::ops::{Add, Neg, Not, Sub};
/// A helper type to build suggestion correctly handling parentheses.
}
}
+/// Suggestion results for handling closure
+/// args dereferencing and borrowing
+pub struct DerefClosure {
+ /// confidence on the built suggestion
+ pub applicability: Applicability,
+ /// gradually built suggestion
+ pub suggestion: String,
+}
+
+/// Build suggestion gradually by handling closure arg specific usages,
+/// such as explicit deref and borrowing cases.
+/// Returns `None` if no such use cases have been triggered in closure body
+///
+/// note: this only works on single line immutable closures with exactly one input parameter.
+pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> {
+ if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = closure.kind {
+ let closure_body = cx.tcx.hir().body(body_id);
+ // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
+ // a type annotation is present if param `kind` is different from `TyKind::Infer`
+ let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
+ {
+ matches!(ty.kind, TyKind::Rptr(_, MutTy { .. }))
+ } else {
+ false
+ };
+
+ let mut visitor = DerefDelegate {
+ cx,
+ closure_span: closure.span,
+ closure_arg_is_type_annotated_double_ref,
+ next_pos: closure.span.lo(),
+ suggestion_start: String::new(),
+ applicability: Applicability::MaybeIncorrect,
+ };
+
+ let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
+ cx.tcx.infer_ctxt().enter(|infcx| {
+ ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
+ .consume_body(closure_body);
+ });
+
+ if !visitor.suggestion_start.is_empty() {
+ return Some(DerefClosure {
+ applicability: visitor.applicability,
+ suggestion: visitor.finish(),
+ });
+ }
+ }
+ None
+}
+
+/// Visitor struct used for tracking down
+/// dereferencing and borrowing of closure's args
+struct DerefDelegate<'a, 'tcx> {
+ /// The late context of the lint
+ cx: &'a LateContext<'tcx>,
+ /// The span of the input closure to adapt
+ closure_span: Span,
+ /// Indicates if the arg of the closure is a type annotated double reference
+ closure_arg_is_type_annotated_double_ref: bool,
+ /// last position of the span to gradually build the suggestion
+ next_pos: BytePos,
+ /// starting part of the gradually built suggestion
+ suggestion_start: String,
+ /// confidence on the built suggestion
+ applicability: Applicability,
+}
+
+impl DerefDelegate<'_, 'tcx> {
+ /// build final suggestion:
+ /// - create the ending part of suggestion
+ /// - concatenate starting and ending parts
+ /// - potentially remove needless borrowing
+ pub fn finish(&mut self) -> String {
+ let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None);
+ let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability);
+ let sugg = format!("{}{}", self.suggestion_start, end_snip);
+ if self.closure_arg_is_type_annotated_double_ref {
+ sugg.replacen('&', "", 1)
+ } else {
+ sugg
+ }
+ }
+
+ /// indicates whether the function from `parent_expr` takes its args by double reference
+ fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
+ let (call_args, inputs) = match parent_expr.kind {
+ ExprKind::MethodCall(_, _, call_args, _) => {
+ if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) {
+ (call_args, self.cx.tcx.fn_sig(method_did).skip_binder().inputs())
+ } else {
+ return false;
+ }
+ },
+ ExprKind::Call(func, call_args) => {
+ let typ = self.cx.typeck_results().expr_ty(func);
+ (call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs())
+ },
+ _ => return false,
+ };
+
+ iter::zip(call_args, inputs)
+ .any(|(arg, ty)| arg.hir_id == cmt_hir_id && matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()))
+ }
+}
+
+impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
+ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
+ #[allow(clippy::too_many_lines)]
+ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
+ if let PlaceBase::Local(id) = cmt.place.base {
+ let map = self.cx.tcx.hir();
+ let span = map.span(cmt.hir_id);
+ let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None);
+ let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
+
+ // identifier referring to the variable currently triggered (i.e.: `fp`)
+ let ident_str = map.name(id).to_string();
+ // full identifier that includes projection (i.e.: `fp.field`)
+ let ident_str_with_proj = snippet(self.cx, span, "..").to_string();
+
+ if cmt.place.projections.is_empty() {
+ // handle item without any projection, that needs an explicit borrowing
+ // i.e.: suggest `&x` instead of `x`
+ self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str));
+ } else {
+ // cases where a parent `Call` or `MethodCall` is using the item
+ // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
+ //
+ // Note about method calls:
+ // - compiler automatically dereference references if the target type is a reference (works also for
+ // function call)
+ // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and
+ // no projection should be suggested
+ if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) {
+ match &parent_expr.kind {
+ // given expression is the self argument and will be handled completely by the compiler
+ // i.e.: `|x| x.is_something()`
+ ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
+ self.suggestion_start
+ .push_str(&format!("{}{}", start_snip, ident_str_with_proj));
+ self.next_pos = span.hi();
+ return;
+ },
+ // item is used in a call
+ // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
+ ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [_, call_args @ ..], _) => {
+ let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
+ let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
+
+ if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) {
+ // suggest ampersand if call function is taking args by double reference
+ let takes_arg_by_double_ref =
+ self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id);
+
+ // compiler will automatically dereference field or index projection, so no need
+ // to suggest ampersand, but full identifier that includes projection is required
+ let has_field_or_index_projection =
+ cmt.place.projections.iter().any(|proj| {
+ matches!(proj.kind, ProjectionKind::Field(..) | ProjectionKind::Index)
+ });
+
+ // no need to bind again if the function doesn't take arg by double ref
+ // and if the item is already a double ref
+ let ident_sugg = if !call_args.is_empty()
+ && !takes_arg_by_double_ref
+ && (self.closure_arg_is_type_annotated_double_ref || has_field_or_index_projection)
+ {
+ let ident = if has_field_or_index_projection {
+ ident_str_with_proj
+ } else {
+ ident_str
+ };
+ format!("{}{}", start_snip, ident)
+ } else {
+ format!("{}&{}", start_snip, ident_str)
+ };
+ self.suggestion_start.push_str(&ident_sugg);
+ self.next_pos = span.hi();
+ return;
+ }
+
+ self.applicability = Applicability::Unspecified;
+ },
+ _ => (),
+ }
+ }
+
+ let mut replacement_str = ident_str;
+ let mut projections_handled = false;
+ cmt.place.projections.iter().enumerate().for_each(|(i, proj)| {
+ match proj.kind {
+ // Field projection like `|v| v.foo`
+ // no adjustment needed here, as field projections are handled by the compiler
+ ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() {
+ ty::Adt(..) | ty::Tuple(_) => {
+ replacement_str = ident_str_with_proj.clone();
+ projections_handled = true;
+ },
+ _ => (),
+ },
+ // Index projection like `|x| foo[x]`
+ // the index is dropped so we can't get it to build the suggestion,
+ // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`)
+ // instead of `span.lo()` (i.e.: `foo`)
+ ProjectionKind::Index => {
+ let start_span = Span::new(self.next_pos, span.hi(), span.ctxt(), None);
+ start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
+ replacement_str.clear();
+ projections_handled = true;
+ },
+ // note: unable to trigger `Subslice` kind in tests
+ ProjectionKind::Subslice => (),
+ ProjectionKind::Deref => {
+ // Explicit derefs are typically handled later on, but
+ // some items do not need explicit deref, such as array accesses,
+ // so we mark them as already processed
+ // i.e.: don't suggest `*sub[1..4].len()` for `|sub| sub[1..4].len() == 3`
+ if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() {
+ if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) {
+ projections_handled = true;
+ }
+ }
+ },
+ }
+ });
+
+ // handle `ProjectionKind::Deref` by removing one explicit deref
+ // if no special case was detected (i.e.: suggest `*x` instead of `**x`)
+ if !projections_handled {
+ let last_deref = cmt
+ .place
+ .projections
+ .iter()
+ .rposition(|proj| proj.kind == ProjectionKind::Deref);
+
+ if let Some(pos) = last_deref {
+ let mut projections = cmt.place.projections.clone();
+ projections.truncate(pos);
+
+ for item in projections {
+ if item.kind == ProjectionKind::Deref {
+ replacement_str = format!("*{}", replacement_str);
+ }
+ }
+ }
+ }
+
+ self.suggestion_start
+ .push_str(&format!("{}{}", start_snip, replacement_str));
+ }
+ self.next_pos = span.hi();
+ }
+ }
+
+ fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
+ fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
+}
+
#[cfg(test)]
mod test {
use super::Sugg;
use crate::path_to_local_id;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Arm, Block, Body, BodyId, Expr, ExprKind, HirId, Stmt, UnOp};
+use rustc_hir::intravisit::{self, walk_block, walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{
+ Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Stmt, UnOp, Unsafety,
+};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
v.visit_expr(e);
v.is_const
}
+
+/// Checks if the given expression performs an unsafe operation outside of an unsafe block.
+pub fn is_expr_unsafe(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
+ struct V<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ is_unsafe: bool,
+ }
+ impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
+ type Map = Map<'tcx>;
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+ }
+ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+ if self.is_unsafe {
+ return;
+ }
+ match e.kind {
+ ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => {
+ self.is_unsafe = true;
+ },
+ ExprKind::MethodCall(..)
+ if self
+ .cx
+ .typeck_results()
+ .type_dependent_def_id(e.hir_id)
+ .map_or(false, |id| self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe) =>
+ {
+ self.is_unsafe = true;
+ },
+ ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
+ ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+ ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+ _ => walk_expr(self, e),
+ },
+ ExprKind::Path(ref p)
+ if self
+ .cx
+ .qpath_res(p, e.hir_id)
+ .opt_def_id()
+ .map_or(false, |id| self.cx.tcx.is_mutable_static(id)) =>
+ {
+ self.is_unsafe = true;
+ },
+ _ => walk_expr(self, e),
+ }
+ }
+ fn visit_block(&mut self, b: &'tcx Block<'_>) {
+ if !matches!(b.rules, BlockCheckMode::UnsafeBlock(_)) {
+ walk_block(self, b);
+ }
+ }
+ fn visit_nested_item(&mut self, id: ItemId) {
+ if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind {
+ self.is_unsafe = i.unsafety == Unsafety::Unsafe;
+ }
+ }
+ }
+ let mut v = V { cx, is_unsafe: false };
+ v.visit_expr(e);
+ v.is_unsafe
+}
[toolchain]
-channel = "nightly-2021-11-23"
+channel = "nightly-2021-12-02"
components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
-error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
+error: some fields in `NoGeneric` are not safe to be sent to another thread
--> $DIR/test.rs:11:1
|
LL | unsafe impl Send for NoGeneric {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
-note: the type of field `rc_is_not_send` is `!Send`
+note: it is not safe to send field `rc_is_not_send` to another thread
--> $DIR/test.rs:8:5
|
LL | rc_is_not_send: Rc<String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
+error: some fields in `MultiField<T>` are not safe to be sent to another thread
--> $DIR/test.rs:19:1
|
LL | unsafe impl<T> Send for MultiField<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
+note: it is not safe to send field `field1` to another thread
--> $DIR/test.rs:14:5
|
LL | field1: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field2` is `!Send`
+note: it is not safe to send field `field2` to another thread
--> $DIR/test.rs:15:5
|
LL | field2: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field3` is `!Send`
+note: it is not safe to send field `field3` to another thread
--> $DIR/test.rs:16:5
|
LL | field3: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
+error: some fields in `MyOption<T>` are not safe to be sent to another thread
--> $DIR/test.rs:26:1
|
LL | unsafe impl<T> Send for MyOption<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `0` is `!Send`
+note: it is not safe to send field `0` to another thread
--> $DIR/test.rs:22:12
|
LL | MySome(T),
| ^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
+error: some fields in `HeuristicTest` are not safe to be sent to another thread
--> $DIR/test.rs:41:1
|
LL | unsafe impl Send for HeuristicTest {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
+note: it is not safe to send field `field1` to another thread
--> $DIR/test.rs:34:5
|
LL | field1: Vec<*const NonSend>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field2` is `!Send`
+note: it is not safe to send field `field2` to another thread
--> $DIR/test.rs:35:5
|
LL | field2: [*const NonSend; 3],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field3` is `!Send`
+note: it is not safe to send field `field3` to another thread
--> $DIR/test.rs:36:5
|
LL | field3: (*const NonSend, *const NonSend, *const NonSend),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field4` is `!Send`
+note: it is not safe to send field `field4` to another thread
--> $DIR/test.rs:37:5
|
LL | field4: (*const NonSend, Rc<u8>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field5` is `!Send`
+note: it is not safe to send field `field5` to another thread
--> $DIR/test.rs:38:5
|
LL | field5: Vec<Vec<*const NonSend>>,
error[E0308]: mismatched types
--> $DIR/ice-6250.rs:12:14
|
+LL | for reference in vec![1, 2, 3] {
+ | --------- expected due to the type of this binding
+...
LL | Some(reference) = cache.data.get(key) {
| ^^^^^^^^^ expected integer, found `&i32`
|
#[warn(clippy::all)]
fn main() {
- // TODO: do somethjing with swap
let mut a = 42;
let mut b = 1337;
error: this looks like you are trying to swap `a` and `b`
- --> $DIR/no_std_swap.rs:13:5
+ --> $DIR/no_std_swap.rs:12:5
|
LL | / a = b;
LL | | b = a;
// Issue #6808
let arr: [u8; 64] = [0; 64];
let _: Vec<_> = arr.to_vec();
+
+ // Issue #6703
+ let _: Vec<isize> = v.to_vec();
}
// Issue #6808
let arr: [u8; 64] = [0; 64];
let _: Vec<_> = arr.iter().cloned().collect();
+
+ // Issue #6703
+ let _: Vec<isize> = v.iter().copied().collect();
}
LL | let _: Vec<_> = arr.iter().cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
-error: aborting due to 4 previous errors
+error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+ --> $DIR/iter_cloned_collect.rs:31:26
+ |
+LL | let _: Vec<isize> = v.iter().copied().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+
+error: aborting due to 5 previous errors
unused_assignments,
clippy::similar_names,
clippy::blacklisted_name,
- clippy::branches_sharing_code
+ clippy::branches_sharing_code,
+ clippy::needless_late_init
)]
#![warn(clippy::useless_let_if_seq)]
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:65:5
+ --> $DIR/let_if_seq.rs:66:5
|
LL | / let mut foo = 0;
LL | | if f() {
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:70:5
+ --> $DIR/let_if_seq.rs:71:5
|
LL | / let mut bar = 0;
LL | | if f() {
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:78:5
+ --> $DIR/let_if_seq.rs:79:5
|
LL | / let quz;
LL | | if f() {
| |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:107:5
+ --> $DIR/let_if_seq.rs:108:5
|
LL | / let mut baz = 0;
LL | | if f() {
}
fn main() {
- let x;
- x = 2usize;
+ let x = 2usize;
min(1, max(3, x));
min(max(3, x), 1);
max(min(x, 1), 3);
let y = 2isize;
min(max(y, -1), 3);
- let s;
- s = "Hello";
-
+ let s = "Hello";
min("Apple", max("Zoo", s));
max(min(s, "Apple"), "Zoo");
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:24:5
+ --> $DIR/min_max.rs:23:5
|
LL | min(1, max(3, x));
| ^^^^^^^^^^^^^^^^^
= note: `-D clippy::min-max` implied by `-D warnings`
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:25:5
+ --> $DIR/min_max.rs:24:5
|
LL | min(max(3, x), 1);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:26:5
+ --> $DIR/min_max.rs:25:5
|
LL | max(min(x, 1), 3);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:27:5
+ --> $DIR/min_max.rs:26:5
|
LL | max(3, min(x, 1));
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:29:5
+ --> $DIR/min_max.rs:28:5
|
LL | my_max(3, my_min(x, 1));
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:41:5
+ --> $DIR/min_max.rs:38:5
|
LL | min("Apple", max("Zoo", s));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:42:5
+ --> $DIR/min_max.rs:39:5
|
LL | max(min(s, "Apple"), "Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:47:5
+ --> $DIR/min_max.rs:44:5
|
LL | x.min(1).max(3);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:48:5
+ --> $DIR/min_max.rs:45:5
|
LL | x.max(3).min(1);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:49:5
+ --> $DIR/min_max.rs:46:5
|
LL | f.max(3f32).min(1f32);
| ^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:55:5
+ --> $DIR/min_max.rs:52:5
|
LL | max(x.min(1), 3);
| ^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:58:5
+ --> $DIR/min_max.rs:55:5
|
LL | s.max("Zoo").min("Apple");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:59:5
+ --> $DIR/min_max.rs:56:5
|
LL | s.min("Apple").max("Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
needless_bool(x);
needless_bool2(x);
needless_bool3(x);
+ needless_bool_condition();
}
fn bool_ret3(x: bool) -> bool {
true
} else { !returns_bool() };
}
+
+unsafe fn no(v: u8) -> u8 {
+ v
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn needless_bool_condition() -> bool {
+ (unsafe { no(4) } & 1 != 0);
+ let _brackets_unneeded = unsafe { no(4) } & 1 != 0;
+ fn foo() -> bool {
+ // parentheses are needed here
+ (unsafe { no(4) } & 1 != 0)
+ }
+
+ foo()
+}
needless_bool(x);
needless_bool2(x);
needless_bool3(x);
+ needless_bool_condition();
}
fn bool_ret3(x: bool) -> bool {
true
};
}
+
+unsafe fn no(v: u8) -> u8 {
+ v
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn needless_bool_condition() -> bool {
+ if unsafe { no(4) } & 1 != 0 {
+ true
+ } else {
+ false
+ };
+ let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
+ fn foo() -> bool {
+ // parentheses are needed here
+ if unsafe { no(4) } & 1 != 0 { true } else { false }
+ }
+
+ foo()
+}
| |_____^ help: you can reduce it to: `!(x && y)`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:71:5
+ --> $DIR/fixable.rs:72:5
|
LL | / if x {
LL | | return true;
| |_____^ help: you can reduce it to: `return x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:79:5
+ --> $DIR/fixable.rs:80:5
|
LL | / if x {
LL | | return false;
| |_____^ help: you can reduce it to: `return !x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:87:5
+ --> $DIR/fixable.rs:88:5
|
LL | / if x && y {
LL | | return true;
| |_____^ help: you can reduce it to: `return x && y`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:95:5
+ --> $DIR/fixable.rs:96:5
|
LL | / if x && y {
LL | | return false;
| |_____^ help: you can reduce it to: `return !(x && y)`
error: equality checks against true are unnecessary
- --> $DIR/fixable.rs:103:8
+ --> $DIR/fixable.rs:104:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`
= note: `-D clippy::bool-comparison` implied by `-D warnings`
error: equality checks against false can be replaced by a negation
- --> $DIR/fixable.rs:107:8
+ --> $DIR/fixable.rs:108:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: equality checks against true are unnecessary
- --> $DIR/fixable.rs:117:8
+ --> $DIR/fixable.rs:118: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:118:8
+ --> $DIR/fixable.rs:119: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:127:12
+ --> $DIR/fixable.rs:128:12
|
LL | } else if returns_bool() {
| ____________^
LL | | };
| |_____^ help: you can reduce it to: `{ !returns_bool() }`
-error: aborting due to 12 previous errors
+error: this if-then-else expression returns a bool literal
+ --> $DIR/fixable.rs:141:5
+ |
+LL | / if unsafe { no(4) } & 1 != 0 {
+LL | | true
+LL | | } else {
+LL | | false
+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
+ |
+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
+ |
+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
--- /dev/null
+#![allow(unused)]
+
+fn main() {
+ let a;
+ let n = 1;
+ match n {
+ 1 => a = "one",
+ _ => {
+ a = "two";
+ },
+ }
+
+ let b;
+ if n == 3 {
+ b = "four";
+ } else {
+ b = "five"
+ }
+
+ let c;
+ if let Some(n) = Some(5) {
+ c = n;
+ } else {
+ c = -50;
+ }
+
+ let d;
+ if true {
+ let temp = 5;
+ d = temp;
+ } else {
+ d = 15;
+ }
+
+ let e;
+ if true {
+ e = format!("{} {}", a, b);
+ } else {
+ e = format!("{}", c);
+ }
+
+ println!("{}", a);
+}
+
+async fn in_async() -> &'static str {
+ async fn f() -> &'static str {
+ "one"
+ }
+
+ let a;
+ let n = 1;
+ match n {
+ 1 => a = f().await,
+ _ => {
+ a = "two";
+ },
+ }
+
+ a
+}
+
+const fn in_const() -> &'static str {
+ const fn f() -> &'static str {
+ "one"
+ }
+
+ let a;
+ let n = 1;
+ match n {
+ 1 => a = f(),
+ _ => {
+ a = "two";
+ },
+ }
+
+ a
+}
+
+fn does_not_lint() {
+ let z;
+ if false {
+ z = 1;
+ }
+
+ let x;
+ let y;
+ if true {
+ x = 1;
+ } else {
+ y = 1;
+ }
+
+ let mut x;
+ if true {
+ x = 5;
+ x = 10 / x;
+ } else {
+ x = 2;
+ }
+
+ let x;
+ let _ = match 1 {
+ 1 => x = 10,
+ _ => x = 20,
+ };
+
+ // using tuples would be possible, but not always preferable
+ let x;
+ let y;
+ if true {
+ x = 1;
+ y = 2;
+ } else {
+ x = 3;
+ y = 4;
+ }
+
+ // could match with a smarter heuristic to avoid multiple assignments
+ let x;
+ if true {
+ let mut y = 5;
+ y = 6;
+ x = y;
+ } else {
+ x = 2;
+ }
+
+ let (x, y);
+ if true {
+ x = 1;
+ } else {
+ x = 2;
+ }
+ y = 3;
+
+ macro_rules! assign {
+ ($i:ident) => {
+ $i = 1;
+ };
+ }
+ let x;
+ assign!(x);
+
+ let x;
+ if true {
+ assign!(x);
+ } else {
+ x = 2;
+ }
+
+ macro_rules! in_macro {
+ () => {
+ let x;
+ x = 1;
+
+ let x;
+ if true {
+ x = 1;
+ } else {
+ x = 2;
+ }
+ };
+ }
+ in_macro!();
+
+ println!("{}", x);
+}
--- /dev/null
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:4:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+ = note: `-D clippy::needless-late-init` implied by `-D warnings`
+help: declare `a` here
+ |
+LL | let a = match n {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL ~ 1 => "one",
+LL | _ => {
+LL ~ "two"
+ |
+help: add a semicolon after the `match` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:13:5
+ |
+LL | let b;
+ | ^^^^^^
+ |
+help: declare `b` here
+ |
+LL | let b = if n == 3 {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ "four"
+LL | } else {
+LL ~ "five"
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:20:5
+ |
+LL | let c;
+ | ^^^^^^
+ |
+help: declare `c` here
+ |
+LL | let c = if let Some(n) = Some(5) {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ n
+LL | } else {
+LL ~ -50
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:27:5
+ |
+LL | let d;
+ | ^^^^^^
+ |
+help: declare `d` here
+ |
+LL | let d = if true {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ temp
+LL | } else {
+LL ~ 15
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:35:5
+ |
+LL | let e;
+ | ^^^^^^
+ |
+help: declare `e` here
+ |
+LL | let e = if true {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ format!("{} {}", a, b)
+LL | } else {
+LL ~ format!("{}", c)
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:50:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+help: declare `a` here
+ |
+LL | let a = match n {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL ~ 1 => f().await,
+LL | _ => {
+LL ~ "two"
+ |
+help: add a semicolon after the `match` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:67:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+help: declare `a` here
+ |
+LL | let a = match n {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL ~ 1 => f(),
+LL | _ => {
+LL ~ "two"
+ |
+help: add a semicolon after the `match` expression
+ |
+LL | };
+ | +
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// run-rustfix
+
+#![allow(unused, clippy::assign_op_pattern)]
+
+fn main() {
+
+ let a = "zero";
+
+
+
+ let b = 1;
+ let c = 2;
+
+
+ let d: usize = 1;
+
+
+ let mut e = 1;
+ e = 2;
+
+
+ let f = match 1 {
+ 1 => "three",
+ _ => return,
+ }; // has semi
+
+
+ let g: usize = if true {
+ 5
+ } else {
+ panic!();
+ };
+
+
+ let h = format!("{}", e);
+
+ println!("{}", a);
+}
--- /dev/null
+// run-rustfix
+
+#![allow(unused, clippy::assign_op_pattern)]
+
+fn main() {
+ let a;
+ a = "zero";
+
+ let b;
+ let c;
+ b = 1;
+ c = 2;
+
+ let d: usize;
+ d = 1;
+
+ let mut e;
+ e = 1;
+ e = 2;
+
+ let f;
+ match 1 {
+ 1 => f = "three",
+ _ => return,
+ }; // has semi
+
+ let g: usize;
+ if true {
+ g = 5;
+ } else {
+ panic!();
+ }
+
+ let h;
+ h = format!("{}", e);
+
+ println!("{}", a);
+}
--- /dev/null
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:6:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+ = note: `-D clippy::needless-late-init` implied by `-D warnings`
+help: declare `a` here
+ |
+LL | let a = "zero";
+ | ~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:9:5
+ |
+LL | let b;
+ | ^^^^^^
+ |
+help: declare `b` here
+ |
+LL | let b = 1;
+ | ~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:10:5
+ |
+LL | let c;
+ | ^^^^^^
+ |
+help: declare `c` here
+ |
+LL | let c = 2;
+ | ~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:14:5
+ |
+LL | let d: usize;
+ | ^^^^^^^^^^^^^
+ |
+help: declare `d` here
+ |
+LL | let d: usize = 1;
+ | ~~~~~~~~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:17:5
+ |
+LL | let mut e;
+ | ^^^^^^^^^^
+ |
+help: declare `e` here
+ |
+LL | let mut e = 1;
+ | ~~~~~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:21:5
+ |
+LL | let f;
+ | ^^^^^^
+ |
+help: declare `f` here
+ |
+LL | let f = match 1 {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL | 1 => "three",
+ | ~~~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:27:5
+ |
+LL | let g: usize;
+ | ^^^^^^^^^^^^^
+ |
+help: declare `g` here
+ |
+LL | let g: usize = if true {
+ | ++++++++++++++
+help: remove the assignments from the branches
+ |
+LL | 5
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:34:5
+ |
+LL | let h;
+ | ^^^^^^
+ |
+help: declare `h` here
+ |
+LL | let h = format!("{}", e);
+ | ~~~~~
+
+error: aborting due to 8 previous errors
+
unsafe impl<T> Send for MyOption<T> {}
+// Test types that contain `NonNull` instead of raw pointers (#8045)
+pub struct WrappedNonNull(UnsafeCell<NonNull<()>>);
+
+unsafe impl Send for WrappedNonNull {}
+
// Multiple type parameters
pub struct MultiParam<A, B> {
vec: Vec<(A, B)>,
-error: this implementation is unsound, as some fields in `RingBuffer<T>` are `!Send`
+error: some fields in `RingBuffer<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:16:1
|
LL | unsafe impl<T> Send for RingBuffer<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
-note: the type of field `data` is `!Send`
+note: it is not safe to send field `data` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:11:5
|
LL | data: Vec<UnsafeCell<T>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: add bounds on type parameter `T` that satisfy `Vec<UnsafeCell<T>>: Send`
-error: this implementation is unsound, as some fields in `MvccRwLock<T>` are `!Send`
+error: some fields in `MvccRwLock<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:24:1
|
LL | unsafe impl<T> Send for MvccRwLock<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `lock` is `!Send`
+note: it is not safe to send field `lock` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:21:5
|
LL | lock: Mutex<Box<T>>,
| ^^^^^^^^^^^^^^^^^^^
= help: add bounds on type parameter `T` that satisfy `Mutex<Box<T>>: Send`
-error: this implementation is unsound, as some fields in `ArcGuard<RC, T>` are `!Send`
+error: some fields in `ArcGuard<RC, T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:32:1
|
LL | unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `head` is `!Send`
+note: it is not safe to send field `head` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:29:5
|
LL | head: Arc<RC>,
| ^^^^^^^^^^^^^
= help: add bounds on type parameter `RC` that satisfy `Arc<RC>: Send`
-error: this implementation is unsound, as some fields in `DeviceHandle<T>` are `!Send`
+error: some fields in `DeviceHandle<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:48:1
|
LL | unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `context` is `!Send`
+note: it is not safe to send field `context` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:44:5
|
LL | context: T,
| ^^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
+error: some fields in `NoGeneric` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:55:1
|
LL | unsafe impl Send for NoGeneric {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `rc_is_not_send` is `!Send`
+note: it is not safe to send field `rc_is_not_send` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:52:5
|
LL | rc_is_not_send: Rc<String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
+error: some fields in `MultiField<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:63:1
|
LL | unsafe impl<T> Send for MultiField<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
+note: it is not safe to send field `field1` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:58:5
|
LL | field1: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field2` is `!Send`
+note: it is not safe to send field `field2` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:59:5
|
LL | field2: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field3` is `!Send`
+note: it is not safe to send field `field3` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:60:5
|
LL | field3: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
+error: some fields in `MyOption<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:70:1
|
LL | unsafe impl<T> Send for MyOption<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `0` is `!Send`
+note: it is not safe to send field `0` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:66:12
|
LL | MySome(T),
| ^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `MultiParam<A, B>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:77:1
+error: some fields in `MultiParam<A, B>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:82:1
|
LL | unsafe impl<A, B> Send for MultiParam<A, B> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `vec` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:74:5
+note: it is not safe to send field `vec` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:79:5
|
LL | vec: Vec<(A, B)>,
| ^^^^^^^^^^^^^^^^
= help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send`
-error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:95:1
+error: some fields in `HeuristicTest` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:100:1
|
LL | unsafe impl Send for HeuristicTest {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field4` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:90:5
+note: it is not safe to send field `field4` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:95:5
|
LL | field4: (*const NonSend, Rc<u8>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-error: this implementation is unsound, as some fields in `AttrTest3<T>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:114:1
+error: some fields in `AttrTest3<T>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:119:1
|
LL | unsafe impl<T> Send for AttrTest3<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `0` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:109:11
+note: it is not safe to send field `0` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:114:11
|
LL | Enum2(T),
| ^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `Complex<P, u32>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:122:1
+error: some fields in `Complex<P, u32>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:127:1
|
LL | unsafe impl<P> Send for Complex<P, u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:118:5
+note: it is not safe to send field `field1` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:123:5
|
LL | field1: A,
| ^^^^^^^^^
= help: add `P: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `Complex<Q, MutexGuard<'static, bool>>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:125:1
+error: some fields in `Complex<Q, MutexGuard<'static, bool>>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:130:1
|
LL | unsafe impl<Q: Send> Send for Complex<Q, MutexGuard<'static, bool>> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field2` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:119:5
+note: it is not safe to send field `field2` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:124:5
|
LL | field2: B,
| ^^^^^^^^^
// aux-build:macro_rules.rs
#![warn(clippy::option_env_unwrap)]
+#![allow(clippy::map_flatten)]
#[macro_use]
extern crate macro_rules;
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:17:13
+ --> $DIR/option_env_unwrap.rs:18:13
|
LL | let _ = option_env!("PATH").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider using the `env!` macro instead
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:18:13
+ --> $DIR/option_env_unwrap.rs:19:13
|
LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider using the `env!` macro instead
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:9:9
+ --> $DIR/option_env_unwrap.rs:10:9
|
LL | option_env!($env).unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:12:9
+ --> $DIR/option_env_unwrap.rs:13:9
|
LL | option_env!($env).expect($message)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:21:13
+ --> $DIR/option_env_unwrap.rs:22:13
|
LL | let _ = option_env_unwrap_external!("PATH");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:22:13
+ --> $DIR/option_env_unwrap.rs:23:13
|
LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#![warn(clippy::option_filter_map)]
// run-rustfix
-fn odds_out(x: i32) -> Option<i32> {
- if x % 2 == 0 { Some(x) } else { None }
-}
+#![warn(clippy::option_filter_map)]
+#![allow(clippy::map_flatten)]
fn main() {
let _ = Some(Some(1)).flatten();
.map(odds_out)
.flatten();
}
+
+fn odds_out(x: i32) -> Option<i32> {
+ if x % 2 == 0 { Some(x) } else { None }
+}
-#![warn(clippy::option_filter_map)]
// run-rustfix
-fn odds_out(x: i32) -> Option<i32> {
- if x % 2 == 0 { Some(x) } else { None }
-}
+#![warn(clippy::option_filter_map)]
+#![allow(clippy::map_flatten)]
fn main() {
let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
.filter(|o| o.is_some())
.map(|o| o.unwrap());
}
+
+fn odds_out(x: i32) -> Option<i32> {
+ if x % 2 == 0 { Some(x) } else { None }
+}
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:8:27
+ --> $DIR/option_filter_map.rs:6:27
|
LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
= note: `-D clippy::option-filter-map` implied by `-D warnings`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:9:27
+ --> $DIR/option_filter_map.rs:7:27
|
LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:10:35
+ --> $DIR/option_filter_map.rs:8:35
|
LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:11:35
+ --> $DIR/option_filter_map.rs:9:35
|
LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:13:39
+ --> $DIR/option_filter_map.rs:11:39
|
LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:14:39
+ --> $DIR/option_filter_map.rs:12:39
|
LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:18:10
+ --> $DIR/option_filter_map.rs:16:10
|
LL | .filter(Option::is_some)
| __________^
| |____________________________^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:23:10
+ --> $DIR/option_filter_map.rs:21:10
|
LL | .filter(|o| o.is_some())
| __________^
.collect::<Vec<_>>()
}
+enum DummyEnum {
+ One(u8),
+ Two,
+}
+
+// should not warn since there is a compled complex subpat
+// see #7991
+fn complex_subpat() -> DummyEnum {
+ let x = Some(DummyEnum::One(1));
+ let _ = if let Some(_one @ DummyEnum::One(..)) = x { 1 } else { 2 };
+ DummyEnum::Two
+}
+
fn main() {
let optional = Some(5);
let _ = optional.map_or(5, |x| x + 2);
}
let _ = pattern_to_vec("hello world");
+ let _ = complex_subpat();
}
.collect::<Vec<_>>()
}
+enum DummyEnum {
+ One(u8),
+ Two,
+}
+
+// should not warn since there is a compled complex subpat
+// see #7991
+fn complex_subpat() -> DummyEnum {
+ let x = Some(DummyEnum::One(1));
+ let _ = if let Some(_one @ DummyEnum::One(..)) = x { 1 } else { 2 };
+ DummyEnum::Two
+}
+
fn main() {
let optional = Some(5);
let _ = if let Some(x) = optional { x + 2 } else { 5 };
}
let _ = pattern_to_vec("hello world");
+ let _ = complex_subpat();
}
| |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:114:13
+ --> $DIR/option_if_let_else.rs:127:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:123:13
+ --> $DIR/option_if_let_else.rs:136:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:151:13
+ --> $DIR/option_if_let_else.rs:164:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:155:13
+ --> $DIR/option_if_let_else.rs:168:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
Some(_) => (),
_ => (),
}
+
+ const FOO: &str = "foo";
+
+ fn foo(s: &str) -> i32 {
+ match s {
+ FOO => 1,
+ _ => 0,
+ }
+ }
}
Ok(y)
}
+// see issue #8019
+pub enum NotOption {
+ None,
+ First,
+ AfterFirst,
+}
+
+fn obj(_: i32) -> Result<(), NotOption> {
+ Err(NotOption::First)
+}
+
+fn f() -> NotOption {
+ if obj(2).is_err() {
+ return NotOption::None;
+ }
+ NotOption::First
+}
+
fn main() {
some_func(Some(42));
some_func(None);
func();
let _ = result_func(Ok(42));
+ let _ = f();
}
Ok(y)
}
+// see issue #8019
+pub enum NotOption {
+ None,
+ First,
+ AfterFirst,
+}
+
+fn obj(_: i32) -> Result<(), NotOption> {
+ Err(NotOption::First)
+}
+
+fn f() -> NotOption {
+ if obj(2).is_err() {
+ return NotOption::None;
+ }
+ NotOption::First
+}
+
fn main() {
some_func(Some(42));
some_func(None);
func();
let _ = result_func(Ok(42));
+ let _ = f();
}
// non rustfixable, see redundant_closure_call_fixable.rs
#![warn(clippy::redundant_closure_call)]
+#![allow(clippy::needless_late_init)]
fn main() {
let mut i = 1;
error: closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call_late.rs:15:5
+ --> $DIR/redundant_closure_call_late.rs:16:5
|
LL | i = redun_closure();
| ^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
error: closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call_late.rs:19:5
+ --> $DIR/redundant_closure_call_late.rs:20:5
|
LL | i = shadowed_closure();
| ^^^^^^^^^^^^^^^^^^^^^^
error: closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call_late.rs:21:5
+ --> $DIR/redundant_closure_call_late.rs:22:5
|
LL | i = shadowed_closure();
| ^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::redundant_else)]
-#![allow(clippy::needless_return, clippy::if_same_then_else)]
+#![allow(clippy::needless_return, clippy::if_same_then_else, clippy::needless_late_init)]
fn main() {
loop {
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:20:13
|
LL | fn foo() {}
LL | fn foo() {}
| ^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:44:13
|
LL | fn foo() {}
LL | fn foo() {}
| ^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:58:13
|
LL | fn foo() {}
LL | impl T1 for S {}
| ^^^^^^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:70:13
|
LL | fn foo() {}
LL | impl T1 for S {}
| ^^^^^^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:34:13
|
LL | fn clone() {}
// check that we don't lint if `find()` is called with
// `Pattern` that is not a string
let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some();
+
+ let some_closure = |x: &u32| *x == 0;
+ let _ = (0..1).find(some_closure).is_some();
}
#[rustfmt::skip]
// check that we don't lint if `find()` is called with
// `Pattern` that is not a string
let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none();
+
+ let some_closure = |x: &u32| *x == 0;
+ let _ = (0..1).find(some_closure).is_none();
}
|
= help: this is more succinctly expressed by calling `any()`
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some.rs:41:20
+ |
+LL | let _ = (0..1).find(some_closure).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(some_closure)`
+
error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some.rs:48:13
+ --> $DIR/search_is_some.rs:51:13
|
LL | let _ = v.iter().find(|&x| {
| _____________^
= help: this is more succinctly expressed by calling `any()` with negation
error: called `is_none()` after searching an `Iterator` with `position`
- --> $DIR/search_is_some.rs:54:13
+ --> $DIR/search_is_some.rs:57:13
|
LL | let _ = v.iter().position(|&x| {
| _____________^
= help: this is more succinctly expressed by calling `any()` with negation
error: called `is_none()` after searching an `Iterator` with `rposition`
- --> $DIR/search_is_some.rs:60:13
+ --> $DIR/search_is_some.rs:63:13
|
LL | let _ = v.iter().rposition(|&x| {
| _____________^
|
= help: this is more succinctly expressed by calling `any()` with negation
-error: aborting due to 6 previous errors
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some.rs:78:13
+ |
+LL | let _ = (0..1).find(some_closure).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(some_closure)`
+
+error: aborting due to 8 previous errors
+++ /dev/null
-// run-rustfix
-#![allow(dead_code)]
-#![warn(clippy::search_is_some)]
-
-fn main() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_some()`, single-line case.
- let _ = v.iter().any(|x| *x < 0);
- let _ = (0..1).any(|x| **y == x); // one dereference less
- let _ = (0..1).any(|x| x == 0);
- let _ = v.iter().any(|x| *x == 0);
-
- // Check `position().is_some()`, single-line case.
- let _ = v.iter().any(|&x| x < 0);
-
- // Check `rposition().is_some()`, single-line case.
- let _ = v.iter().any(|&x| x < 0);
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
- // caller of `find()` is a `&`static str`
- let _ = "hello world".contains("world");
- let _ = "hello world".contains(&s2);
- let _ = "hello world".contains(&s2[2..]);
- // caller of `find()` is a `String`
- let _ = s1.contains("world");
- let _ = s1.contains(&s2);
- let _ = s1.contains(&s2[2..]);
- // caller of `find()` is slice of `String`
- let _ = s1[2..].contains("world");
- let _ = s1[2..].contains(&s2);
- let _ = s1[2..].contains(&s2[2..]);
-}
-
-fn is_none() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_none()`, single-line case.
- let _ = !v.iter().any(|x| *x < 0);
- let _ = !(0..1).any(|x| **y == x); // one dereference less
- let _ = !(0..1).any(|x| x == 0);
- let _ = !v.iter().any(|x| *x == 0);
-
- // Check `position().is_none()`, single-line case.
- let _ = !v.iter().any(|&x| x < 0);
-
- // Check `rposition().is_none()`, single-line case.
- let _ = !v.iter().any(|&x| x < 0);
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
-
- // caller of `find()` is a `&`static str`
- let _ = !"hello world".contains("world");
- let _ = !"hello world".contains(&s2);
- let _ = !"hello world".contains(&s2[2..]);
- // caller of `find()` is a `String`
- let _ = !s1.contains("world");
- let _ = !s1.contains(&s2);
- let _ = !s1.contains(&s2[2..]);
- // caller of `find()` is slice of `String`
- let _ = !s1[2..].contains("world");
- let _ = !s1[2..].contains(&s2);
- let _ = !s1[2..].contains(&s2[2..]);
-}
+++ /dev/null
-// run-rustfix
-#![allow(dead_code)]
-#![warn(clippy::search_is_some)]
-
-fn main() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_some()`, single-line case.
- let _ = v.iter().find(|&x| *x < 0).is_some();
- let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
- let _ = (0..1).find(|x| *x == 0).is_some();
- let _ = v.iter().find(|x| **x == 0).is_some();
-
- // Check `position().is_some()`, single-line case.
- let _ = v.iter().position(|&x| x < 0).is_some();
-
- // Check `rposition().is_some()`, single-line case.
- let _ = v.iter().rposition(|&x| x < 0).is_some();
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
- // caller of `find()` is a `&`static str`
- let _ = "hello world".find("world").is_some();
- let _ = "hello world".find(&s2).is_some();
- let _ = "hello world".find(&s2[2..]).is_some();
- // caller of `find()` is a `String`
- let _ = s1.find("world").is_some();
- let _ = s1.find(&s2).is_some();
- let _ = s1.find(&s2[2..]).is_some();
- // caller of `find()` is slice of `String`
- let _ = s1[2..].find("world").is_some();
- let _ = s1[2..].find(&s2).is_some();
- let _ = s1[2..].find(&s2[2..]).is_some();
-}
-
-fn is_none() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_none()`, single-line case.
- let _ = v.iter().find(|&x| *x < 0).is_none();
- let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
- let _ = (0..1).find(|x| *x == 0).is_none();
- let _ = v.iter().find(|x| **x == 0).is_none();
-
- // Check `position().is_none()`, single-line case.
- let _ = v.iter().position(|&x| x < 0).is_none();
-
- // Check `rposition().is_none()`, single-line case.
- let _ = v.iter().rposition(|&x| x < 0).is_none();
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
-
- // caller of `find()` is a `&`static str`
- let _ = "hello world".find("world").is_none();
- let _ = "hello world".find(&s2).is_none();
- let _ = "hello world".find(&s2[2..]).is_none();
- // caller of `find()` is a `String`
- let _ = s1.find("world").is_none();
- let _ = s1.find(&s2).is_none();
- let _ = s1.find(&s2[2..]).is_none();
- // caller of `find()` is slice of `String`
- let _ = s1[2..].find("world").is_none();
- let _ = s1[2..].find(&s2).is_none();
- let _ = s1[2..].find(&s2[2..]).is_none();
-}
+++ /dev/null
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:10:22
- |
-LL | let _ = v.iter().find(|&x| *x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)`
- |
- = note: `-D clippy::search-is-some` implied by `-D warnings`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:11:20
- |
-LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:12:20
- |
-LL | let _ = (0..1).find(|x| *x == 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:13:22
- |
-LL | let _ = v.iter().find(|x| **x == 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with `position`
- --> $DIR/search_is_some_fixable.rs:16:22
- |
-LL | let _ = v.iter().position(|&x| x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
-
-error: called `is_some()` after searching an `Iterator` with `rposition`
- --> $DIR/search_is_some_fixable.rs:19:22
- |
-LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:24:27
- |
-LL | let _ = "hello world".find("world").is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:25:27
- |
-LL | let _ = "hello world".find(&s2).is_some();
- | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:26:27
- |
-LL | let _ = "hello world".find(&s2[2..]).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:28:16
- |
-LL | let _ = s1.find("world").is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:29:16
- |
-LL | let _ = s1.find(&s2).is_some();
- | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:30:16
- |
-LL | let _ = s1.find(&s2[2..]).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:32:21
- |
-LL | let _ = s1[2..].find("world").is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:33:21
- |
-LL | let _ = s1[2..].find(&s2).is_some();
- | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:34:21
- |
-LL | let _ = s1[2..].find(&s2[2..]).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:42:13
- |
-LL | let _ = v.iter().find(|&x| *x < 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:43:13
- |
-LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:44:13
- |
-LL | let _ = (0..1).find(|x| *x == 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:45:13
- |
-LL | let _ = v.iter().find(|x| **x == 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)`
-
-error: called `is_none()` after searching an `Iterator` with `position`
- --> $DIR/search_is_some_fixable.rs:48:13
- |
-LL | let _ = v.iter().position(|&x| x < 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
-
-error: called `is_none()` after searching an `Iterator` with `rposition`
- --> $DIR/search_is_some_fixable.rs:51:13
- |
-LL | let _ = v.iter().rposition(|&x| x < 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:57:13
- |
-LL | let _ = "hello world".find("world").is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:58:13
- |
-LL | let _ = "hello world".find(&s2).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:59:13
- |
-LL | let _ = "hello world".find(&s2[2..]).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:61:13
- |
-LL | let _ = s1.find("world").is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:62:13
- |
-LL | let _ = s1.find(&s2).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:63:13
- |
-LL | let _ = s1.find(&s2[2..]).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:65:13
- |
-LL | let _ = s1[2..].find("world").is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:66:13
- |
-LL | let _ = s1[2..].find(&s2).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:67:13
- |
-LL | let _ = s1[2..].find(&s2[2..]).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])`
-
-error: aborting due to 30 previous errors
-
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_none()`, single-line case.
+ let _ = !v.iter().any(|x| *x < 0);
+ let _ = !(0..1).any(|x| **y == x); // one dereference less
+ let _ = !(0..1).any(|x| x == 0);
+ let _ = !v.iter().any(|x| *x == 0);
+ let _ = !(4..5).any(|x| x == 1 || x == 3 || x == 5);
+ let _ = !(1..3).any(|x| [1, 2, 3].contains(&x));
+ let _ = !(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x));
+ let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0);
+ let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1);
+
+ // Check `position().is_none()`, single-line case.
+ let _ = !v.iter().any(|&x| x < 0);
+
+ // Check `rposition().is_none()`, single-line case.
+ let _ = !v.iter().any(|&x| x < 0);
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+
+ // caller of `find()` is a `&`static str`
+ let _ = !"hello world".contains("world");
+ let _ = !"hello world".contains(&s2);
+ let _ = !"hello world".contains(&s2[2..]);
+ // caller of `find()` is a `String`
+ let _ = !s1.contains("world");
+ let _ = !s1.contains(&s2);
+ let _ = !s1.contains(&s2[2..]);
+ // caller of `find()` is slice of `String`
+ let _ = !s1[2..].contains("world");
+ let _ = !s1[2..].contains(&s2);
+ let _ = !s1[2..].contains(&s2[2..]);
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| !filter_hand.iter().any(|cc| c == &cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = !vfoo.iter().any(|v| v.foo == 1 && v.bar == 2);
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = !vfoo
+ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2);
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = !vfoo.iter().any(|a| a[0] == 42);
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = !vfoo.iter().any(|sub| sub[1..4].len() == 3);
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = ![ppx].iter().any(|ppp_x: &&u32| please(ppp_x));
+ let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2);
+
+ let v = vec![3, 2, 1, 0];
+ let _ = !v.iter().any(|x| deref_enough(*x));
+ let _ = !v.iter().any(|x: &u32| deref_enough(*x));
+
+ #[allow(clippy::redundant_closure)]
+ let _ = !v.iter().any(|x| arg_no_deref(&x));
+ #[allow(clippy::redundant_closure)]
+ let _ = !v.iter().any(|x: &u32| arg_no_deref(&x));
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = !vfoo
+ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2);
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = !vfoo.iter().any(|v| v.inner[0].bar == 2);
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = !vfoo.iter().any(|x| (**x)[0] == 9);
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = !vfoo.iter().any(|v| v.by_ref(&v.bar));
+ }
+
+ fn ref_bindings() {
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ }
+
+ fn test_string_1(s: &str) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = !v.iter().any(|s| s[0].is_empty());
+ let _ = !v.iter().any(|s| test_string_1(&s[0]));
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = !v.iter().any(|fp| fp.field.is_power_of_two());
+ let _ = !v.iter().any(|fp| test_u32_1(fp.field));
+ let _ = !v.iter().any(|fp| test_u32_2(*fp.field));
+ }
+}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_none()`, single-line case.
+ let _ = v.iter().find(|&x| *x < 0).is_none();
+ let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
+ let _ = (0..1).find(|x| *x == 0).is_none();
+ let _ = v.iter().find(|x| **x == 0).is_none();
+ let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none();
+ let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none();
+ let _ = (1..3)
+ .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+ .is_none();
+
+ // Check `position().is_none()`, single-line case.
+ let _ = v.iter().position(|&x| x < 0).is_none();
+
+ // Check `rposition().is_none()`, single-line case.
+ let _ = v.iter().rposition(|&x| x < 0).is_none();
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".find("world").is_none();
+ let _ = "hello world".find(&s2).is_none();
+ let _ = "hello world".find(&s2[2..]).is_none();
+ // caller of `find()` is a `String`
+ let _ = s1.find("world").is_none();
+ let _ = s1.find(&s2).is_none();
+ let _ = s1.find(&s2[2..]).is_none();
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].find("world").is_none();
+ let _ = s1[2..].find(&s2).is_none();
+ let _ = s1[2..].find(&s2[2..]).is_none();
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none();
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = vfoo
+ .iter()
+ .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+ .is_none();
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|a| a[0] == 42).is_none();
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none();
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none();
+ let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none();
+
+ let v = vec![3, 2, 1, 0];
+ let _ = v.iter().find(|x| deref_enough(**x)).is_none();
+ let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none();
+
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x| arg_no_deref(x)).is_none();
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none();
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = vfoo
+ .iter()
+ .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+ .is_none();
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none();
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none();
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none();
+ }
+
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
+ }
+
+ fn test_string_1(s: &String) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = v.iter().find(|s| s[0].is_empty()).is_none();
+ let _ = v.iter().find(|s| test_string_1(&s[0])).is_none();
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none();
+ let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none();
+ let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
+ }
+}
--- /dev/null
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:10:13
+ |
+LL | let _ = v.iter().find(|&x| *x < 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:11:13
+ |
+LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:12:13
+ |
+LL | let _ = (0..1).find(|x| *x == 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:13:13
+ |
+LL | let _ = v.iter().find(|x| **x == 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:14:13
+ |
+LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:15:13
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:16:13
+ |
+LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:17:13
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:18:13
+ |
+LL | let _ = (1..3)
+ | _____________^
+LL | | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+LL | | .is_none();
+ | |__________________^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)`
+
+error: called `is_none()` after searching an `Iterator` with `position`
+ --> $DIR/search_is_some_fixable_none.rs:23:13
+ |
+LL | let _ = v.iter().position(|&x| x < 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
+
+error: called `is_none()` after searching an `Iterator` with `rposition`
+ --> $DIR/search_is_some_fixable_none.rs:26:13
+ |
+LL | let _ = v.iter().rposition(|&x| x < 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:32:13
+ |
+LL | let _ = "hello world".find("world").is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:33:13
+ |
+LL | let _ = "hello world".find(&s2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:34:13
+ |
+LL | let _ = "hello world".find(&s2[2..]).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:36:13
+ |
+LL | let _ = s1.find("world").is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:37:13
+ |
+LL | let _ = s1.find(&s2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:38:13
+ |
+LL | let _ = s1.find(&s2[2..]).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:40:13
+ |
+LL | let _ = s1[2..].find("world").is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:41:13
+ |
+LL | let _ = s1[2..].find(&s2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:42:13
+ |
+LL | let _ = s1[2..].find(&s2[2..]).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:58:25
+ |
+LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:74:30
+ |
+LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:85:17
+ |
+LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:88:17
+ |
+LL | let _ = vfoo
+ | _________________^
+LL | | .iter()
+LL | | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+LL | | .is_none();
+ | |______________________^
+ |
+help: use `!_.any()` instead
+ |
+LL ~ let _ = !vfoo
+LL ~ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2);
+ |
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:96:17
+ |
+LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|a| a[0] == 42)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:102:17
+ |
+LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:120:17
+ |
+LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:121:17
+ |
+LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:124:17
+ |
+LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| deref_enough(*x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:125:17
+ |
+LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| deref_enough(*x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:128:17
+ |
+LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| arg_no_deref(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:130:17
+ |
+LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| arg_no_deref(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:150:17
+ |
+LL | let _ = vfoo
+ | _________________^
+LL | | .iter()
+LL | | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+LL | | .is_none();
+ | |______________________^
+ |
+help: use `!_.any()` instead
+ |
+LL ~ let _ = !vfoo
+LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2);
+ |
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:166:17
+ |
+LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.inner[0].bar == 2)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:171:17
+ |
+LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:184:17
+ |
+LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.by_ref(&v.bar))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:188:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:189:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do
+ --> $DIR/search_is_some_fixable_none.rs:192:25
+ |
+LL | fn test_string_1(s: &String) -> bool {
+ | ^^^^^^^ help: change this to: `&str`
+ |
+ = note: `-D clippy::ptr-arg` implied by `-D warnings`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:208:17
+ |
+LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| s[0].is_empty())`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:209:17
+ |
+LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| test_string_1(&s[0]))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:218:17
+ |
+LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| fp.field.is_power_of_two())`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:219:17
+ |
+LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_1(fp.field))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:220:17
+ |
+LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))`
+
+error: aborting due to 44 previous errors
+
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_some()`, single-line case.
+ let _ = v.iter().any(|x| *x < 0);
+ let _ = (0..1).any(|x| **y == x); // one dereference less
+ let _ = (0..1).any(|x| x == 0);
+ let _ = v.iter().any(|x| *x == 0);
+ let _ = (4..5).any(|x| x == 1 || x == 3 || x == 5);
+ let _ = (1..3).any(|x| [1, 2, 3].contains(&x));
+ let _ = (1..3).any(|x| x == 0 || [1, 2, 3].contains(&x));
+ let _ = (1..3).any(|x| [1, 2, 3].contains(&x) || x == 0);
+ let _ = (1..3)
+ .any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1);
+
+ // Check `position().is_some()`, single-line case.
+ let _ = v.iter().any(|&x| x < 0);
+
+ // Check `rposition().is_some()`, single-line case.
+ let _ = v.iter().any(|&x| x < 0);
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".contains("world");
+ let _ = "hello world".contains(&s2);
+ let _ = "hello world".contains(&s2[2..]);
+ // caller of `find()` is a `String`
+ let _ = s1.contains("world");
+ let _ = s1.contains(&s2);
+ let _ = s1.contains(&s2[2..]);
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].contains("world");
+ let _ = s1[2..].contains(&s2);
+ let _ = s1[2..].contains(&s2[2..]);
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| filter_hand.iter().any(|cc| c == &cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| filter_hand.iter().any(|cc| c == cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = vfoo.iter().any(|v| v.foo == 1 && v.bar == 2);
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = vfoo
+ .iter()
+ .any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2);
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = vfoo.iter().any(|a| a[0] == 42);
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = vfoo.iter().any(|sub| sub[1..4].len() == 3);
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = [ppx].iter().any(|ppp_x: &&u32| please(ppp_x));
+ let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2);
+
+ let v = vec![3, 2, 1, 0];
+ let _ = v.iter().any(|x| deref_enough(*x));
+ let _ = v.iter().any(|x: &u32| deref_enough(*x));
+
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().any(|x| arg_no_deref(&x));
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().any(|x: &u32| arg_no_deref(&x));
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = vfoo
+ .iter()
+ .any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2);
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = vfoo.iter().any(|v| v.inner[0].bar == 2);
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = vfoo.iter().any(|x| (**x)[0] == 9);
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = vfoo.iter().any(|v| v.by_ref(&v.bar));
+ }
+
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ }
+
+ fn test_string_1(s: &str) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = v.iter().any(|s| s[0].is_empty());
+ let _ = v.iter().any(|s| test_string_1(&s[0]));
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = v.iter().any(|fp| fp.field.is_power_of_two());
+ let _ = v.iter().any(|fp| test_u32_1(fp.field));
+ let _ = v.iter().any(|fp| test_u32_2(*fp.field));
+ }
+}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_some()`, single-line case.
+ let _ = v.iter().find(|&x| *x < 0).is_some();
+ let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+ let _ = (0..1).find(|x| *x == 0).is_some();
+ let _ = v.iter().find(|x| **x == 0).is_some();
+ let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some();
+ let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some();
+ let _ = (1..3)
+ .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+ .is_some();
+
+ // Check `position().is_some()`, single-line case.
+ let _ = v.iter().position(|&x| x < 0).is_some();
+
+ // Check `rposition().is_some()`, single-line case.
+ let _ = v.iter().rposition(|&x| x < 0).is_some();
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".find("world").is_some();
+ let _ = "hello world".find(&s2).is_some();
+ let _ = "hello world".find(&s2[2..]).is_some();
+ // caller of `find()` is a `String`
+ let _ = s1.find("world").is_some();
+ let _ = s1.find(&s2).is_some();
+ let _ = s1.find(&s2[2..]).is_some();
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].find("world").is_some();
+ let _ = s1[2..].find(&s2).is_some();
+ let _ = s1[2..].find(&s2[2..]).is_some();
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some();
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = vfoo
+ .iter()
+ .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+ .is_some();
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|a| a[0] == 42).is_some();
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some();
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some();
+ let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some();
+
+ let v = vec![3, 2, 1, 0];
+ let _ = v.iter().find(|x| deref_enough(**x)).is_some();
+ let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some();
+
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x| arg_no_deref(x)).is_some();
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some();
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = vfoo
+ .iter()
+ .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+ .is_some();
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some();
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some();
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some();
+ }
+
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
+ }
+
+ fn test_string_1(s: &String) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = v.iter().find(|s| s[0].is_empty()).is_some();
+ let _ = v.iter().find(|s| test_string_1(&s[0])).is_some();
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some();
+ let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some();
+ let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
+ }
+}
--- /dev/null
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:10:22
+ |
+LL | let _ = v.iter().find(|&x| *x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:11:20
+ |
+LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:12:20
+ |
+LL | let _ = (0..1).find(|x| *x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:13:22
+ |
+LL | let _ = v.iter().find(|x| **x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:14:20
+ |
+LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 1 || x == 3 || x == 5)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:15:20
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:16:20
+ |
+LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0 || [1, 2, 3].contains(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:17:20
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:19:10
+ |
+LL | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+ | __________^
+LL | | .is_some();
+ | |__________________^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)`
+
+error: called `is_some()` after searching an `Iterator` with `position`
+ --> $DIR/search_is_some_fixable_some.rs:23:22
+ |
+LL | let _ = v.iter().position(|&x| x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
+
+error: called `is_some()` after searching an `Iterator` with `rposition`
+ --> $DIR/search_is_some_fixable_some.rs:26:22
+ |
+LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:31:27
+ |
+LL | let _ = "hello world".find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:32:27
+ |
+LL | let _ = "hello world".find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:33:27
+ |
+LL | let _ = "hello world".find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:35:16
+ |
+LL | let _ = s1.find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:36:16
+ |
+LL | let _ = s1.find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:37:16
+ |
+LL | let _ = s1.find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:39:21
+ |
+LL | let _ = s1[2..].find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:40:21
+ |
+LL | let _ = s1[2..].find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:41:21
+ |
+LL | let _ = s1[2..].find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:57:44
+ |
+LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == &cc)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:73:49
+ |
+LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == cc)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:84:29
+ |
+LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.foo == 1 && v.bar == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:89:14
+ |
+LL | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+ | ______________^
+LL | | .is_some();
+ | |______________________^ help: use `any()` instead: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:95:29
+ |
+LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|a| a[0] == 42)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:101:29
+ |
+LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:119:30
+ |
+LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:120:50
+ |
+LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:123:26
+ |
+LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| deref_enough(*x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:124:26
+ |
+LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| deref_enough(*x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:127:26
+ |
+LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| arg_no_deref(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:129:26
+ |
+LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:151:14
+ |
+LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+ | ______________^
+LL | | .is_some();
+ | |______________________^ help: use `any()` instead: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:165:29
+ |
+LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.inner[0].bar == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:170:29
+ |
+LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:183:29
+ |
+LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.by_ref(&v.bar))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:187:55
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:188:55
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)`
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do
+ --> $DIR/search_is_some_fixable_some.rs:191:25
+ |
+LL | fn test_string_1(s: &String) -> bool {
+ | ^^^^^^^ help: change this to: `&str`
+ |
+ = note: `-D clippy::ptr-arg` implied by `-D warnings`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:207:26
+ |
+LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s[0].is_empty())`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:208:26
+ |
+LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| test_string_1(&s[0]))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:217:26
+ |
+LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| fp.field.is_power_of_two())`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:218:26
+ |
+LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_1(fp.field))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:219:26
+ |
+LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))`
+
+error: aborting due to 44 previous errors
+
x.split('💣');
// Can't use this lint for unicode code points which don't fit in a char
x.split("❤️");
+ x.split_inclusive('x');
x.contains('x');
x.starts_with('x');
x.ends_with('x');
x.rsplit_terminator('x');
x.splitn(2, 'x');
x.rsplitn(2, 'x');
+ x.split_once('x');
+ x.rsplit_once('x');
x.matches('x');
x.rmatches('x');
x.match_indices('x');
x.trim_end_matches('x');
x.strip_prefix('x');
x.strip_suffix('x');
+ x.replace('x', "y");
+ x.replacen('x', "y", 3);
// Make sure we escape characters correctly.
x.split('\n');
x.split('\'');
let h = HashSet::<String>::new();
h.contains("X"); // should not warn
- x.replace(";", ",").split(','); // issue #2978
+ x.replace(';', ",").split(','); // issue #2978
x.starts_with('\x03'); // issue #2996
// Issue #3204
x.split('a');
x.split('\'');
x.split('#');
+ // Must escape backslash in raw strings when converting to char #8060
+ x.split('\\');
+ x.split('\\');
}
x.split("💣");
// Can't use this lint for unicode code points which don't fit in a char
x.split("❤️");
+ x.split_inclusive("x");
x.contains("x");
x.starts_with("x");
x.ends_with("x");
x.rsplit_terminator("x");
x.splitn(2, "x");
x.rsplitn(2, "x");
+ x.split_once("x");
+ x.rsplit_once("x");
x.matches("x");
x.rmatches("x");
x.match_indices("x");
x.trim_end_matches("x");
x.strip_prefix("x");
x.strip_suffix("x");
+ x.replace("x", "y");
+ x.replacen("x", "y", 3);
// Make sure we escape characters correctly.
x.split("\n");
x.split("'");
let h = HashSet::<String>::new();
h.contains("X"); // should not warn
- x.replace(";", ",").split(","); // issue #2978
+ x.replace(';', ",").split(","); // issue #2978
x.starts_with("\x03"); // issue #2996
// Issue #3204
x.split(r###"a"###);
x.split(r###"'"###);
x.split(r###"#"###);
+ // Must escape backslash in raw strings when converting to char #8060
+ x.split(r#"\"#);
+ x.split(r"\");
}
| ^^^^ help: try using a `char` instead: `'💣'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:20:16
+ --> $DIR/single_char_pattern.rs:20:23
+ |
+LL | x.split_inclusive("x");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:21:16
|
LL | x.contains("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:21:19
+ --> $DIR/single_char_pattern.rs:22:19
|
LL | x.starts_with("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:22:17
+ --> $DIR/single_char_pattern.rs:23:17
|
LL | x.ends_with("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:23:12
+ --> $DIR/single_char_pattern.rs:24:12
|
LL | x.find("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:24:13
+ --> $DIR/single_char_pattern.rs:25:13
|
LL | x.rfind("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:25:14
+ --> $DIR/single_char_pattern.rs:26:14
|
LL | x.rsplit("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:26:24
+ --> $DIR/single_char_pattern.rs:27:24
|
LL | x.split_terminator("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:27:25
+ --> $DIR/single_char_pattern.rs:28:25
|
LL | x.rsplit_terminator("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:28:17
+ --> $DIR/single_char_pattern.rs:29:17
|
LL | x.splitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:29:18
+ --> $DIR/single_char_pattern.rs:30:18
|
LL | x.rsplitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:30:15
+ --> $DIR/single_char_pattern.rs:31:18
+ |
+LL | x.split_once("x");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:32:19
+ |
+LL | x.rsplit_once("x");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:33:15
|
LL | x.matches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:31:16
+ --> $DIR/single_char_pattern.rs:34:16
|
LL | x.rmatches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:32:21
+ --> $DIR/single_char_pattern.rs:35:21
|
LL | x.match_indices("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:33:22
+ --> $DIR/single_char_pattern.rs:36:22
|
LL | x.rmatch_indices("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:34:26
+ --> $DIR/single_char_pattern.rs:37:26
|
LL | x.trim_start_matches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:35:24
+ --> $DIR/single_char_pattern.rs:38:24
|
LL | x.trim_end_matches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:36:20
+ --> $DIR/single_char_pattern.rs:39:20
|
LL | x.strip_prefix("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:37:20
+ --> $DIR/single_char_pattern.rs:40:20
|
LL | x.strip_suffix("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:39:13
+ --> $DIR/single_char_pattern.rs:41:15
+ |
+LL | x.replace("x", "y");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:42:16
+ |
+LL | x.replacen("x", "y", 3);
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:44:13
|
LL | x.split("/n");
| ^^^^ help: try using a `char` instead: `'/n'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:40:13
+ --> $DIR/single_char_pattern.rs:45:13
|
LL | x.split("'");
| ^^^ help: try using a `char` instead: `'/''`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:41:13
+ --> $DIR/single_char_pattern.rs:46:13
|
LL | x.split("/'");
| ^^^^ help: try using a `char` instead: `'/''`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:46:31
+ --> $DIR/single_char_pattern.rs:51:31
|
-LL | x.replace(";", ",").split(","); // issue #2978
+LL | x.replace(';', ",").split(","); // issue #2978
| ^^^ help: try using a `char` instead: `','`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:47:19
+ --> $DIR/single_char_pattern.rs:52:19
|
LL | x.starts_with("/x03"); // issue #2996
| ^^^^^^ help: try using a `char` instead: `'/x03'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:54:13
+ --> $DIR/single_char_pattern.rs:59:13
|
LL | x.split(r"a");
| ^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:55:13
+ --> $DIR/single_char_pattern.rs:60:13
|
LL | x.split(r#"a"#);
| ^^^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:56:13
+ --> $DIR/single_char_pattern.rs:61:13
|
LL | x.split(r###"a"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:57:13
+ --> $DIR/single_char_pattern.rs:62:13
|
LL | x.split(r###"'"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'/''`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:58:13
+ --> $DIR/single_char_pattern.rs:63:13
|
LL | x.split(r###"#"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'#'`
-error: aborting due to 32 previous errors
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:65:13
+ |
+LL | x.split(r#"/"#);
+ | ^^^^^^ help: try using a `char` instead: `'/'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:66:13
+ |
+LL | x.split(r"/");
+ | ^^^^ help: try using a `char` instead: `'/'`
+
+error: aborting due to 39 previous errors
--- /dev/null
+// run-rustfix
+
+#![warn(clippy::strlen_on_c_strings)]
+#![allow(dead_code)]
+#![feature(rustc_private)]
+extern crate libc;
+
+#[allow(unused)]
+use libc::strlen;
+use std::ffi::{CStr, CString};
+
+fn main() {
+ // CString
+ let cstring = CString::new("foo").expect("CString::new failed");
+ let _ = cstring.as_bytes().len();
+
+ // CStr
+ let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ let _ = cstr.to_bytes().len();
+
+ let _ = cstr.to_bytes().len();
+
+ let pcstr: *const &CStr = &cstr;
+ let _ = unsafe { (*pcstr).to_bytes().len() };
+
+ unsafe fn unsafe_identity<T>(x: T) -> T {
+ x
+ }
+ let _ = unsafe { unsafe_identity(cstr).to_bytes().len() };
+ let _ = unsafe { unsafe_identity(cstr) }.to_bytes().len();
+
+ let f: unsafe fn(_) -> _ = unsafe_identity;
+ let _ = unsafe { f(cstr).to_bytes().len() };
+}
+// run-rustfix
+
#![warn(clippy::strlen_on_c_strings)]
#![allow(dead_code)]
#![feature(rustc_private)]
extern crate libc;
+#[allow(unused)]
+use libc::strlen;
use std::ffi::{CStr, CString};
fn main() {
// CString
let cstring = CString::new("foo").expect("CString::new failed");
- let len = unsafe { libc::strlen(cstring.as_ptr()) };
+ let _ = unsafe { libc::strlen(cstring.as_ptr()) };
// CStr
let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- let len = unsafe { libc::strlen(cstr.as_ptr()) };
+ let _ = unsafe { libc::strlen(cstr.as_ptr()) };
+
+ let _ = unsafe { strlen(cstr.as_ptr()) };
+
+ let pcstr: *const &CStr = &cstr;
+ let _ = unsafe { strlen((*pcstr).as_ptr()) };
+
+ unsafe fn unsafe_identity<T>(x: T) -> T {
+ x
+ }
+ let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) };
+ let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) };
+
+ let f: unsafe fn(_) -> _ = unsafe_identity;
+ let _ = unsafe { strlen(f(cstr).as_ptr()) };
}
error: using `libc::strlen` on a `CString` or `CStr` value
- --> $DIR/strlen_on_c_strings.rs:11:24
+ --> $DIR/strlen_on_c_strings.rs:15:13
|
-LL | let len = unsafe { libc::strlen(cstring.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstring.as_bytes().len()`
|
= note: `-D clippy::strlen-on-c-strings` implied by `-D warnings`
-help: try this (you might also need to get rid of `unsafe` block in some cases):
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:19:13
+ |
+LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:21:13
+ |
+LL | let _ = unsafe { strlen(cstr.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:24:22
|
-LL | let len = unsafe { cstring.as_bytes().len() };
- | ~~~~~~~~~~~~~~~~~~~~~~~~
+LL | let _ = unsafe { strlen((*pcstr).as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*pcstr).to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
- --> $DIR/strlen_on_c_strings.rs:15:24
+ --> $DIR/strlen_on_c_strings.rs:29:22
|
-LL | let len = unsafe { libc::strlen(cstr.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe_identity(cstr).to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:30:13
|
-help: try this (you might also need to get rid of `unsafe` block in some cases):
+LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe { unsafe_identity(cstr) }.to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:33:22
|
-LL | let len = unsafe { cstr.to_bytes().len() };
- | ~~~~~~~~~~~~~~~~~~~~~
+LL | let _ = unsafe { strlen(f(cstr).as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `f(cstr).to_bytes().len()`
-error: aborting due to 2 previous errors
+error: aborting due to 7 previous errors
print!("\u{DC}ben!"); // this is ok
}
+// issue 8013
+#[warn(clippy::non_ascii_literal)]
+fn single_quote() {
+ const _EMPTY_BLOCK: char = '▱';
+ const _FULL_BLOCK: char = '▰';
+}
+
fn main() {
zero();
uni();
canon();
+ single_quote();
}
|
= note: `-D clippy::non-ascii-literal` implied by `-D warnings`
-error: aborting due to 5 previous errors
+error: literal non-ASCII character detected
+ --> $DIR/unicode.rs:26:32
+ |
+LL | const _EMPTY_BLOCK: char = '▱';
+ | ^^^ help: consider replacing the string with: `'/u{25b1}'`
+
+error: literal non-ASCII character detected
+ --> $DIR/unicode.rs:27:31
+ |
+LL | const _FULL_BLOCK: char = '▰';
+ | ^^^ help: consider replacing the string with: `'/u{25b0}'`
+
+error: aborting due to 7 previous errors
]
[assign]
+
+# Allows shortcuts like `@rustbot ready`
+#
+# See https://github.com/rust-lang/triagebot/wiki/Shortcuts
+[shortcut]
</h2>
</header>
- <ul class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
+ <div class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
<div class="list-group-item lint-doc-md" ng-bind-html="lint.docs | markdown"></div>
<div class="lint-additional-info-container">
<!-- Applicability -->
<a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a>
</div>
</div>
- </ul>
+ </div>
</article>
</div>
</div>