[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
+[`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow
[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
# Clippy
-[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
+[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](#license)
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
use rustc_hir::{
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
};
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
-use rustc_span::sym;
use rustc_span::symbol::Symbol;
+use rustc_span::{sym, DUMMY_SP};
use semver::Version;
static UNIX_SYSTEMS: &[&str] = &[
]);
impl<'tcx> LateLintPass<'tcx> for Attributes {
+ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+ for (name, level) in &cx.sess().opts.lint_opts {
+ if name == "clippy::restriction" && *level > Level::Allow {
+ span_lint_and_then(
+ cx,
+ BLANKET_CLIPPY_RESTRICTION_LINTS,
+ DUMMY_SP,
+ "`clippy::restriction` is not meant to be enabled as a group",
+ |diag| {
+ diag.note(format!(
+ "because of the command line `--{} clippy::restriction`",
+ level.as_str()
+ ));
+ diag.help("enable the restriction lints you need individually");
+ },
+ );
+ }
+ }
+ }
+
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
if let Some(items) = &attr.meta_item_list() {
if let Some(ident) = attr.ident() {
cx,
BLANKET_CLIPPY_RESTRICTION_LINTS,
lint.span(),
- "restriction lints are not meant to be all enabled",
+ "`clippy::restriction` is not meant to be enabled as a group",
None,
- "try enabling only the lints you really need",
+ "enable the restriction lints you need individually",
);
}
}
+use clippy_utils::higher::If;
use rustc_ast::LitKind;
use rustc_hir::{Block, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, is_integer_literal, sugg::Sugg};
+use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg};
use rustc_errors::Applicability;
declare_clippy_lint! {
declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
- fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
- if !expr.span.from_expansion() {
- check_if_else(ctx, expr);
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+ if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
+ check_if_else(cx, expr);
}
}
}
-fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
- if let ExprKind::If(check, then, Some(else_)) = expr.kind
+fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+ if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr)
&& let Some(then_lit) = int_literal(then)
- && let Some(else_lit) = int_literal(else_)
+ && let Some(else_lit) = int_literal(r#else)
{
let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
false
};
let mut applicability = Applicability::MachineApplicable;
let snippet = {
- let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &mut applicability);
+ let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
if inverted {
sugg = !sugg;
}
sugg
};
- let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+ let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
let suggestion = {
- let wrap_in_curly = is_else_clause(ctx.tcx, expr);
+ let wrap_in_curly = is_else_clause(cx.tcx, expr);
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
if wrap_in_curly {
s = s.blockify();
let into_snippet = snippet.clone().maybe_par();
let as_snippet = snippet.as_ty(ty);
- span_lint_and_then(ctx,
+ span_lint_and_then(cx,
BOOL_TO_INT_WITH_IF,
expr.span,
"boolean to int conversion using if",
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
+ crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
crate::swap::ALMOST_SWAPPED_INFO,
crate::swap::MANUAL_SWAP_INFO,
crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,
};
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
&& !place.has_deref()
+ // Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
+ && TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
{
let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
if possible_borrowers
mod strlen_on_c_strings;
mod suspicious_operation_groupings;
mod suspicious_trait_impl;
+mod suspicious_xor_used_as_pow;
mod swap;
mod swap_ptr_to_ref;
mod tabs_in_doc_comments;
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
+ store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
// add lints here, do not remove this comment, it's used in `new_lint`
}
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
let ret_ty = return_ty(cx, impl_item.hir_id());
- // walk the return type and check for Self (this does not check associated types)
- if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(ret_ty, self_adt) {
- return;
- }
- } else if ret_ty.contains(self_ty) {
+ if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
return;
}
- // if return type is impl trait, check the associated types
- if let ty::Opaque(def_id, _) = *ret_ty.kind() {
- // one of the associated types must be Self
- for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
- if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
- let assoc_ty = match projection_predicate.term.unpack() {
- ty::TermKind::Ty(ty) => ty,
- ty::TermKind::Const(_c) => continue,
- };
- // walk the associated type and check for Self
- if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(assoc_ty, self_adt) {
- return;
- }
- } else if assoc_ty.contains(self_ty) {
- return;
- }
- }
- }
- }
-
if name == "new" && ret_ty != self_ty {
span_lint(
cx,
let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if *self_ty.kind() == ty::Str {
- ""
+ if matches!(target.kind, hir::ExprKind::Index(..)) {
+ "&"
+ } else {
+ ""
+ }
} else if is_type_diagnostic_item(cx, self_ty, sym::String) {
"&"
} else {
cx: &LateContext<'tcx>,
arms: &[Arm<'tcx>],
) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
- if arms.len() == 2 {
- return if is_none_or_err_arm(cx, &arms[1]) {
- Some((arms[0].pat, arms[0].body, arms[1].body))
- } else if is_none_or_err_arm(cx, &arms[0]) {
- Some((arms[1].pat, arms[1].body, arms[0].body))
+ if let [first_arm, second_arm] = arms
+ && first_arm.guard.is_none()
+ && second_arm.guard.is_none()
+ {
+ return if is_none_or_err_arm(cx, second_arm) {
+ Some((first_arm.pat, first_arm.body, second_arm.body))
+ } else if is_none_or_err_arm(cx, first_arm) {
+ Some((second_arm.pat, second_arm.body, first_arm.body))
} else {
None
};
--- /dev/null
+use clippy_utils::{numeric_literal::NumericLiteral, source::snippet_with_context};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
+ /// ### Why is this bad?
+ /// It's most probably a typo and may lead to unexpected behaviours.
+ /// ### Example
+ /// ```rust
+ /// let x = 3_i32 ^ 4_i32;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let x = 3_i32.pow(4);
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub SUSPICIOUS_XOR_USED_AS_POW,
+ restriction,
+ "XOR (`^`) operator possibly used as exponentiation operator"
+}
+declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
+
+impl LateLintPass<'_> for ConfusingXorAndPow {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if !in_external_macro(cx.sess(), expr.span) &&
+ let ExprKind::Binary(op, left, right) = &expr.kind &&
+ op.node == BinOpKind::BitXor &&
+ left.span.ctxt() == right.span.ctxt() &&
+ let ExprKind::Lit(lit_left) = &left.kind &&
+ let ExprKind::Lit(lit_right) = &right.kind &&
+ let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
+ let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
+ let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
+ let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
+ left_val.is_decimal() &&
+ right_val.is_decimal() {
+ clippy_utils::diagnostics::span_lint_and_sugg(
+ cx,
+ SUSPICIOUS_XOR_USED_AS_POW,
+ expr.span,
+ "`^` is not the exponentiation operator",
+ "did you mean to write",
+ format!("{}.pow({})", left_val.format(), right_val.format()),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+}
&& !in_external_macro(cx.tcx.sess, block.span)
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
&& !is_unsafe_from_proc_macro(cx, block.span)
- && !block_has_safety_comment(cx, block)
+ && !block_has_safety_comment(cx, block.span)
+ && !block_parents_have_safety_comment(cx, block.hir_id)
{
let source_map = cx.tcx.sess.source_map();
let span = if source_map.is_multiline(block.span) {
.map_or(true, |src| !src.starts_with("unsafe"))
}
+// Checks if any parent {expression, statement, block, local, const, static}
+// has a safety comment
+fn block_parents_have_safety_comment(cx: &LateContext<'_>, id: hir::HirId) -> bool {
+ if let Some(node) = get_parent_node(cx.tcx, id) {
+ return match node {
+ Node::Expr(expr) => !is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span),
+ Node::Stmt(hir::Stmt {
+ kind:
+ hir::StmtKind::Local(hir::Local { span, .. })
+ | hir::StmtKind::Expr(hir::Expr { span, .. })
+ | hir::StmtKind::Semi(hir::Expr { span, .. }),
+ ..
+ })
+ | Node::Local(hir::Local { span, .. })
+ | Node::Item(hir::Item {
+ kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+ span,
+ ..
+ }) => span_in_body_has_safety_comment(cx, *span),
+ _ => false,
+ };
+ }
+ false
+}
+
+/// Checks if an expression is "branchy", e.g. loop, match/if/etc.
+fn is_branchy(expr: &hir::Expr<'_>) -> bool {
+ matches!(
+ expr.kind,
+ hir::ExprKind::If(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..)
+ )
+}
+
/// Checks if the lines immediately preceding the block contain a safety comment.
-fn block_has_safety_comment(cx: &LateContext<'_>, block: &hir::Block<'_>) -> bool {
+fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
// This intentionally ignores text before the start of a function so something like:
// ```
// // SAFETY: reason
// won't work. This is to avoid dealing with where such a comment should be place relative to
// attributes and doc comments.
- span_from_macro_expansion_has_safety_comment(cx, block.span) || span_in_body_has_safety_comment(cx, block.span)
+ span_from_macro_expansion_has_safety_comment(cx, span) || span_in_body_has_safety_comment(cx, span)
}
/// Checks if the lines immediately preceding the item contain a safety comment.
})
}
+/// Walks into `ty` and returns `true` if any inner type is an instance of the given type, or adt
+/// constructor of the same type.
+///
+/// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U`
+/// will also return `true`.
+pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool {
+ ty.walk().any(|inner| match inner.unpack() {
+ GenericArgKind::Type(inner_ty) => {
+ if inner_ty == needle {
+ return true;
+ }
+
+ if inner_ty.ty_adt_def() == needle.ty_adt_def() {
+ return true;
+ }
+
+ if let ty::Opaque(def_id, _) = *inner_ty.kind() {
+ for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
+ match predicate.kind().skip_binder() {
+ // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
+ // and check substituions to find `U`.
+ ty::PredicateKind::Trait(trait_predicate) => {
+ if trait_predicate
+ .trait_ref
+ .substs
+ .types()
+ .skip(1) // Skip the implicit `Self` generic parameter
+ .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle))
+ {
+ return true;
+ }
+ },
+ // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
+ // so we check the term for `U`.
+ ty::PredicateKind::Projection(projection_predicate) => {
+ if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
+ if contains_ty_adt_constructor_opaque(cx, ty, needle) {
+ return true;
+ }
+ };
+ },
+ _ => (),
+ }
+ }
+ }
+
+ false
+ },
+ GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+ })
+}
+
/// Resolves `<T as Iterator>::Item` for `T`
/// Do not invoke without first verifying that the type implements `Iterator`
pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+// compile-flags: -W clippy::restriction
+
#![warn(clippy::blanket_clippy_restriction_lints)]
//! Test that the whole restriction group is not enabled
-error: restriction lints are not meant to be all enabled
- --> $DIR/blanket_clippy_restriction_lints.rs:4:9
+error: `clippy::restriction` is not meant to be enabled as a group
+ |
+ = note: because of the command line `--warn clippy::restriction`
+ = help: enable the restriction lints you need individually
+ = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+
+error: `clippy::restriction` is not meant to be enabled as a group
+ --> $DIR/blanket_clippy_restriction_lints.rs:6:9
|
LL | #![warn(clippy::restriction)]
| ^^^^^^^^^^^^^^^^^^^
|
- = help: try enabling only the lints you really need
- = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+ = help: enable the restriction lints you need individually
-error: restriction lints are not meant to be all enabled
- --> $DIR/blanket_clippy_restriction_lints.rs:5:9
+error: `clippy::restriction` is not meant to be enabled as a group
+ --> $DIR/blanket_clippy_restriction_lints.rs:7:9
|
LL | #![deny(clippy::restriction)]
| ^^^^^^^^^^^^^^^^^^^
|
- = help: try enabling only the lints you really need
+ = help: enable the restriction lints you need individually
-error: restriction lints are not meant to be all enabled
- --> $DIR/blanket_clippy_restriction_lints.rs:6:11
+error: `clippy::restriction` is not meant to be enabled as a group
+ --> $DIR/blanket_clippy_restriction_lints.rs:8:11
|
LL | #![forbid(clippy::restriction)]
| ^^^^^^^^^^^^^^^^^^^
|
- = help: try enabling only the lints you really need
+ = help: enable the restriction lints you need individually
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
// run-rustfix
+#![feature(let_chains)]
#![warn(clippy::bool_to_int_with_if)]
#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
123
};
+ pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
+
some_fn(a);
}
fn cond(a: bool, b: bool) -> bool {
a || b
}
+
+enum Enum {
+ A,
+ B,
+}
+
+fn if_let(a: Enum, b: Enum) {
+ if let Enum::A = a {
+ 1
+ } else {
+ 0
+ };
+
+ if let Enum::A = a && let Enum::B = b {
+ 1
+ } else {
+ 0
+ };
+}
// run-rustfix
+#![feature(let_chains)]
#![warn(clippy::bool_to_int_with_if)]
#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
123
};
+ pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
+
some_fn(a);
}
fn cond(a: bool, b: bool) -> bool {
a || b
}
+
+enum Enum {
+ A,
+ B,
+}
+
+fn if_let(a: Enum, b: Enum) {
+ if let Enum::A = a {
+ 1
+ } else {
+ 0
+ };
+
+ if let Enum::A = a && let Enum::B = b {
+ 1
+ } else {
+ 0
+ };
+}
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:15:5
+ --> $DIR/bool_to_int_with_if.rs:16:5
|
LL | / if a {
LL | | 1
= note: `-D clippy::bool-to-int-with-if` implied by `-D warnings`
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:20:5
+ --> $DIR/bool_to_int_with_if.rs:21:5
|
LL | / if a {
LL | | 0
= note: `!a as i32` or `(!a).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:25:5
+ --> $DIR/bool_to_int_with_if.rs:26:5
|
LL | / if !a {
LL | | 1
= note: `!a as i32` or `(!a).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:30:5
+ --> $DIR/bool_to_int_with_if.rs:31:5
|
LL | / if a || b {
LL | | 1
= note: `(a || b) as i32` or `(a || b).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:35:5
+ --> $DIR/bool_to_int_with_if.rs:36:5
|
LL | / if cond(a, b) {
LL | | 1
= note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:40:5
+ --> $DIR/bool_to_int_with_if.rs:41:5
|
LL | / if x + y < 4 {
LL | | 1
= note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:49:12
+ --> $DIR/bool_to_int_with_if.rs:50:12
|
LL | } else if b {
| ____________^
= note: `b as i32` or `b.into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:58:12
+ --> $DIR/bool_to_int_with_if.rs:59:12
|
LL | } else if b {
| ____________^
= note: `!b as i32` or `(!b).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:116:5
+ --> $DIR/bool_to_int_with_if.rs:119:5
|
LL | if a { 1 } else { 0 }
| ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
#![warn(clippy::eq_op)]
#![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)]
+#![allow(clippy::suspicious_xor_used_as_pow)]
fn main() {
// simple values and comparisons
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:8:13
+ --> $DIR/eq_op.rs:9:13
|
LL | let _ = 1 == 1;
| ^^^^^^
= note: `-D clippy::eq-op` implied by `-D warnings`
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:9:13
+ --> $DIR/eq_op.rs:10:13
|
LL | let _ = "no" == "no";
| ^^^^^^^^^^^^
error: equal expressions as operands to `!=`
- --> $DIR/eq_op.rs:11:13
+ --> $DIR/eq_op.rs:12:13
|
LL | let _ = false != false;
| ^^^^^^^^^^^^^^
error: equal expressions as operands to `<`
- --> $DIR/eq_op.rs:12:13
+ --> $DIR/eq_op.rs:13:13
|
LL | let _ = 1.5 < 1.5;
| ^^^^^^^^^
error: equal expressions as operands to `>=`
- --> $DIR/eq_op.rs:13:13
+ --> $DIR/eq_op.rs:14:13
|
LL | let _ = 1u64 >= 1u64;
| ^^^^^^^^^^^^
error: equal expressions as operands to `&`
- --> $DIR/eq_op.rs:16:13
+ --> $DIR/eq_op.rs:17:13
|
LL | let _ = (1u32 as u64) & (1u32 as u64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `^`
- --> $DIR/eq_op.rs:19:17
+ --> $DIR/eq_op.rs:20:17
|
LL | let _ = 1 ^ ((((((1))))));
| ^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `<`
- --> $DIR/eq_op.rs:23:13
+ --> $DIR/eq_op.rs:24:13
|
LL | let _ = (-(2) < -(2));
| ^^^^^^^^^^^^^
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:24:13
+ --> $DIR/eq_op.rs:25:13
|
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `&`
- --> $DIR/eq_op.rs:24:14
+ --> $DIR/eq_op.rs:25:14
|
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
| ^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `&`
- --> $DIR/eq_op.rs:24:35
+ --> $DIR/eq_op.rs:25:35
|
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
| ^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:25:13
+ --> $DIR/eq_op.rs:26:13
|
LL | let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `!=`
- --> $DIR/eq_op.rs:28:13
+ --> $DIR/eq_op.rs:29:13
|
LL | let _ = ([1] != [1]);
| ^^^^^^^^^^^^
error: equal expressions as operands to `!=`
- --> $DIR/eq_op.rs:29:13
+ --> $DIR/eq_op.rs:30:13
|
LL | let _ = ((1, 2) != (1, 2));
| ^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:33:13
+ --> $DIR/eq_op.rs:34:13
|
LL | let _ = 1 + 1 == 2;
| ^^^^^^^^^^
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:34:13
+ --> $DIR/eq_op.rs:35:13
|
LL | let _ = 1 - 1 == 0;
| ^^^^^^^^^^
error: equal expressions as operands to `-`
- --> $DIR/eq_op.rs:34:13
+ --> $DIR/eq_op.rs:35:13
|
LL | let _ = 1 - 1 == 0;
| ^^^^^
error: equal expressions as operands to `-`
- --> $DIR/eq_op.rs:36:13
+ --> $DIR/eq_op.rs:37:13
|
LL | let _ = 1 - 1;
| ^^^^^
error: equal expressions as operands to `/`
- --> $DIR/eq_op.rs:37:13
+ --> $DIR/eq_op.rs:38:13
|
LL | let _ = 1 / 1;
| ^^^^^
error: equal expressions as operands to `&&`
- --> $DIR/eq_op.rs:38:13
+ --> $DIR/eq_op.rs:39:13
|
LL | let _ = true && true;
| ^^^^^^^^^^^^
error: equal expressions as operands to `||`
- --> $DIR/eq_op.rs:40:13
+ --> $DIR/eq_op.rs:41:13
|
LL | let _ = true || true;
| ^^^^^^^^^^^^
error: equal expressions as operands to `&&`
- --> $DIR/eq_op.rs:45:13
+ --> $DIR/eq_op.rs:46:13
|
LL | let _ = a == b && b == a;
| ^^^^^^^^^^^^^^^^
error: equal expressions as operands to `&&`
- --> $DIR/eq_op.rs:46:13
+ --> $DIR/eq_op.rs:47:13
|
LL | let _ = a != b && b != a;
| ^^^^^^^^^^^^^^^^
error: equal expressions as operands to `&&`
- --> $DIR/eq_op.rs:47:13
+ --> $DIR/eq_op.rs:48:13
|
LL | let _ = a < b && b > a;
| ^^^^^^^^^^^^^^
error: equal expressions as operands to `&&`
- --> $DIR/eq_op.rs:48:13
+ --> $DIR/eq_op.rs:49:13
|
LL | let _ = a <= b && b >= a;
| ^^^^^^^^^^^^^^^^
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:51:13
+ --> $DIR/eq_op.rs:52:13
|
LL | let _ = a == a;
| ^^^^^^
error: equal expressions as operands to `/`
- --> $DIR/eq_op.rs:61:20
+ --> $DIR/eq_op.rs:62:20
|
LL | const D: u32 = A / A;
| ^^^^^
error: equal expressions as operands to `==`
- --> $DIR/eq_op.rs:92:5
+ --> $DIR/eq_op.rs:93:5
|
LL | (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
a.extend(&[]); // vs a.extend([]);
}
}
+
+#[allow(dead_code)]
+mod issue_9710 {
+ fn main() {
+ let string = String::new();
+ for _i in 0..10 {
+ f(&string);
+ }
+ }
+
+ fn f<T: AsRef<str>>(_: T) {}
+}
a.extend(&[]); // vs a.extend([]);
}
}
+
+#[allow(dead_code)]
+mod issue_9710 {
+ fn main() {
+ let string = String::new();
+ for _i in 0..10 {
+ f(&string);
+ }
+ }
+
+ fn f<T: AsRef<str>>(_: T) {}
+}
RetOtherSelf(RetOtherSelfWrapper(t))
}
}
+
+mod issue7344 {
+ struct RetImplTraitSelf<T>(T);
+
+ impl<T> RetImplTraitSelf<T> {
+ // should not trigger lint
+ fn new(t: T) -> impl Into<Self> {
+ Self(t)
+ }
+ }
+
+ struct RetImplTraitNoSelf<T>(T);
+
+ impl<T> RetImplTraitNoSelf<T> {
+ // should trigger lint
+ fn new(t: T) -> impl Into<i32> {
+ 1
+ }
+ }
+
+ trait Trait2<T, U> {}
+ impl<T, U> Trait2<T, U> for () {}
+
+ struct RetImplTraitSelf2<T>(T);
+
+ impl<T> RetImplTraitSelf2<T> {
+ // should not trigger lint
+ fn new(t: T) -> impl Trait2<(), Self> {
+ unimplemented!()
+ }
+ }
+
+ struct RetImplTraitNoSelf2<T>(T);
+
+ impl<T> RetImplTraitNoSelf2<T> {
+ // should trigger lint
+ fn new(t: T) -> impl Trait2<(), i32> {
+ unimplemented!()
+ }
+ }
+
+ struct RetImplTraitSelfAdt<'a>(&'a str);
+
+ impl<'a> RetImplTraitSelfAdt<'a> {
+ // should not trigger lint
+ fn new<'b: 'a>(s: &'b str) -> impl Into<RetImplTraitSelfAdt<'b>> {
+ RetImplTraitSelfAdt(s)
+ }
+ }
+}
LL | | }
| |_________^
-error: aborting due to 10 previous errors
+error: methods called `new` usually return `Self`
+ --> $DIR/new_ret_no_self.rs:368:9
+ |
+LL | / fn new(t: T) -> impl Into<i32> {
+LL | | 1
+LL | | }
+ | |_________^
+
+error: methods called `new` usually return `Self`
+ --> $DIR/new_ret_no_self.rs:389:9
+ |
+LL | / fn new(t: T) -> impl Trait2<(), i32> {
+LL | | unimplemented!()
+LL | | }
+ | |_________^
+
+error: aborting due to 12 previous errors
let _ = res.map_or(1, |a| a + 1);
let _ = res.map_or(5, |a| a + 1);
}
+
+#[allow(dead_code)]
+fn issue9742() -> Option<&'static str> {
+ // should not lint because of guards
+ match Some("foo ") {
+ Some(name) if name.starts_with("foo") => Some(name.trim()),
+ _ => None,
+ }
+}
};
let _ = if let Ok(a) = res { a + 1 } else { 5 };
}
+
+#[allow(dead_code)]
+fn issue9742() -> Option<&'static str> {
+ // should not lint because of guards
+ match Some("foo ") {
+ Some(name) if name.starts_with("foo") => Some(name.trim()),
+ _ => None,
+ }
+}
let f = HasChars;
s.extend(f.chars());
+
+ // issue #9735
+ s.push_str(&abc[0..2]);
}
let f = HasChars;
s.extend(f.chars());
+
+ // issue #9735
+ s.extend(abc[0..2].chars());
}
LL | s.extend(def.chars());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)`
-error: aborting due to 3 previous errors
+error: calling `.extend(_.chars())`
+ --> $DIR/string_extend.rs:34:5
+ |
+LL | s.extend(abc[0..2].chars());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&abc[0..2])`
+
+error: aborting due to 4 previous errors
--- /dev/null
+#![allow(unused)]
+#![warn(clippy::suspicious_xor_used_as_pow)]
+#![allow(clippy::eq_op)]
+
+macro_rules! macro_test {
+ () => {
+ 13
+ };
+}
+
+macro_rules! macro_test_inside {
+ () => {
+ 1 ^ 2 // should warn even if inside macro
+ };
+}
+
+fn main() {
+ // Should warn:
+ let _ = 2 ^ 5;
+ let _ = 2i32 ^ 9i32;
+ let _ = 2i32 ^ 2i32;
+ let _ = 50i32 ^ 3i32;
+ let _ = 5i32 ^ 8i32;
+ let _ = 2i32 ^ 32i32;
+ macro_test_inside!();
+
+ // Should not warn:
+ let x = 0x02;
+ let _ = x ^ 2;
+ let _ = 2 ^ x;
+ let _ = x ^ 5;
+ let _ = 10 ^ 0b0101;
+ let _ = 2i32 ^ macro_test!();
+}
--- /dev/null
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:19:13
+ |
+LL | let _ = 2 ^ 5;
+ | ^^^^^ help: did you mean to write: `2.pow(5)`
+ |
+ = note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings`
+
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:20:13
+ |
+LL | let _ = 2i32 ^ 9i32;
+ | ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`
+
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:21:13
+ |
+LL | let _ = 2i32 ^ 2i32;
+ | ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`
+
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:22:13
+ |
+LL | let _ = 50i32 ^ 3i32;
+ | ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`
+
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:23:13
+ |
+LL | let _ = 5i32 ^ 8i32;
+ | ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`
+
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:24:13
+ |
+LL | let _ = 2i32 ^ 32i32;
+ | ^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(32_i32)`
+
+error: `^` is not the exponentiation operator
+ --> $DIR/suspicious_xor_used_as_pow.rs:13:9
+ |
+LL | 1 ^ 2 // should warn even if inside macro
+ | ^^^^^ help: did you mean to write: `1.pow(2)`
+...
+LL | macro_test_inside!();
+ | -------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `macro_test_inside` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
// SAFETY: ok
unsafe impl CrateRoot for (i32) {}
+fn issue_9142() {
+ // SAFETY: ok
+ let _ =
+ // we need this comment to avoid rustfmt putting
+ // it all on one line
+ unsafe {};
+
+ // SAFETY: this is more than one level away, so it should warn
+ let _ = {
+ if unsafe { true } {
+ todo!();
+ } else {
+ let bar = unsafe {};
+ todo!();
+ bar
+ }
+ };
+}
+
fn main() {}
|
= help: consider adding a safety comment on the preceding line
-error: aborting due to 31 previous errors
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:498:9
+ |
+LL | unsafe {};
+ | ^^^^^^^^^
+ |
+ = help: consider adding a safety comment on the preceding line
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:502:12
+ |
+LL | if unsafe { true } {
+ | ^^^^^^^^^^^^^^^
+ |
+ = help: consider adding a safety comment on the preceding line
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:505:23
+ |
+LL | let bar = unsafe {};
+ | ^^^^^^^^^
+ |
+ = help: consider adding a safety comment on the preceding line
+
+error: aborting due to 34 previous errors