Skip to content

Commit 4b87008

Browse files
committed
Auto merge of rust-lang#5792 - flip1995:rollup-torc1we, r=flip1995
Rollup of 5 pull requests Successful merges: - rust-lang#5443 (Some accuracy lints for floating point operations) - rust-lang#5752 (Move range_minus_one to pedantic) - rust-lang#5756 (unnecessary_sort_by: avoid linting if key borrows) - rust-lang#5784 (Fix out of bounds access by checking length equality BEFORE accessing by index.) - rust-lang#5786 (fix phrase in new_lint issue template) Failed merges: r? @ghost changelog: rollup
2 parents fa4a737 + 314b068 commit 4b87008

35 files changed

+656
-94
lines changed

.github/ISSUE_TEMPLATE/new_lint.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ labels: L-lint
1212

1313
- Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
1414

15-
*What benefit of this lint over old code?*
15+
*What is the advantage of the recommended code over the original code*
1616

1717
For example:
1818
- Remove bounce checking inserted by ...

clippy_lints/src/floating_point_arithmetic.rs

+224-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::consts::{
22
constant, constant_simple, Constant,
3-
Constant::{F32, F64},
3+
Constant::{Int, F32, F64},
44
};
5-
use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
5+
use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
66
use if_chain::if_chain;
77
use rustc_errors::Applicability;
8-
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
8+
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::ty;
1111
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -293,6 +293,121 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
293293
}
294294
}
295295

296+
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
297+
if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) {
298+
if value == Int(2) {
299+
if let Some(parent) = get_parent_expr(cx, expr) {
300+
if let Some(grandparent) = get_parent_expr(cx, parent) {
301+
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
302+
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
303+
return;
304+
}
305+
}
306+
}
307+
308+
if let ExprKind::Binary(
309+
Spanned {
310+
node: BinOpKind::Add, ..
311+
},
312+
ref lhs,
313+
ref rhs,
314+
) = parent.kind
315+
{
316+
let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
317+
318+
span_lint_and_sugg(
319+
cx,
320+
SUBOPTIMAL_FLOPS,
321+
parent.span,
322+
"square can be computed more efficiently",
323+
"consider using",
324+
format!(
325+
"{}.mul_add({}, {})",
326+
Sugg::hir(cx, &args[0], ".."),
327+
Sugg::hir(cx, &args[0], ".."),
328+
Sugg::hir(cx, &other_addend, ".."),
329+
),
330+
Applicability::MachineApplicable,
331+
);
332+
333+
return;
334+
}
335+
}
336+
337+
span_lint_and_sugg(
338+
cx,
339+
SUBOPTIMAL_FLOPS,
340+
expr.span,
341+
"square can be computed more efficiently",
342+
"consider using",
343+
format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
344+
Applicability::MachineApplicable,
345+
);
346+
}
347+
}
348+
}
349+
350+
fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
351+
if let ExprKind::Binary(
352+
Spanned {
353+
node: BinOpKind::Add, ..
354+
},
355+
ref add_lhs,
356+
ref add_rhs,
357+
) = args[0].kind
358+
{
359+
// check if expression of the form x * x + y * y
360+
if_chain! {
361+
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind;
362+
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind;
363+
if are_exprs_equal(cx, lmul_lhs, lmul_rhs);
364+
if are_exprs_equal(cx, rmul_lhs, rmul_rhs);
365+
then {
366+
return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, "..")));
367+
}
368+
}
369+
370+
// check if expression of the form x.powi(2) + y.powi(2)
371+
if_chain! {
372+
if let ExprKind::MethodCall(
373+
PathSegment { ident: lmethod_name, .. },
374+
ref _lspan,
375+
ref largs,
376+
_
377+
) = add_lhs.kind;
378+
if let ExprKind::MethodCall(
379+
PathSegment { ident: rmethod_name, .. },
380+
ref _rspan,
381+
ref rargs,
382+
_
383+
) = add_rhs.kind;
384+
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
385+
if let Some((lvalue, _)) = constant(cx, cx.tables(), &largs[1]);
386+
if let Some((rvalue, _)) = constant(cx, cx.tables(), &rargs[1]);
387+
if Int(2) == lvalue && Int(2) == rvalue;
388+
then {
389+
return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], "..")));
390+
}
391+
}
392+
}
393+
394+
None
395+
}
396+
397+
fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
398+
if let Some(message) = detect_hypot(cx, args) {
399+
span_lint_and_sugg(
400+
cx,
401+
IMPRECISE_FLOPS,
402+
expr.span,
403+
"hypotenuse can be computed more accurately",
404+
"consider using",
405+
message,
406+
Applicability::MachineApplicable,
407+
);
408+
}
409+
}
410+
296411
// TODO: Lint expressions of the form `x.exp() - y` where y > 1
297412
// and suggest usage of `x.exp_m1() - (y - 1)` instead
298413
fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -344,6 +459,14 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
344459
rhs,
345460
) = &expr.kind
346461
{
462+
if let Some(parent) = get_parent_expr(cx, expr) {
463+
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind {
464+
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
465+
return;
466+
}
467+
}
468+
}
469+
347470
let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
348471
(inner_lhs, inner_rhs, rhs)
349472
} else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
@@ -479,6 +602,100 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
479602
}
480603
}
481604

