Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #5792

Merged
merged 21 commits into from
Jul 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a6f1af7
Lint for x.powi(2) => x * x
thiagoarrais Apr 3, 2020
f627984
Lint (x * x + y * y).sqrt() => x.hypot(y)
thiagoarrais May 25, 2020
0c8afa3
Lint x.log(b) / y.log(b) => x.log(y)
thiagoarrais Jun 1, 2020
076ec87
Lint for to_radians and to_degrees
thiagoarrais Jun 10, 2020
f559682
Better copy for lint message
thiagoarrais Jun 15, 2020
db7bc6b
Place radian lints under suboptimal_flops
thiagoarrais Jun 15, 2020
6dc066f
Includes TODO comment for hypot lint
thiagoarrais Jun 17, 2020
6be9491
Reclassify powi(2) lint under suboptimal_flops
thiagoarrais Jun 22, 2020
3065201
Includes TODO for constants equivalent to π/180
thiagoarrais Jul 6, 2020
db1c946
unnecessary_sort_by: avoid linting if key borrows
ebroto Jun 30, 2020
298a1fa
Move range_minus_one to pedantic
chrisduerr Jun 26, 2020
ba2a85d
Run update_lints
chrisduerr Jul 3, 2020
b3c7196
Fix test failures
chrisduerr Jul 10, 2020
afa4148
Fix tests a bit more
chrisduerr Jul 10, 2020
1b3bc16
Fix out of bounds access by checking length equality BEFORE accessing…
matthiaskrgr Jul 11, 2020
2c5f8ab
fix phrase in new_lint issue template
matthiaskrgr Jul 11, 2020
75d43aa
Rollup merge of #5443 - thiagoarrais:issue-2040, r=flip1995
flip1995 Jul 13, 2020
019e281
Rollup merge of #5752 - chrisduerr:pedantic_ranges, r=flip1995
flip1995 Jul 13, 2020
32ef448
Rollup merge of #5756 - ebroto:5754_sort_by, r=flip1995
flip1995 Jul 13, 2020
26ede31
Rollup merge of #5784 - matthiaskrgr:ice_5780, r=phansch
flip1995 Jul 13, 2020
314b068
Rollup merge of #5786 - matthiaskrgr:new_lint_issue_templ, r=phansch
flip1995 Jul 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/new_lint.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ labels: L-lint

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

*What benefit of this lint over old code?*
*What is the advantage of the recommended code over the original code*

For example:
- Remove bounce checking inserted by ...
Expand Down
227 changes: 224 additions & 3 deletions clippy_lints/src/floating_point_arithmetic.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::consts::{
constant, constant_simple, Constant,
Constant::{F32, F64},
Constant::{Int, F32, F64},
};
use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
Expand Down Expand Up @@ -293,6 +293,121 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
}
}

fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) {
if value == Int(2) {
if let Some(parent) = get_parent_expr(cx, expr) {
if let Some(grandparent) = get_parent_expr(cx, parent) {
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
return;
}
}
}

if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
ref lhs,
ref rhs,
) = parent.kind
{
let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };

span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
parent.span,
"square can be computed more efficiently",
"consider using",
format!(
"{}.mul_add({}, {})",
Sugg::hir(cx, &args[0], ".."),
Sugg::hir(cx, &args[0], ".."),
Sugg::hir(cx, &other_addend, ".."),
),
Applicability::MachineApplicable,
);

return;
}
}

span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"square can be computed more efficiently",
"consider using",
format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
Applicability::MachineApplicable,
);
}
}
}

fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
ref add_lhs,
ref add_rhs,
) = args[0].kind
{
// check if expression of the form x * x + y * y
if_chain! {
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind;
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind;
if are_exprs_equal(cx, lmul_lhs, lmul_rhs);
if are_exprs_equal(cx, rmul_lhs, rmul_rhs);
then {
return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, "..")));
}
}

// check if expression of the form x.powi(2) + y.powi(2)
if_chain! {
if let ExprKind::MethodCall(
PathSegment { ident: lmethod_name, .. },
ref _lspan,
ref largs,
_
) = add_lhs.kind;
if let ExprKind::MethodCall(
PathSegment { ident: rmethod_name, .. },
ref _rspan,
ref rargs,
_
) = add_rhs.kind;
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
if let Some((lvalue, _)) = constant(cx, cx.tables(), &largs[1]);
if let Some((rvalue, _)) = constant(cx, cx.tables(), &rargs[1]);
if Int(2) == lvalue && Int(2) == rvalue;
then {
return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], "..")));
}
}
}

None
}

fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
if let Some(message) = detect_hypot(cx, args) {
span_lint_and_sugg(
cx,
IMPRECISE_FLOPS,
expr.span,
"hypotenuse can be computed more accurately",
"consider using",
message,
Applicability::MachineApplicable,
);
}
}

// TODO: Lint expressions of the form `x.exp() - y` where y > 1
// and suggest usage of `x.exp_m1() - (y - 1)` instead
fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
Expand Down Expand Up @@ -344,6 +459,14 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
rhs,
) = &expr.kind
{
if let Some(parent) = get_parent_expr(cx, expr) {
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
return;
}
}
}

