Skip to content

Commit eac1e50

Browse files
committed
Add ControlFlow.{map_break,map_continue} to useless_conversion
1 parent 711c2dc commit eac1e50

File tree

5 files changed

+107
-49
lines changed

5 files changed

+107
-49
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4984,6 +4984,9 @@ impl Methods {
49844984
manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv);
49854985
crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
49864986
},
4987+
("map_break" | "map_continue", [m_arg]) => {
4988+
crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
4989+
},
49874990
("map_or", [def, map]) => {
49884991
option_map_or_none::check(cx, expr, recv, def, map);
49894992
manual_ok_or::check(cx, expr, recv, def, map);

clippy_lints/src/useless_conversion.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin
22
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
33
use clippy_utils::sugg::{DiagExt as _, Sugg};
44
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
5-
use clippy_utils::{get_parent_expr, is_trait_item, is_trait_method, is_ty_alias, path_to_local};
5+
use clippy_utils::{
6+
get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local,
7+
};
68
use rustc_errors::Applicability;
79
use rustc_hir::def_id::DefId;
810
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
@@ -12,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass};
1214
use rustc_middle::traits::ObligationCause;
1315
use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
1416
use rustc_session::impl_lint_pass;
15-
use rustc_span::{Span, sym};
17+
use rustc_span::{Span, Symbol, sym};
1618
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
1719

1820
declare_clippy_lint! {
@@ -386,11 +388,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
386388
/// Check if `arg` is a `Into::into` or `From::from` applied to `receiver` to give `expr`, through a
387389
/// higher-order mapping function.
388390
pub fn check_function_application(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
389-
let recv_ty = cx.typeck_results().expr_ty(recv);
390-
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
391-
if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did)
392-
&& let Some(diag_name) = cx.tcx.get_diagnostic_name(recv_ty_defid)
393-
&& matches!(diag_name, sym::Option | sym::Result)
391+
if has_eligible_receiver(cx, recv, expr)
392+
&& let expr_ty = cx.typeck_results().expr_ty_adjusted(expr)
394393
&& same_type_and_consts(expr_ty, cx.typeck_results().expr_ty_adjusted(recv))
395394
&& (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From))
396395
{
@@ -410,3 +409,29 @@ pub fn check_function_application(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &
410409
);
411410
}
412411
}
412+
413+
fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) -> bool {
414+
let recv_ty = cx.typeck_results().expr_ty(recv);
415+
if is_inherent_method_call(cx, expr)
416+
&& let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did)
417+
{
418+
if let Some(diag_name) = cx.tcx.get_diagnostic_name(recv_ty_defid)
419+
&& matches!(diag_name, sym::Option | sym::Result)
420+
{
421+
return true;
422+
}
423+
424+
// Necessary for `core::ops::control_flow::ControlFlow` until a diagnostic item
425+
// has been added.
426+
let def_path = cx.get_def_path(recv_ty_defid);
427+
if def_path
428+
.iter()
429+
.map(Symbol::as_str)
430+
.zip(["core", "ops", "control_flow", "ControlFlow"])
431+
.all(|(sym, s)| sym == s)
432+
{
433+
return true;
434+
}
435+
}
436+
false
437+
}

tests/ui/useless_conversion.fixed

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
44
#![allow(static_mut_refs)]
55

6+
use std::ops::ControlFlow;
7+
68
fn test_generic<T: Copy>(val: T) -> T {
79
let _ = val;
810
val
@@ -308,6 +310,13 @@ fn direct_application() {
308310
let _: Result<(), std::io::Error> = test_issue_3913();
309311
//~^ useless_conversion
310312

313+
let c: ControlFlow<()> = ControlFlow::Continue(());
314+
let _: ControlFlow<()> = c;
315+
//~^ useless_conversion
316+
let c: ControlFlow<()> = ControlFlow::Continue(());
317+
let _: ControlFlow<()> = c;
318+
//~^ useless_conversion
319+
311320
struct Absorb;
312321
impl From<()> for Absorb {
313322
fn from(_: ()) -> Self {

tests/ui/useless_conversion.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
44
#![allow(static_mut_refs)]
55

6+
use std::ops::ControlFlow;
7+
68
fn test_generic<T: Copy>(val: T) -> T {
79
let _ = T::from(val);
810
val.into()
@@ -308,6 +310,13 @@ fn direct_application() {
308310
let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from);
309311
//~^ useless_conversion
310312

313+
let c: ControlFlow<()> = ControlFlow::Continue(());
314+
let _: ControlFlow<()> = c.map_break(Into::into);
315+
//~^ useless_conversion
316+
let c: ControlFlow<()> = ControlFlow::Continue(());
317+
let _: ControlFlow<()> = c.map_continue(Into::into);
318+
//~^ useless_conversion
319+
311320
struct Absorb;
312321
impl From<()> for Absorb {
313322
fn from(_: ()) -> Self {

0 commit comments

Comments
 (0)