@@ -293,13 +293,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
293
293
}
294
294
}
295
295
296
- fn check_powi ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , args : & [ Expr < ' _ > ] ) {
296
+ fn check_powi ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , args : & [ Expr < ' _ > ] ) {
297
297
// Check argument
298
- if let Some ( ( value, _) ) = constant ( cx, cx. tables , & args[ 1 ] ) {
298
+ if let Some ( ( value, _) ) = constant ( cx, cx. tables ( ) , & args[ 1 ] ) {
299
299
// TODO: need more specific check. this is too wide. remember also to include tests
300
300
if let Some ( parent) = get_parent_expr ( cx, expr) {
301
301
if let Some ( grandparent) = get_parent_expr ( cx, parent) {
302
- if let ExprKind :: MethodCall ( PathSegment { ident : method_name, .. } , _, args) = grandparent. kind {
302
+ if let ExprKind :: MethodCall ( PathSegment { ident : method_name, .. } , _, args, _ ) = grandparent. kind {
303
303
if method_name. as_str ( ) == "sqrt" && detect_hypot ( cx, args) . is_some ( ) {
304
304
return ;
305
305
}
@@ -328,7 +328,7 @@ fn check_powi(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
328
328
}
329
329
}
330
330
331
- fn detect_hypot ( cx : & LateContext < ' _ , ' _ > , args : & [ Expr < ' _ > ] ) -> Option < String > {
331
+ fn detect_hypot ( cx : & LateContext < ' _ > , args : & [ Expr < ' _ > ] ) -> Option < String > {
332
332
if let ExprKind :: Binary (
333
333
Spanned {
334
334
node : BinOpKind :: Add , ..
@@ -350,11 +350,11 @@ fn detect_hypot(cx: &LateContext<'_, '_>, args: &[Expr<'_>]) -> Option<String> {
350
350
351
351
// check if expression of the form x.powi(2) + y.powi(2)
352
352
if_chain ! {
353
- if let ExprKind :: MethodCall ( PathSegment { ident: lmethod_name, .. } , ref _lspan, ref largs) = add_lhs. kind;
354
- if let ExprKind :: MethodCall ( PathSegment { ident: rmethod_name, .. } , ref _rspan, ref rargs) = add_rhs. kind;
353
+ if let ExprKind :: MethodCall ( PathSegment { ident: lmethod_name, .. } , ref _lspan, ref largs, _ ) = add_lhs. kind;
354
+ if let ExprKind :: MethodCall ( PathSegment { ident: rmethod_name, .. } , ref _rspan, ref rargs, _ ) = add_rhs. kind;
355
355
if lmethod_name. as_str( ) == "powi" && rmethod_name. as_str( ) == "powi" ;
356
- if let Some ( ( lvalue, _) ) = constant( cx, cx. tables, & largs[ 1 ] ) ;
357
- if let Some ( ( rvalue, _) ) = constant( cx, cx. tables, & rargs[ 1 ] ) ;
356
+ if let Some ( ( lvalue, _) ) = constant( cx, cx. tables( ) , & largs[ 1 ] ) ;
357
+ if let Some ( ( rvalue, _) ) = constant( cx, cx. tables( ) , & rargs[ 1 ] ) ;
358
358
if Int ( 2 ) == lvalue && Int ( 2 ) == rvalue;
359
359
then {
360
360
return Some ( format!( "{}.hypot({})" , Sugg :: hir( cx, & largs[ 0 ] , ".." ) , Sugg :: hir( cx, & rargs[ 0 ] , ".." ) ) ) ;
@@ -365,7 +365,7 @@ fn detect_hypot(cx: &LateContext<'_, '_>, args: &[Expr<'_>]) -> Option<String> {
365
365
None
366
366
}
367
367
368
- fn check_hypot ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , args : & [ Expr < ' _ > ] ) {
368
+ fn check_hypot ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , args : & [ Expr < ' _ > ] ) {
369
369
if let Some ( message) = detect_hypot ( cx, args) {
370
370
span_lint_and_sugg (
371
371
cx,
@@ -431,7 +431,7 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
431
431
) = & expr. kind
432
432
{
433
433
if let Some ( parent) = get_parent_expr ( cx, expr) {
434
- if let ExprKind :: MethodCall ( PathSegment { ident : method_name, .. } , _, args) = parent. kind {
434
+ if let ExprKind :: MethodCall ( PathSegment { ident : method_name, .. } , _, args, _ ) = parent. kind {
435
435
if method_name. as_str ( ) == "sqrt" && detect_hypot ( cx, args) . is_some ( ) {
436
436
return ;
437
437
}
@@ -573,6 +573,50 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
573
573
}
574
574
}
575
575
576
+ fn are_same_base_logs ( cx : & LateContext < ' _ > , expr_a : & Expr < ' _ > , expr_b : & Expr < ' _ > ) -> bool {
577
+ if_chain ! {
578
+ if let ExprKind :: MethodCall ( PathSegment { ident: method_name_a, .. } , _, ref args_a, _) = expr_a. kind;
579
+ if let ExprKind :: MethodCall ( PathSegment { ident: method_name_b, .. } , _, ref args_b, _) = expr_b. kind;
580
+ then {
581
+ return method_name_a. as_str( ) == method_name_b. as_str( ) &&
582
+ args_a. len( ) == args_b. len( ) &&
583
+ (
584
+ [ "ln" , "log2" , "log10" ] . contains( &&* method_name_a. as_str( ) ) ||
585
+ method_name_a. as_str( ) == "log" && args_a. len( ) == 2 && are_exprs_equal( cx, & args_a[ 1 ] , & args_b[ 1 ] )
586
+ ) ;
587
+ }
588
+ }
589
+
590
+ false
591
+ }
592
+
593
+ fn check_log_division ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
594
+ // check if expression of the form x.logN() / y.logN()
595
+ if_chain ! {
596
+ if let ExprKind :: Binary (
597
+ Spanned {
598
+ node: BinOpKind :: Div , ..
599
+ } ,
600
+ lhs,
601
+ rhs,
602
+ ) = & expr. kind;
603
+ if are_same_base_logs( cx, lhs, rhs) ;
604
+ if let ExprKind :: MethodCall ( _, _, ref largs, _) = lhs. kind;
605
+ if let ExprKind :: MethodCall ( _, _, ref rargs, _) = rhs. kind;
606
+ then {
607
+ span_lint_and_sugg(
608
+ cx,
609
+ SUBOPTIMAL_FLOPS ,
610
+ expr. span,
611
+ "division of logarithms can be calculated more efficiently and accurately" ,
612
+ "consider using" ,
613
+ format!( "{}.log({})" , Sugg :: hir( cx, & largs[ 0 ] , ".." ) , Sugg :: hir( cx, & rargs[ 0 ] , ".." ) , ) ,
614
+ Applicability :: MachineApplicable ,
615
+ ) ;
616
+ }
617
+ }
618
+ }
619
+
576
620
impl < ' tcx > LateLintPass < ' tcx > for FloatingPointArithmetic {
577
621
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
578
622
if let ExprKind :: MethodCall ( ref path, _, args, _) = & expr. kind {
@@ -592,6 +636,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
592
636
check_expm1 ( cx, expr) ;
593
637
check_mul_add ( cx, expr) ;
594
638
check_custom_abs ( cx, expr) ;
639
+ check_log_division ( cx, expr) ;
595
640
}
596
641
}
597
642
}
0 commit comments