605+
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
606+
if_chain! {
607+
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, ref args_a, _) = expr_a.kind;
608+
if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref args_b, _) = expr_b.kind;
609+
then {
610+
return method_name_a.as_str() == method_name_b.as_str() &&
611+
args_a.len() == args_b.len() &&
612+
(
613+
["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) ||
614+
method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1])
615+
);
616+
}
617+
}
618+
619+
false
620+
}
621+
622+
fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
623+
// check if expression of the form x.logN() / y.logN()
624+
if_chain! {
625+
if let ExprKind::Binary(
626+
Spanned {
627+
node: BinOpKind::Div, ..
628+
},
629+
lhs,
630+
rhs,
631+
) = &expr.kind;
632+
if are_same_base_logs(cx, lhs, rhs);
633+
if let ExprKind::MethodCall(_, _, ref largs, _) = lhs.kind;
634+
if let ExprKind::MethodCall(_, _, ref rargs, _) = rhs.kind;
635+
then {
636+
span_lint_and_sugg(
637+
cx,
638+
SUBOPTIMAL_FLOPS,
639+
expr.span,
640+
"log base can be expressed more clearly",
641+
"consider using",
642+
format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),),
643+
Applicability::MachineApplicable,
644+
);
645+
}
646+
}
647+
}
648+
649+
fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
650+
if_chain! {
651+
if let ExprKind::Binary(
652+
Spanned {
653+
node: BinOpKind::Div, ..
654+
},
655+
div_lhs,
656+
div_rhs,
657+
) = &expr.kind;
658+
if let ExprKind::Binary(
659+
Spanned {
660+
node: BinOpKind::Mul, ..
661+
},
662+
mul_lhs,
663+
mul_rhs,
664+
) = &div_lhs.kind;
665+
if let Some((rvalue, _)) = constant(cx, cx.tables(), div_rhs);
666+
if let Some((lvalue, _)) = constant(cx, cx.tables(), mul_rhs);
667+
then {
668+
// TODO: also check for constant values near PI/180 or 180/PI
669+
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
670+
(F32(180_f32) == lvalue || F64(180_f64) == lvalue)
671+
{
672+
span_lint_and_sugg(
673+
cx,
674+
SUBOPTIMAL_FLOPS,
675+
expr.span,
676+
"conversion to degrees can be done more accurately",
677+
"consider using",
678+
format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")),
679+
Applicability::MachineApplicable,
680+
);
681+
} else if
682+
(F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
683+
(F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
684+
{
685+
span_lint_and_sugg(
686+
cx,
687+
SUBOPTIMAL_FLOPS,
688+
expr.span,
689+
"conversion to radians can be done more accurately",
690+
"consider using",
691+
format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")),
692+
Applicability::MachineApplicable,
693+
);
694+
}
695+
}
696+
}
697+
}
698+
482699
impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
483700
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
484701
if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind {
@@ -489,13 +706,17 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
489706
"ln" => check_ln1p(cx, expr, args),
490707
"log" => check_log_base(cx, expr, args),
491708
"powf" => check_powf(cx, expr, args),
709+
"powi" => check_powi(cx, expr, args),
710+
"sqrt" => check_hypot(cx, expr, args),
492711
_ => {},
493712
}
494713
}
495714
} else {
496715
check_expm1(cx, expr);
497716
check_mul_add(cx, expr);
498717
check_custom_abs(cx, expr);
718+
check_log_division(cx, expr);
719+
check_radians(cx, expr);
499720
}
500721
}
501722
}

