Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones 2023-07-14 13:27:56 +02:00
commit 415fdb2d1a
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5
522 changed files with 5251 additions and 2556 deletions

View file

@ -1,7 +1,8 @@
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::peel_blocks;
use clippy_utils::source::{snippet, snippet_with_context};
use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
use clippy_utils::visitors::find_all_ret_expressions;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -87,7 +88,7 @@ pub(crate) trait BindInsteadOfMap {
BIND_INSTEAD_OF_MAP,
expr.span,
&msg,
"try this",
"try",
note,
app,
);
@ -124,7 +125,7 @@ pub(crate) trait BindInsteadOfMap {
span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
multispan_sugg_with_applicability(
diag,
"try this",
"try",
Applicability::MachineApplicable,
std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
suggs

View file

@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::source::{indent_of, reindent_multiline};
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_lang_item;
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext;
use rustc_span::{source_map::Spanned, Span};
use rustc_span::source_map::Spanned;
use rustc_span::Span;
use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;

View file

@ -4,8 +4,7 @@ use clippy_utils::{method_chain_args, path_def_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_lint::Lint;
use rustc_lint::{LateContext, Lint};
use rustc_middle::ty;
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.

View file

@ -5,8 +5,7 @@ use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_lint::Lint;
use rustc_lint::{LateContext, Lint};
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
pub(super) fn check(

View file

@ -5,7 +5,9 @@ use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::{self};
use rustc_span::symbol::{sym, Symbol};
use super::CLONE_ON_COPY;

View file

@ -42,7 +42,7 @@ pub(super) fn check(
CLONE_ON_REF_PTR,
expr.span,
"using `.clone()` on a ref-counted pointer",
"try this",
"try",
format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
app,
);

View file

@ -8,8 +8,7 @@ use rustc_hir as hir;
use rustc_lint::LateContext;
use std::collections::VecDeque;
use super::method_call;
use super::COLLAPSIBLE_STR_REPLACE;
use super::{method_call, COLLAPSIBLE_STR_REPLACE};
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,

View file

@ -4,17 +4,12 @@ use clippy_utils::is_range_full;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_hir::ExprKind;
use rustc_hir::LangItem;
use rustc_hir::Path;
use rustc_hir::QPath;
use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::query::Key;
use rustc_middle::ty;
use rustc_middle::ty::Ty;
use rustc_span::sym;
use rustc_span::Symbol;
use rustc_span::{sym, Symbol};
/// Checks if both types match the given diagnostic item, e.g.:
///

View file

@ -1,8 +1,7 @@
use super::ERR_EXPECT;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::has_debug_impl;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
use rustc_errors::Applicability;
use rustc_lint::LateContext;
use rustc_middle::ty;

View file

@ -144,7 +144,7 @@ pub(super) fn check<'tcx>(
EXPECT_FUN_CALL,
span_replace_word,
&format!("use of `{name}` followed by a function call"),
"try this",
"try",
format!("unwrap_or_else({closure_args} panic!({sugg}))"),
applicability,
);
@ -162,7 +162,7 @@ pub(super) fn check<'tcx>(
EXPECT_FUN_CALL,
span_replace_word,
&format!("use of `{name}` followed by a function call"),
"try this",
"try",
format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"),
applicability,
);

View file

@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
EXTEND_WITH_DRAIN,
expr.span,
"use of `extend` instead of `append` for adding the full range of a second vector",
"try this",
"try",
format!(
"{}.append({}{})",
snippet_with_applicability(cx, recv.span, "..", &mut applicability),

View file

@ -13,9 +13,7 @@ use rustc_span::source_map::Span;
use rustc_span::symbol::{sym, Symbol};
use std::borrow::Cow;
use super::MANUAL_FILTER_MAP;
use super::MANUAL_FIND_MAP;
use super::OPTION_FILTER_MAP;
use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
match &expr.kind {

View file

@ -3,7 +3,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::{source_map::Span, sym};
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::FILTER_MAP_IDENTITY;

View file

@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
FILTER_MAP_NEXT,
expr.span,
msg,
"try this",
"try",
format!("{iter_snippet}.find_map({filter_snippet})"),
Applicability::MachineApplicable,
);

View file

@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::implements_trait;
use rustc_ast::{BindingAnnotation, Mutability};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@ -8,6 +9,21 @@ use rustc_span::sym;
use super::FILTER_NEXT;
fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> {
match expr.kind {
hir::ExprKind::Field(f, _) => path_to_local(f),
hir::ExprKind::Index(recv, _) => path_to_local(recv),
hir::ExprKind::Path(hir::QPath::Resolved(
_,
hir::Path {
res: rustc_hir::def::Res::Local(local),
..
},
)) => Some(*local),
_ => None,
}
}
/// lint use of `filter().next()` for `Iterators`
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
@ -26,15 +42,30 @@ pub(super) fn check<'tcx>(
if filter_snippet.lines().count() <= 1 {
let iter_snippet = snippet(cx, recv.span, "..");
// add note if not multi-line
span_lint_and_sugg(
cx,
FILTER_NEXT,
expr.span,
msg,
"try this",
format!("{iter_snippet}.find({filter_snippet})"),
Applicability::MachineApplicable,
);
span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| {
let (applicability, pat) = if let Some(id) = path_to_local(recv)
&& let Some(hir::Node::Pat(pat)) = cx.tcx.hir().find(id)
&& let hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind
{
(Applicability::Unspecified, Some((pat.span, ident)))
} else {
(Applicability::MachineApplicable, None)
};
diag.span_suggestion(
expr.span,
"try",
format!("{iter_snippet}.find({filter_snippet})"),
applicability,
);
if let Some((pat_span, ident)) = pat {
diag.span_help(
pat_span,
format!("you will also need to make `{ident}` mutable, because `find` takes `&mut self`"),
);
}
});
} else {
span_lint(cx, FILTER_NEXT, expr.span, msg);
}

View file

@ -3,7 +3,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::{source_map::Span, sym};
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::FLAT_MAP_IDENTITY;

View file

@ -4,7 +4,8 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::{source_map::Span, sym};
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::FLAT_MAP_OPTION;
use clippy_utils::ty::is_type_diagnostic_item;

View file

@ -71,7 +71,7 @@ pub(super) fn check<'tcx>(
GET_UNWRAP,
span,
&format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
"try this",
"try",
format!(
"{borrow_str}{}[{get_args_str}]",
snippet_with_applicability(cx, recv.span, "..", &mut applicability)

View file

@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::{Symbol, sym};
use rustc_span::symbol::{sym, Symbol};
use super::INEFFICIENT_TO_STRING;

View file

@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_trait_method;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::{source_map::Span, sym};
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::INSPECT_FOR_EACH;

View file

@ -1,10 +1,10 @@
//! Lint for `c.is_digit(10)`
use super::IS_DIGIT_ASCII_RADIX;
use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{
consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability,
};
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;

View file

@ -9,8 +9,7 @@ use clippy_utils::visitors::is_local_used;
use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
use rustc_span::sym;
use rustc_span::Span;
use rustc_span::{sym, Span};
/// lint use of:
/// - `hashmap.iter().map(|(_, v)| v)`

View file

@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
if let Some(mut snip) = snippet_opt(cx, method_span) {
snip.push_str(trailing_clone);
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
diag.span_suggestion(replace_span, "try this", snip, Applicability::MachineApplicable);
diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
}
}
);

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_trait_method;
use clippy_utils::path_to_local;
use clippy_utils::source::snippet;
use clippy_utils::{is_trait_method, path_to_local};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{BindingAnnotation, Node, PatKind};

View file

@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
ITER_WITH_DRAIN,
span.with_hi(expr.span.hi()),
&format!("`drain(..)` used on a `{ty_name}`"),
"try this",
"try",
"into_iter()".to_string(),
Applicability::MaybeIncorrect,
);

