-
Notifications
You must be signed in to change notification settings - Fork 11.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[move][move-linter] implemen meaningless math operator rules
- Loading branch information
Showing
11 changed files
with
241 additions
and
151 deletions.
There are no files selected for viewing
105 changes: 105 additions & 0 deletions
105
external-crates/move/crates/move-compiler/src/linters/meaningless_math_operation.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright (c) The Move Contributors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
//! Detects meaningless math operations like `x * 0`, `x << 0`, `x >> 0`, `x * 1`, `x + 0`, `x - 0`, and `x / 0`. | ||
//! Aims to reduce code redundancy and improve clarity by flagging operations with no effect. | ||
use crate::{ | ||
diag, | ||
diagnostics::{ | ||
codes::{custom, DiagnosticInfo, Severity}, | ||
WarningFilters, | ||
}, | ||
expansion::ast::Value_, | ||
parser::ast::BinOp_, | ||
shared::CompilationEnv, | ||
typing::{ | ||
ast::{self as T, Exp, UnannotatedExp_}, | ||
visitor::{TypingVisitorConstructor, TypingVisitorContext}, | ||
}, | ||
}; | ||
use move_ir_types::location::Loc; | ||
|
||
use super::{LinterDiagnosticCategory, LINT_WARNING_PREFIX, MEANINGLESS_MATH_DIAG_CODE}; | ||
|
||
const MEANINGLESS_MATH_OP_DIAG: DiagnosticInfo = custom( | ||
LINT_WARNING_PREFIX, | ||
Severity::Warning, | ||
LinterDiagnosticCategory::Complexity as u8, | ||
MEANINGLESS_MATH_DIAG_CODE, | ||
"Detected a meaningless math operation that has no effect.", | ||
); | ||
|
||
pub struct MeaninglessMathOperation; | ||
|
||
pub struct Context<'a> { | ||
env: &'a mut CompilationEnv, | ||
} | ||
|
||
impl TypingVisitorConstructor for MeaninglessMathOperation { | ||
type Context<'a> = Context<'a>; | ||
|
||
fn context<'a>(env: &'a mut CompilationEnv, _program: &T::Program) -> Self::Context<'a> { | ||
Context { env } | ||
} | ||
} | ||
|
||
impl TypingVisitorContext for Context<'_> { | ||
fn add_warning_filter_scope(&mut self, filter: WarningFilters) { | ||
self.env.add_warning_filter_scope(filter) | ||
} | ||
fn pop_warning_filter_scope(&mut self) { | ||
self.env.pop_warning_filter_scope() | ||
} | ||
|
||
fn visit_exp_custom(&mut self, exp: &mut T::Exp) -> bool { | ||
if let UnannotatedExp_::BinopExp(_, op, _, rhs) = &exp.exp.value { | ||
match op.value { | ||
BinOp_::Mul | BinOp_::Div => { | ||
if is_zero(&rhs) || (matches!(op.value, BinOp_::Mul) && is_one(&rhs)) { | ||
report_meaningless_math_op(self.env, op.loc); | ||
} | ||
} | ||
BinOp_::Add | BinOp_::Sub => { | ||
if is_zero(&rhs) { | ||
report_meaningless_math_op(self.env, op.loc); | ||
} | ||
} | ||
BinOp_::Shl | BinOp_::Shr => { | ||
if is_zero(&rhs) { | ||
report_meaningless_math_op(self.env, op.loc); | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
false | ||
} | ||
} | ||
|
||
fn is_zero(exp: &Exp) -> bool { | ||
if let UnannotatedExp_::Value(spanned) = &exp.exp.value { | ||
matches!(spanned.value, Value_::U64(0)) | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
fn is_one(exp: &Exp) -> bool { | ||
if let UnannotatedExp_::Value(spanned) = &exp.exp.value { | ||
matches!(spanned.value, Value_::U64(1)) | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
fn report_meaningless_math_op(env: &mut CompilationEnv, loc: Loc) { | ||
let diag = diag!( | ||
MEANINGLESS_MATH_OP_DIAG, | ||
( | ||
loc, | ||
"Detected a meaningless math operation that has no effect.", | ||
) | ||
); | ||
env.add_diag(diag); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 0 additions & 109 deletions
109
external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs
This file was deleted.
Oops, something went wrong.
24 changes: 0 additions & 24 deletions
24
external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp
This file was deleted.
Oops, something went wrong.
9 changes: 0 additions & 9 deletions
9
external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move
This file was deleted.
Oops, something went wrong.
8 changes: 8 additions & 0 deletions
8
...ates/move/crates/move-compiler/tests/linter/false_negative_meaningless_math_operation.exp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
warning[Lint W01008]: Detected a meaningless math operation that has no effect. | ||
┌─ tests/linter/false_negative_meaningless_math_operation.move:16:11 | ||
│ | ||
16 │ x / 0 // This is undefined behavior, should be caught by a different linter | ||
│ ^ Detected a meaningless math operation that has no effect. | ||
│ | ||
= This warning can be suppressed with '#[allow(lint(meaningless_math_operation))]' applied to the 'module' or module member ('const', 'fun', or 'struct') | ||
|
22 changes: 22 additions & 0 deletions
22
...tes/move/crates/move-compiler/tests/linter/false_negative_meaningless_math_operation.move
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module 0x42::M { | ||
public fun complex_zero_operation(x: u64): u64 { | ||
x * (1 - 1) // This is effectively x * 0, but might not be caught | ||
} | ||
|
||
public fun complex_one_operation(x: u64): u64 { | ||
x * (2 - 1) // This is effectively x * 1, but might not be caught | ||
} | ||
|
||
public fun zero_shift_complex(x: u64, y: u64): u64 { | ||
x * (y - y) // This is effectively x << 0, but might not be caught | ||
} | ||
|
||
// Edge cases | ||
public fun divide_by_zero(x: u64): u64 { | ||
x / 0 // This is undefined behavior, should be caught by a different linter | ||
} | ||
|
||
public fun complex_zero_divide(x: u64): u64 { | ||
x / (1 - 1) // This is also undefined, might not be caught by this linter | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...tes/move/crates/move-compiler/tests/linter/false_positive_meaningless_math_operation.move
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module 0x42::M { | ||
public fun multiply_by_zero_var(x: u64, y: u64): u64 { | ||
x * y // Might trigger if y is always 0, but shouldn't if y is variable | ||
} | ||
|
||
public fun add_zero_var(x: u64, y: u64): u64 { | ||
x + y // Might trigger if y is always 0, but shouldn't if y is variable | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...ates/move/crates/move-compiler/tests/linter/true_negative_meaningless_math_operation.move
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module 0x42::M { | ||
public fun multiply_by_two(x: u64): u64 { | ||
x * 2 // Should not trigger the linter | ||
} | ||
|
||
public fun left_shift_by_one(x: u64): u64 { | ||
x << 1 // Should not trigger the linter | ||
} | ||
|
||
public fun add_one(x: u64): u64 { | ||
x + 1 // Should not trigger the linter | ||
} | ||
|
||
public fun divide_by_two(x: u64): u64 { | ||
x / 2 // Should not trigger the linter | ||
} | ||
} |
Oops, something went wrong.