let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
(inner_lhs, inner_rhs, rhs)
} else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
Expand Down Expand Up @@ -479,6 +602,100 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
}
}

fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
if_chain! {
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, ref args_a, _) = expr_a.kind;
if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref args_b, _) = expr_b.kind;
then {
return method_name_a.as_str() == method_name_b.as_str() &&
args_a.len() == args_b.len() &&
(
["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) ||
method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1])
);
}
}

false
}

fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
// check if expression of the form x.logN() / y.logN()
if_chain! {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Div, ..
},
lhs,
rhs,
) = &expr.kind;
if are_same_base_logs(cx, lhs, rhs);
if let ExprKind::MethodCall(_, _, ref largs, _) = lhs.kind;
if let ExprKind::MethodCall(_, _, ref rargs, _) = rhs.kind;
then {
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"log base can be expressed more clearly",
"consider using",
format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),),
Applicability::MachineApplicable,
);
}
}
}

fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Div, ..
},
div_lhs,
div_rhs,
) = &expr.kind;
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Mul, ..
},
mul_lhs,
mul_rhs,
) = &div_lhs.kind;
if let Some((rvalue, _)) = constant(cx, cx.tables(), div_rhs);
if let Some((lvalue, _)) = constant(cx, cx.tables(), mul_rhs);
then {
// TODO: also check for constant values near PI/180 or 180/PI
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
(F32(180_f32) == lvalue || F64(180_f64) == lvalue)
{
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"conversion to degrees can be done more accurately",
"consider using",
format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")),
Applicability::MachineApplicable,
);
} else if
(F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
(F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
{
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"conversion to radians can be done more accurately",
"consider using",
format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")),
Applicability::MachineApplicable,
);
}
}
}
}

impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind {
Expand All @@ -489,13 +706,17 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
"ln" => check_ln1p(cx, expr, args),
"log" => check_log_base(cx, expr, args),
"powf" => check_powf(cx, expr, args),
"powi" => check_powi(cx, expr, args),
"sqrt" => check_hypot(cx, expr, args),
_ => {},
}
}
} else {
check_expm1(cx, expr);
check_mul_add(cx, expr);
check_custom_abs(cx, expr);
check_log_division(cx, expr);
check_radians(cx, expr);
}
}
}
21 changes: 2 additions & 19 deletions clippy_lints/src/let_and_return.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
Expand All @@ -9,7 +8,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then};
use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then};

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

impl BorrowVisitor<'_, '_> {
fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> {
match &expr.kind {
ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id),
ExprKind::Call(
Expr {
kind: ExprKind::Path(qpath),
..
},
..,
) => self.cx.qpath_res(qpath, expr.hir_id).opt_def_id(),
_ => None,
}
}
}

impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
type Map = Map<'tcx>;

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

if let Some(def_id) = self.fn_def_id(expr) {
if let Some(def_id) = fn_def_id(self.cx, expr) {
self.borrows = self
.cx
.tcx
Expand Down
3 changes: 1 addition & 2 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
LintId::of(&non_expressive_names::SIMILAR_NAMES),
LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(&ranges::RANGE_MINUS_ONE),
LintId::of(&ranges::RANGE_PLUS_ONE),
LintId::of(&shadow::SHADOW_UNRELATED),
LintId::of(&strings::STRING_ADD_ASSIGN),
Expand Down Expand Up @@ -1383,7 +1384,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&ptr::PTR_ARG),
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
LintId::of(&question_mark::QUESTION_MARK),
LintId::of(&ranges::RANGE_MINUS_ONE),
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
LintId::of(&redundant_clone::REDUNDANT_CLONE),
Expand Down Expand Up @@ -1599,7 +1599,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(&precedence::PRECEDENCE),
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
LintId::of(&ranges::RANGE_MINUS_ONE),
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
LintId::of(&reference::DEREF_ADDROF),
LintId::of(&reference::REF_IN_DEREF),
Expand Down
12 changes: 10 additions & 2 deletions clippy_lints/src/ranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ declare_clippy_lint! {
/// exclusive ranges, because they essentially add an extra branch that
/// LLVM may fail to hoist out of the loop.
///
/// This will cause a warning that cannot be fixed if the consumer of the
/// range only accepts a specific range type, instead of the generic
/// `RangeBounds` trait
/// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
///
/// **Example:**
/// ```rust,ignore
/// for x..(y+1) { .. }
Expand All @@ -72,7 +77,10 @@ declare_clippy_lint! {
/// **Why is this bad?** The code is more readable with an exclusive range
/// like `x..y`.
///
/// **Known problems:** None.
/// **Known problems:** This will cause a warning that cannot be fixed if
/// the consumer of the range only accepts a specific range type, instead of
/// the generic `RangeBounds` trait
/// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
///
/// **Example:**
/// ```rust,ignore
Expand All @@ -83,7 +91,7 @@ declare_clippy_lint! {
/// for x..y { .. }
/// ```
pub RANGE_MINUS_ONE,
complexity,
pedantic,
"`x..=(y-1)` reads better as `x..y`"
}

Expand Down
Loading