View file

@ -21,13 +21,13 @@ pub fn check(
return;
}
let Some(mm) = is_min_or_max(cx, unwrap_arg) else { return };
let Some(mm) = is_min_or_max(cx, unwrap_arg) else {
return;
};
if ty.is_signed() {
use self::{
MinMax::{Max, Min},
Sign::{Neg, Pos},
};
use self::MinMax::{Max, Min};
use self::Sign::{Neg, Pos};
let Some(sign) = lit_sign(arith_rhs) else {
return;

View file

@ -88,7 +88,7 @@ pub(super) fn check(
MANUAL_STR_REPEAT,
collect_expr.span,
"manual implementation of `str::repeat` using iterators",
"try this",
"try",
format!("{val_str}.repeat({count_snip})"),
app
)

View file

@ -1,15 +1,11 @@
use clippy_utils::{
diagnostics::span_lint_and_sugg,
is_from_proc_macro,
msrvs::{Msrv, ITERATOR_TRY_FOLD},
source::snippet_opt,
ty::implements_trait,
};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_from_proc_macro;
use clippy_utils::msrvs::{Msrv, ITERATOR_TRY_FOLD};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::{
def::{DefKind, Res},
Expr, ExprKind,
};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_span::Span;

View file

@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr
MAP_COLLECT_RESULT_UNIT,
expr.span,
"`.map().collect()` can be replaced with `.try_for_each()`",
"try this",
"try",
format!(
"{}.try_for_each({})",
snippet(cx, iter.span, ".."),

View file

@ -6,7 +6,8 @@ use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::{symbol::sym, Span};
use rustc_span::symbol::sym;
use rustc_span::Span;
use super::MAP_FLATTEN;

View file

@ -4,7 +4,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::{source_map::Span, sym};
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::MAP_IDENTITY;

View file

@ -11,7 +11,8 @@ use rustc_span::symbol::sym;
use super::MAP_UNWRAP_OR;
/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
/// Return true if lint triggered
///
/// Returns true if the lint was emitted
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
@ -63,7 +64,7 @@ pub(super) fn check<'tcx>(
MAP_UNWRAP_OR,
expr.span,
msg,
"try this",
"try",
format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"),
Applicability::MachineApplicable,
);

View file

@ -72,6 +72,7 @@ mod or_fun_call;
mod or_then_unwrap;
mod path_buf_push_overwrite;
mod range_zip_with_len;
mod read_line_without_trim;
mod repeat_once;
mod search_is_some;
mod seek_from_current;
@ -88,6 +89,7 @@ mod suspicious_command_arg_space;
mod suspicious_map;
mod suspicious_splitn;
mod suspicious_to_owned;
mod type_id_on_box;
mod uninit_assumed_init;
mod unit_hash;
mod unnecessary_filter_map;
@ -2925,6 +2927,37 @@ declare_clippy_lint! {
"use of sort() when sort_unstable() is equivalent"
}
declare_clippy_lint! {
/// ### What it does
/// Looks for calls to `<Box<dyn Any> as Any>::type_id`.
///
/// ### Why is this bad?
/// This most certainly does not do what the user expects and is very easy to miss.
/// Calling `type_id` on a `Box<dyn Any>` calls `type_id` on the `Box<..>` itself,
/// so this will return the `TypeId` of the `Box<dyn Any>` type (not the type id
/// of the value referenced by the box!).
///
/// ### Example
/// ```rust,ignore
/// use std::any::{Any, TypeId};
///
/// let any_box: Box<dyn Any> = Box::new(42_i32);
/// assert_eq!(any_box.type_id(), TypeId::of::<i32>()); // ⚠️ this fails!
/// ```
/// Use instead:
/// ```rust
/// use std::any::{Any, TypeId};
///
/// let any_box: Box<dyn Any> = Box::new(42_i32);
/// assert_eq!((*any_box).type_id(), TypeId::of::<i32>());
/// // ^ dereference first, to call `type_id` on `dyn Any`
/// ```
#[clippy::version = "1.72.0"]
pub TYPE_ID_ON_BOX,
suspicious,
"calling `.type_id()` on `Box<dyn Any>`"
}
declare_clippy_lint! {
/// ### What it does
/// Detects `().hash(_)`.
@ -3316,6 +3349,35 @@ declare_clippy_lint! {
"checks for usage of `Iterator::fold` with a type that implements `Try`"
}
declare_clippy_lint! {
/// Looks for calls to [`Stdin::read_line`] to read a line from the standard input
/// into a string, then later attempting to parse this string into a type without first trimming it, which will
/// always fail because the string has a trailing newline in it.
///
/// ### Why is this bad?
/// The `.parse()` call will always fail.
///
/// ### Example
/// ```rust,ignore
/// let mut input = String::new();
/// std::io::stdin().read_line(&mut input).expect("Failed to read a line");
/// let num: i32 = input.parse().expect("Not a number!");
/// assert_eq!(num, 42); // we never even get here!
/// ```
/// Use instead:
/// ```rust,ignore
/// let mut input = String::new();
/// std::io::stdin().read_line(&mut input).expect("Failed to read a line");
/// let num: i32 = input.trim_end().parse().expect("Not a number!");
/// // ^^^^^^^^^^^ remove the trailing newline
/// assert_eq!(num, 42);
/// ```
#[clippy::version = "1.72.0"]
pub READ_LINE_WITHOUT_TRIM,
correctness,
"calling `Stdin::read_line`, then trying to parse it without first trimming"
}
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@ -3389,6 +3451,7 @@ impl_lint_pass!(Methods => [
STRING_EXTEND_CHARS,
ITER_CLONED_COLLECT,
ITER_WITH_DRAIN,
TYPE_ID_ON_BOX,
USELESS_ASREF,
UNNECESSARY_FOLD,
UNNECESSARY_FILTER_MAP,
@ -3435,6 +3498,7 @@ impl_lint_pass!(Methods => [
REPEAT_ONCE,
STABLE_SORT_PRIMITIVE,
UNIT_HASH,
READ_LINE_WITHOUT_TRIM,
UNNECESSARY_SORT_BY,
VEC_RESIZE_TO_ZERO,
VERBOSE_FILE_READS,
@ -3846,6 +3910,9 @@ impl Methods {
("read_to_string", [_]) => {
verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
},
("read_line", [arg]) => {
read_line_without_trim::check(cx, expr, recv, arg);
}
("repeat", [arg]) => {
repeat_once::check(cx, expr, recv, arg);
},
@ -3914,6 +3981,9 @@ impl Methods {
("to_os_string" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
("type_id", []) => {
type_id_on_box::check(cx, recv, expr.span);
}
("unwrap", []) => {
match method_call(recv) {
Some(("get", recv, [get_arg], _, _)) => {
@ -3949,7 +4019,7 @@ impl Methods {
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
("unwrap_or_default", []) => {
("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}
("unwrap_or_else", [u_arg]) => {
@ -4134,7 +4204,7 @@ impl SelfKind {
};
let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
return false
return false;
};
implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
}

View file

@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item};
use clippy_utils::expr_custom_deref_adjustment;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability};

View file

@ -4,10 +4,9 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
use clippy_utils::{
can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id,
CaptureKind,
can_move_expr_to_closure, fn_def_id, get_enclosing_block, get_parent_node, higher, is_trait_method, path_to_local,
path_to_local_id, CaptureKind,
};
use clippy_utils::{fn_def_id, higher};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};

View file

@ -17,7 +17,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
if name == "as_deref_mut" && recv.is_syntactic_place_expr() {
let Res::Local(binding_id) = path_res(cx, recv) else { return };
let Res::Local(binding_id) = path_res(cx, recv) else {
return;
};
if local_used_after_expr(cx, binding_id, recv) {
return;
@ -29,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
NEEDLESS_OPTION_AS_DEREF,
expr.span,
"derefed type is same as origin",
"try this",
"try",
snippet_opt(cx, recv.span).unwrap(),
Applicability::MachineApplicable,
);

View file

@ -1,5 +1,6 @@
use super::OBFUSCATED_IF_ELSE;
use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;

View file

@ -8,8 +8,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use super::OPTION_MAP_OR_NONE;
use super::RESULT_MAP_OR_INTO_OPTION;
use super::{OPTION_MAP_OR_NONE, RESULT_MAP_OR_INTO_OPTION};
// The expression inside a closure may or may not have surrounding braces
// which causes problems when generating a suggestion.

View file

@ -1,17 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_path, Visitor};
use rustc_hir::ExprKind;
use rustc_hir::Node;
use rustc_hir::PatKind;
use rustc_hir::QPath;
use rustc_hir::{self, HirId, Path};
use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_span::source_map::Span;

View file

@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
OR_FUN_CALL,
method_span.with_hi(span.hi()),
&format!("use of `{name}` followed by a call to `{path}`"),
"try this",
"try",
format!("{sugg}()"),
Applicability::MachineApplicable,
);
@ -139,7 +139,7 @@ pub(super) fn check<'tcx>(
OR_FUN_CALL,
span_replace_word,
&format!("use of `{name}` followed by a function call"),
"try this",
"try",
format!("{name}_{suffix}({sugg})"),
app,
);

View file

@ -1,8 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res};
use clippy_utils::{is_res_lang_ctor, path_res};
use rustc_errors::Applicability;
use rustc_hir::{lang_items::LangItem, Expr, ExprKind};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Span};
@ -50,7 +52,7 @@ pub(super) fn check<'tcx>(
OR_THEN_UNWRAP,
unwrap_expr.span.with_lo(or_span.lo()),
title,
"try this",
"try",
suggestion,
applicability,
);

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
use clippy_utils::{higher, SpanlessEq};
use clippy_utils::{is_integer_const, is_trait_method};
use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq};
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::LateContext;

View file

@ -0,0 +1,74 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, match_def_path};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
use rustc_span::sym;
use super::READ_LINE_WITHOUT_TRIM;
/// Will a `.parse::<ty>()` call fail if the input has a trailing newline?
fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
// only allow a very limited set of types for now, for which we 100% know parsing will fail
matches!(ty.kind(), ty::Float(_) | ty::Bool | ty::Int(_) | ty::Uint(_))
}
pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
&& match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"])
&& let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
&& let Res::Local(local_id) = path.res
{
// We've checked that `call` is a call to `Stdin::read_line()` with the right receiver,
// now let's check if the first use of the string passed to `::read_line()` is
// parsed into a type that will always fail if it has a trailing newline.
for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| {
if let Some(parent) = get_parent_expr(cx, expr)
&& let ExprKind::MethodCall(segment, .., span) = parent.kind
&& segment.ident.name == sym!(parse)
&& let parse_result_ty = cx.typeck_results().expr_ty(parent)
&& is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
&& let ty::Adt(_, substs) = parse_result_ty.kind()
&& let Some(ok_ty) = substs[0].as_type()
&& parse_fails_on_trailing_newline(ok_ty)
{
let local_snippet = snippet(cx, expr.span, "<expr>");
span_lint_and_then(
cx,
READ_LINE_WITHOUT_TRIM,
span,
"calling `.parse()` without trimming the trailing newline character",
|diag| {
diag.span_note(call.span, "call to `.read_line()` here, \
which leaves a trailing newline character in the buffer, \
which in turn will cause `.parse()` to fail");
diag.span_suggestion(
expr.span,
"try",
format!("{local_snippet}.trim_end()"),
Applicability::MachineApplicable,
);
}
);
}
// only consider the first use to prevent this scenario:
// ```
// let mut s = String::new();
// std::io::stdin().read_line(&mut s);
// s.pop();
// let _x: i32 = s.parse().unwrap();
// ```
// this is actually fine, because the pop call removes the trailing newline.
ControlFlow::<(), ()>::Break(())
});
}
}

View file

@ -3,10 +3,10 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use clippy_utils::{
diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability,
ty::implements_trait,
};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::{get_trait_def_id, match_def_path, paths};
use super::SEEK_FROM_CURRENT;

View file

@ -55,7 +55,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_
NEEDLESS_SPLITN,
expr.span,
&format!("unnecessary use of `{r}splitn`"),
"try this",
"try",
format!(
"{}.{r}split({})",
snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut app).0,
@ -110,7 +110,7 @@ fn check_manual_split_once(
IterUsageKind::Nth(_) => return,
};
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try", sugg, app);
}
/// checks for

View file

@ -34,7 +34,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
STRING_EXTEND_CHARS,
expr.span,
"calling `.extend(_.chars())`",
"try this",
"try",
format!(
"{}.push_str({ref_str}{})",
snippet_with_applicability(cx, recv.span, "..", &mut applicability),

View file

@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::paths;
use clippy_utils::ty::match_type;
use rustc_ast as ast;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::Span;
use {rustc_ast as ast, rustc_hir as hir};
use super::SUSPICIOUS_COMMAND_ARG_SPACE;

View file

@ -5,7 +5,8 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, print::with_forced_trimmed_paths};
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::{self};
use rustc_span::sym;
use super::SUSPICIOUS_TO_OWNED;

View file

@ -0,0 +1,62 @@
use crate::methods::TYPE_ID_ON_BOX;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::{self, ExistentialPredicate, Ty};
use rustc_span::{sym, Span};
fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
if let ty::Dynamic(preds, ..) = ty.kind() {
preds.iter().any(|p| match p.skip_binder() {
ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id),
_ => false,
})
} else {
false
}
}
pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) {
let recv_adjusts = cx.typeck_results().expr_adjustments(receiver);
if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last()
&& let ty::Ref(_, ty, _) = recv_ty.kind()
&& let ty::Adt(adt, substs) = ty.kind()
&& adt.is_box()
&& is_dyn_any(cx, substs.type_at(0))
{
span_lint_and_then(
cx,
TYPE_ID_ON_BOX,
call_span,
"calling `.type_id()` on a `Box<dyn Any>`",
|diag| {
let derefs = recv_adjusts
.iter()
.filter(|adj| matches!(adj.kind, Adjust::Deref(None)))
.count();
let mut sugg = "*".repeat(derefs + 1);
sugg += &snippet(cx, receiver.span, "<expr>");
diag.note(
"this returns the type id of the literal type `Box<dyn Any>` instead of the \
type id of the boxed value, which is most likely not what you want"
)
.note(
"if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \
which makes it more clear"
)
.span_suggestion(
receiver.span,
"consider dereferencing first",
format!("({sugg})"),
Applicability::MaybeIncorrect,
);
},
);
}
}