clippy_lints/src/let_and_return.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use if_chain::if_chain;
22
use rustc_errors::Applicability;
3-
use rustc_hir::def_id::DefId;
43
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
54
use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind};
65
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -9,7 +8,7 @@ use rustc_middle::lint::in_external_macro;
98
use rustc_middle::ty::subst::GenericArgKind;
109
use rustc_session::{declare_lint_pass, declare_tool_lint};
1110

12-
use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then};
11+
use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then};
1312

1413
declare_clippy_lint! {
1514
/// **What it does:** Checks for `let`-bindings, which are subsequently
@@ -97,22 +96,6 @@ struct BorrowVisitor<'a, 'tcx> {
9796
borrows: bool,
9897
}
9998

100-
impl BorrowVisitor<'_, '_> {
101-
fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> {
102-
match &expr.kind {
103-
ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id),
104-
ExprKind::Call(
105-
Expr {
106-
kind: ExprKind::Path(qpath),
107-
..
108-
},
109-
..,
110-
) => self.cx.qpath_res(qpath, expr.hir_id).opt_def_id(),
111-
_ => None,
112-
}
113-
}
114-
}
115-
11699
impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
117100
type Map = Map<'tcx>;
118101

@@ -121,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
121104
return;
122105
}
123106

124-
if let Some(def_id) = self.fn_def_id(expr) {
107+
if let Some(def_id) = fn_def_id(self.cx, expr) {
125108
self.borrows = self
126109
.cx
127110
.tcx

clippy_lints/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11611161
LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
11621162
LintId::of(&non_expressive_names::SIMILAR_NAMES),
11631163
LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE),
1164+
LintId::of(&ranges::RANGE_MINUS_ONE),
11641165
LintId::of(&ranges::RANGE_PLUS_ONE),
11651166
LintId::of(&shadow::SHADOW_UNRELATED),
11661167
LintId::of(&strings::STRING_ADD_ASSIGN),
@@ -1383,7 +1384,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13831384
LintId::of(&ptr::PTR_ARG),
13841385
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
13851386
LintId::of(&question_mark::QUESTION_MARK),
1386-
LintId::of(&ranges::RANGE_MINUS_ONE),
13871387
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
13881388
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
13891389
LintId::of(&redundant_clone::REDUNDANT_CLONE),
@@ -1599,7 +1599,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15991599
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
16001600
LintId::of(&precedence::PRECEDENCE),
16011601
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
1602-
LintId::of(&ranges::RANGE_MINUS_ONE),
16031602
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
16041603
LintId::of(&reference::DEREF_ADDROF),
16051604
LintId::of(&reference::REF_IN_DEREF),

clippy_lints/src/ranges.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ declare_clippy_lint! {
5252
/// exclusive ranges, because they essentially add an extra branch that
5353
/// LLVM may fail to hoist out of the loop.
5454
///
55+
/// This will cause a warning that cannot be fixed if the consumer of the
56+
/// range only accepts a specific range type, instead of the generic
57+
/// `RangeBounds` trait
58+
/// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
59+
///
5560
/// **Example:**
5661
/// ```rust,ignore
5762
/// for x..(y+1) { .. }
@@ -72,7 +77,10 @@ declare_clippy_lint! {
7277
/// **Why is this bad?** The code is more readable with an exclusive range
7378
/// like `x..y`.
7479
///
75-
/// **Known problems:** None.
80+
/// **Known problems:** This will cause a warning that cannot be fixed if
81+
/// the consumer of the range only accepts a specific range type, instead of
82+
/// the generic `RangeBounds` trait
83+
/// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
7684
///
7785
/// **Example:**
7886
/// ```rust,ignore
@@ -83,7 +91,7 @@ declare_clippy_lint! {
8391
/// for x..y { .. }
8492
/// ```
8593
pub RANGE_MINUS_ONE,
86-
complexity,
94+
pedantic,
8795
"`x..=(y-1)` reads better as `x..y`"
8896
}
8997

0 commit comments

Comments
 (0)