View file

@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty};
use clippy_utils::is_path_diagnostic_item;
use clippy_utils::ty::is_uninit_value_valid_for_ty;
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;

View file

@ -11,8 +11,7 @@ use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::sym;
use super::UNNECESSARY_FILTER_MAP;
use super::UNNECESSARY_FIND_MAP;
use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) {
if !is_trait_method(cx, expr, sym::Iterator) {

View file

@ -8,7 +8,8 @@ use rustc_hir as hir;
use rustc_hir::PatKind;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::{source_map::Span, sym};
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::UNNECESSARY_FOLD;

View file

@ -5,7 +5,8 @@ use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
use clippy_utils::{fn_def_id, get_parent_expr};
use rustc_errors::Applicability;
use rustc_hir::{def_id::DefId, Expr, ExprKind};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Symbol};

View file

@ -1,4 +1,5 @@
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_lang_item;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};

View file

@ -1,4 +1,5 @@
use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_segment, path_res, MaybePath};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@ -29,6 +30,11 @@ pub(super) fn check(
args: &[hir::Expr<'_>],
) {
let init = clippy_utils::expr_or_init(cx, recv);
if init.span.from_expansion() {
// don't lint if the receiver or binding initializer comes from a macro
// (e.g. `let x = option_env!(..); x.unwrap()`)
return;
}
let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind {
let Some(qpath) = call.qpath_opt() else { return };
@ -62,6 +68,22 @@ pub(super) fn check(
(expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
(expr.span.with_lo(args[0].span.hi()), ")".to_string()),
]),
("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => {
let mut suggs = vec![
(recv.span.with_hi(call_args[0].span.lo()), String::new()),
(expr.span.with_lo(call_args[0].span.hi()), String::new()),
];
// try to also remove the unsafe block if present
if let hir::Node::Block(block) = cx.tcx.hir().get_parent(expr.hir_id)
&& let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules
{
suggs.extend([
(block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()),
(expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new())
]);
}
Some(suggs)
},
(_, _, Some(_)) => None,
("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
(

View file

@ -6,7 +6,8 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, subst::GenericArgKind};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self};
use rustc_span::sym;
use rustc_span::symbol::Ident;
use std::iter;

View file

@ -7,7 +7,8 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid
use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
use rustc_errors::Applicability;
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
use rustc_hir::def_id::DefId;
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node};
use rustc_hir_typeck::{FnCtxt, Inherited};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
@ -16,7 +17,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, ProjectionPredicate, TraitPredicate, Ty};
use rustc_span::{sym, Symbol};
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{Obligation, ObligationCause};
use super::UNNECESSARY_TO_OWNED;

View file

@ -1,10 +1,10 @@
//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
use super::UNWRAP_OR_ELSE_DEFAULT;
use clippy_utils::{
diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
ty::is_type_diagnostic_item,
};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_default_equivalent_call;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir as hir;

View file

@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
USELESS_ASREF,
expr.span,
&format!("this call to `{call_name}` does nothing"),
"try this",
"try",
snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(),
applicability,
);