From 53209755d7868e09a12d1c050dff933db26c9e97 Mon Sep 17 00:00:00 2001 From: jamedzung Date: Sat, 23 Mar 2024 01:43:33 +0700 Subject: [PATCH 01/20] implement rules --- .../src/linters/shift_overflow.rs | 109 ++++++++++++++++++ .../tests/custom_rules/shift_overflow.exp | 24 ++++ .../tests/custom_rules/shift_overflow.move | 9 ++ 3 files changed, 142 insertions(+) create mode 100644 external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs create mode 100644 external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp create mode 100644 external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move diff --git a/external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs b/external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs new file mode 100644 index 0000000000000..a66d97525fb8e --- /dev/null +++ b/external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs @@ -0,0 +1,109 @@ +//! Detect potential overflow scenarios where the number of bits being shifted exceeds the bit width of +//! the variable being shifted, which could lead to unintended behavior or loss of data. If such a +//! potential overflow is detected, a warning is generated to alert the developer. +use crate::{ + diag, + diagnostics::{ + codes::{custom, DiagnosticInfo, Severity}, + WarningFilters, + }, + expansion::ast::Value_, + naming::ast::{BuiltinTypeName_, TypeName_, Type_}, + parser::ast::BinOp_, + shared::{program_info::TypingProgramInfo, CompilationEnv}, + typing::{ + ast::{self as T, UnannotatedExp_}, + visitor::{TypingVisitorConstructor, TypingVisitorContext}, + }, +}; +use move_ir_types::location::Loc; +use std::str::FromStr; + +use super::{LinterDiagCategory, LINTER_DEFAULT_DIAG_CODE, LINT_WARNING_PREFIX}; + +const SHIFT_OPERATION_OVERFLOW_DIAG: DiagnosticInfo = custom( + LINT_WARNING_PREFIX, + Severity::Warning, + LinterDiagCategory::ShiftOperationOverflow as u8, + LINTER_DEFAULT_DIAG_CODE, + "Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted.", +); + +pub struct ShiftOperationOverflow; + +pub struct Context<'a> { + env: &'a mut CompilationEnv, +} + +impl TypingVisitorConstructor for ShiftOperationOverflow { + type Context<'a> = Context<'a>; + + fn context<'a>( + env: &'a mut CompilationEnv, + _program_info: &'a TypingProgramInfo, + _program: &T::Program_, + ) -> Self::Context<'a> { + Context { env } + } +} + +impl TypingVisitorContext for Context<'_> { + fn visit_exp_custom(&mut self, exp: &mut T::Exp) -> bool { + // Check if the expression is a binary operation and if it is a shift operation. + if let UnannotatedExp_::BinopExp(lhs, op, _, rhs) = &exp.exp.value { + // can't do let UnannotatedExp_::BinopExp(lhs, BinOp_::Shl | BinOp_::Shr, _, rhs) = &exp.exp.value else { return }; + // because the op is Spanned and not BinOp_ + if matches!(op.value, BinOp_::Shl | BinOp_::Shr) { + match ( + get_bit_width(&lhs.ty.value), + get_shift_amount(&rhs.exp.value), + ) { + (Some(bit_width), Some(shift_amount)) if shift_amount >= bit_width => { + report_overflow(self.env, shift_amount, bit_width, op.loc); + } + _ => (), + } + } + } + false + } + 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 get_bit_width(ty: &Type_) -> Option { + ty.builtin_name().and_then(|typ| match typ.value { + BuiltinTypeName_::U8 => Some(8), + BuiltinTypeName_::U16 => Some(16), + BuiltinTypeName_::U32 => Some(32), + BuiltinTypeName_::U64 => Some(64), + BuiltinTypeName_::U128 => Some(128), + BuiltinTypeName_::U256 => Some(256), + _ => None, + }) +} + +fn get_shift_amount(value: &UnannotatedExp_) -> Option { + if let UnannotatedExp_::Value(v) = value { + match &v.value { + Value_::U8(v) => Some(*v as u128), + _ => None, + } + } else { + None + } +} + +fn report_overflow(env: &mut CompilationEnv, shift_amount: u128, bit_width: u128, loc: Loc) { + let msg = format!( + "The {} of bits being shifted exceeds the {} bit width of the variable being shifted.", + shift_amount, bit_width + ); + let diag = diag!(SHIFT_OPERATION_OVERFLOW_DIAG, (loc, msg)); + env.add_diag(diag); +} diff --git a/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp b/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp new file mode 100644 index 0000000000000..ed6efd6a2ea67 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp @@ -0,0 +1,24 @@ +warning[Lint W00001]: Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted. + ┌─ tests/custom_rules/shift_overflow.move:5:20 + │ +5 │ let _b = x << 64; // Should not raise an issue + │ ^^ The 64 of bits being shifted exceeds the 64 bit width of the variable being shifted. + │ + = This warning can be suppressed with '#[allow(lint(shift_overflow))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W00001]: Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted. + ┌─ tests/custom_rules/shift_overflow.move:6:20 + │ +6 │ let _b = x << 65; // Should raise an issue + │ ^^ The 65 of bits being shifted exceeds the 64 bit width of the variable being shifted. + │ + = This warning can be suppressed with '#[allow(lint(shift_overflow))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W00001]: Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted. + ┌─ tests/custom_rules/shift_overflow.move:7:20 + │ +7 │ let _b = x >> 66; // Should raise an issue + │ ^^ The 66 of bits being shifted exceeds the 64 bit width of the variable being shifted. + │ + = This warning can be suppressed with '#[allow(lint(shift_overflow))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move b/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move new file mode 100644 index 0000000000000..e5dc71e6f6563 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move @@ -0,0 +1,9 @@ +module 0x42::M { + + fun func1(x: u64) { + let _b = x << 24; + let _b = x << 64; // Should raise an issue + let _b = x << 65; // Should raise an issue + let _b = x >> 66; // Should raise an issue + } +} \ No newline at end of file From dfd22da18b0669ac271e362e2a6945c3afeb3c92 Mon Sep 17 00:00:00 2001 From: dzungdinh94 Date: Fri, 31 May 2024 18:15:13 +0700 Subject: [PATCH 02/20] [move][move-linter] implement combinable bool rules --- .../src/linters/combinable_bool_conditions.rs | 140 ++++++++++++++++++ .../src/linters/shift_overflow.rs | 109 -------------- .../move-compiler/src/sui_mode/linters/mod.rs | 3 +- .../tests/custom_rules/shift_overflow.exp | 24 --- .../tests/custom_rules/shift_overflow.move | 9 -- .../tests/linter/correct_combinable_bool.move | 12 ++ .../linter/incorrect_combinable_bool.exp | 40 +++++ .../linter/incorrect_combinable_bool.move | 12 ++ .../linter/incorrect_constant_naming.exp | 4 - .../tests/linter/suppressed_lints.move | 5 + 10 files changed, 210 insertions(+), 148 deletions(-) create mode 100644 external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs delete mode 100644 external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs delete mode 100644 external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move create mode 100644 external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move create mode 100644 external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs new file mode 100644 index 0000000000000..bc69a0c94aa6e --- /dev/null +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs @@ -0,0 +1,140 @@ +//! The `CombinableBool` detects and warns about boolean conditions in Move code that can be simplified. +//! It identifies comparisons that are logically equivalent and suggests more concise alternatives. +//! This rule focuses on simplifying expressions involving `==`, `<`, `>`, and `!=` operators to improve code readability. +use move_ir_types::location::Loc; + +use crate::{ + diag, + diagnostics::{ + codes::{custom, DiagnosticInfo, Severity}, + WarningFilters, + }, + parser::ast::BinOp_, + shared::CompilationEnv, + typing::{ + ast::{self as T, UnannotatedExp_}, + visitor::{TypingVisitorConstructor, TypingVisitorContext}, + }, +}; + +use super::{LinterDiagnosticCategory, COMBINABLE_COMPARISON_DIAG_CODE, LINT_WARNING_PREFIX}; + +const COMBINABLE_BOOL_COND_DIAG: DiagnosticInfo = custom( + LINT_WARNING_PREFIX, + Severity::Warning, + LinterDiagnosticCategory::Complexity as u8, + COMBINABLE_COMPARISON_DIAG_CODE, + "", +); + +pub struct CombinableBool; + +pub struct Context<'a> { + env: &'a mut CompilationEnv, +} + +impl TypingVisitorConstructor for CombinableBool { + 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 visit_exp_custom(&mut self, exp: &mut T::Exp) -> bool { + let UnannotatedExp_::BinopExp(e1, op, _, e2) = &exp.exp.value else { + return false; + }; + let ( + UnannotatedExp_::BinopExp(lhs1, op1, _, rhs1), + UnannotatedExp_::BinopExp(lhs2, op2, _, rhs2), + ) = (&e1.exp.value, &e2.exp.value) + else { + return false; + }; + // Check both exp side are the same + if lhs1 == lhs2 && rhs1 == rhs2 { + if is_module_call(lhs1) || is_module_call(rhs1) { + return false; + }; + process_combinable_exp(self.env, exp.exp.loc, &op1.value, &op2.value, &op.value); + } + false + } + 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 process_combinable_exp( + env: &mut CompilationEnv, + loc: Loc, + op1: &BinOp_, + op2: &BinOp_, + parent_op: &BinOp_, +) { + match (op1, op2) { + (BinOp_::Eq, BinOp_::Lt) + | (BinOp_::Lt, BinOp_::Eq) + | (BinOp_::Eq, BinOp_::Gt) + | (BinOp_::Gt, BinOp_::Eq) + | (BinOp_::Ge, BinOp_::Eq) + | (BinOp_::Eq, BinOp_::Ge) + | (BinOp_::Le, BinOp_::Eq) + | (BinOp_::Eq, BinOp_::Le) + | (BinOp_::Neq, BinOp_::Lt) + | (BinOp_::Lt, BinOp_::Neq) + | (BinOp_::Neq, BinOp_::Gt) + | (BinOp_::Gt, BinOp_::Neq) => { + suggest_simplification(env, loc, op1, op2, parent_op); + } + _ => {} + } +} + +fn suggest_simplification( + env: &mut CompilationEnv, + loc: Loc, + op1: &BinOp_, + op2: &BinOp_, + parent_op: &BinOp_, +) { + let message = match (op1, op2, parent_op) { + (BinOp_::Eq, BinOp_::Lt, BinOp_::And) + | (BinOp_::Eq, BinOp_::Gt, BinOp_::And) + | (BinOp_::Gt, BinOp_::Eq, BinOp_::And) + | (BinOp_::Lt, BinOp_::Eq, BinOp_::And) => { + "This is always contradictory and can be simplified to false" + } + (BinOp_::Eq, BinOp_::Lt, _) + | (BinOp_::Eq, BinOp_::Gt, _) + | (BinOp_::Lt, BinOp_::Eq, _) + | (BinOp_::Gt, BinOp_::Eq, _) => "Consider simplifying to `<=` or `>=` respectively.", + (BinOp_::Ge, BinOp_::Eq, BinOp_::And) + | (BinOp_::Le, BinOp_::Eq, BinOp_::And) + | (BinOp_::Eq, BinOp_::Le, BinOp_::And) + | (BinOp_::Eq, BinOp_::Ge, BinOp_::And) => "Consider simplifying to `==`.", + (BinOp_::Neq, BinOp_::Lt, BinOp_::And) + | (BinOp_::Neq, BinOp_::Gt, BinOp_::And) + | (BinOp_::Gt, BinOp_::Neq, BinOp_::And) + | (BinOp_::Lt, BinOp_::Neq, BinOp_::And) => { + "Consider simplifying to `<` or `>` respectively." + } + _ => return, + }; + add_replaceable_comparison_diag(env, loc, message); +} + +fn add_replaceable_comparison_diag(env: &mut CompilationEnv, loc: Loc, message: &str) { + let d = diag!(COMBINABLE_BOOL_COND_DIAG, (loc, message)); + env.add_diag(d); +} + +fn is_module_call(exp: &T::Exp) -> bool { + matches!(exp.exp.value, UnannotatedExp_::ModuleCall(_)) +} diff --git a/external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs b/external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs deleted file mode 100644 index a66d97525fb8e..0000000000000 --- a/external-crates/move/crates/move-compiler/src/linters/shift_overflow.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Detect potential overflow scenarios where the number of bits being shifted exceeds the bit width of -//! the variable being shifted, which could lead to unintended behavior or loss of data. If such a -//! potential overflow is detected, a warning is generated to alert the developer. -use crate::{ - diag, - diagnostics::{ - codes::{custom, DiagnosticInfo, Severity}, - WarningFilters, - }, - expansion::ast::Value_, - naming::ast::{BuiltinTypeName_, TypeName_, Type_}, - parser::ast::BinOp_, - shared::{program_info::TypingProgramInfo, CompilationEnv}, - typing::{ - ast::{self as T, UnannotatedExp_}, - visitor::{TypingVisitorConstructor, TypingVisitorContext}, - }, -}; -use move_ir_types::location::Loc; -use std::str::FromStr; - -use super::{LinterDiagCategory, LINTER_DEFAULT_DIAG_CODE, LINT_WARNING_PREFIX}; - -const SHIFT_OPERATION_OVERFLOW_DIAG: DiagnosticInfo = custom( - LINT_WARNING_PREFIX, - Severity::Warning, - LinterDiagCategory::ShiftOperationOverflow as u8, - LINTER_DEFAULT_DIAG_CODE, - "Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted.", -); - -pub struct ShiftOperationOverflow; - -pub struct Context<'a> { - env: &'a mut CompilationEnv, -} - -impl TypingVisitorConstructor for ShiftOperationOverflow { - type Context<'a> = Context<'a>; - - fn context<'a>( - env: &'a mut CompilationEnv, - _program_info: &'a TypingProgramInfo, - _program: &T::Program_, - ) -> Self::Context<'a> { - Context { env } - } -} - -impl TypingVisitorContext for Context<'_> { - fn visit_exp_custom(&mut self, exp: &mut T::Exp) -> bool { - // Check if the expression is a binary operation and if it is a shift operation. - if let UnannotatedExp_::BinopExp(lhs, op, _, rhs) = &exp.exp.value { - // can't do let UnannotatedExp_::BinopExp(lhs, BinOp_::Shl | BinOp_::Shr, _, rhs) = &exp.exp.value else { return }; - // because the op is Spanned and not BinOp_ - if matches!(op.value, BinOp_::Shl | BinOp_::Shr) { - match ( - get_bit_width(&lhs.ty.value), - get_shift_amount(&rhs.exp.value), - ) { - (Some(bit_width), Some(shift_amount)) if shift_amount >= bit_width => { - report_overflow(self.env, shift_amount, bit_width, op.loc); - } - _ => (), - } - } - } - false - } - 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 get_bit_width(ty: &Type_) -> Option { - ty.builtin_name().and_then(|typ| match typ.value { - BuiltinTypeName_::U8 => Some(8), - BuiltinTypeName_::U16 => Some(16), - BuiltinTypeName_::U32 => Some(32), - BuiltinTypeName_::U64 => Some(64), - BuiltinTypeName_::U128 => Some(128), - BuiltinTypeName_::U256 => Some(256), - _ => None, - }) -} - -fn get_shift_amount(value: &UnannotatedExp_) -> Option { - if let UnannotatedExp_::Value(v) = value { - match &v.value { - Value_::U8(v) => Some(*v as u128), - _ => None, - } - } else { - None - } -} - -fn report_overflow(env: &mut CompilationEnv, shift_amount: u128, bit_width: u128, loc: Loc) { - let msg = format!( - "The {} of bits being shifted exceeds the {} bit width of the variable being shifted.", - shift_amount, bit_width - ); - let diag = diag!(SHIFT_OPERATION_OVERFLOW_DIAG, (loc, msg)); - env.add_diag(diag); -} diff --git a/external-crates/move/crates/move-compiler/src/sui_mode/linters/mod.rs b/external-crates/move/crates/move-compiler/src/sui_mode/linters/mod.rs index d308381283f1e..2b2727bba6306 100644 --- a/external-crates/move/crates/move-compiler/src/sui_mode/linters/mod.rs +++ b/external-crates/move/crates/move-compiler/src/sui_mode/linters/mod.rs @@ -13,7 +13,6 @@ use crate::{ }; use move_ir_types::location::Loc; use move_symbol_pool::Symbol; - pub mod coin_field; pub mod collection_equality; pub mod custom_state_change; @@ -24,8 +23,8 @@ pub mod public_mut_tx_context; pub mod public_random; pub mod self_transfer; pub mod share_owned; - pub const SUI_PKG_NAME: &str = "sui"; +pub const INCLUDE_NEW_RULES: bool = true; pub const TRANSFER_MOD_NAME: &str = "transfer"; pub const TRANSFER_FUN: &str = "transfer"; diff --git a/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp b/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp deleted file mode 100644 index ed6efd6a2ea67..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.exp +++ /dev/null @@ -1,24 +0,0 @@ -warning[Lint W00001]: Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted. - ┌─ tests/custom_rules/shift_overflow.move:5:20 - │ -5 │ let _b = x << 64; // Should not raise an issue - │ ^^ The 64 of bits being shifted exceeds the 64 bit width of the variable being shifted. - │ - = This warning can be suppressed with '#[allow(lint(shift_overflow))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W00001]: Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted. - ┌─ tests/custom_rules/shift_overflow.move:6:20 - │ -6 │ let _b = x << 65; // Should raise an issue - │ ^^ The 65 of bits being shifted exceeds the 64 bit width of the variable being shifted. - │ - = This warning can be suppressed with '#[allow(lint(shift_overflow))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W00001]: Potential overflow detected. The number of bits being shifted exceeds the bit width of the variable being shifted. - ┌─ tests/custom_rules/shift_overflow.move:7:20 - │ -7 │ let _b = x >> 66; // Should raise an issue - │ ^^ The 66 of bits being shifted exceeds the 64 bit width of the variable being shifted. - │ - = This warning can be suppressed with '#[allow(lint(shift_overflow))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move b/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move deleted file mode 100644 index e5dc71e6f6563..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/custom_rules/shift_overflow.move +++ /dev/null @@ -1,9 +0,0 @@ -module 0x42::M { - - fun func1(x: u64) { - let _b = x << 24; - let _b = x << 64; // Should raise an issue - let _b = x << 65; // Should raise an issue - let _b = x >> 66; // Should raise an issue - } -} \ No newline at end of file diff --git a/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move b/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move new file mode 100644 index 0000000000000..2458c2a7ce84c --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move @@ -0,0 +1,12 @@ +module 0x42::M { + const ERROR_NUM: u64 = 2; + + public fun func1(x: u64, y: u64, z: u64) { + if (x == y || z < y) {}; + if (x <= y) {}; + if (x >= y) {}; + if (x > y) {}; + if (x < y) {}; + if (x == 11 || x < 3) {}; + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp new file mode 100644 index 0000000000000..73b51ec36c8b7 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp @@ -0,0 +1,40 @@ +warning[Lint W01005]: + ┌─ tests/linter/incorrect_combinable_bool.move:6:13 + │ +6 │ if (x < y || x == y) {}; // should be x <= y + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01005]: + ┌─ tests/linter/incorrect_combinable_bool.move:7:13 + │ +7 │ if (x == y || x > y) {}; // should be x >= y + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01005]: + ┌─ tests/linter/incorrect_combinable_bool.move:8:13 + │ +8 │ if (x > y || x == y) {}; // should be x >= y + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01005]: + ┌─ tests/linter/incorrect_combinable_bool.move:9:13 + │ +9 │ if (m == n || m < n) {}; // should be m <= n + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01005]: + ┌─ tests/linter/incorrect_combinable_bool.move:10:13 + │ +10 │ if (x == 11 || x < 11) {}; + │ ^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move new file mode 100644 index 0000000000000..f83ea801d9cee --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move @@ -0,0 +1,12 @@ +module 0x42::M { + const ERROR_NUM: u64 = 2; + public fun func1(x: u64, y: u64) { + let m = 3; + let n = 4; + if (x < y || x == y) {}; // should be x <= y + if (x == y || x > y) {}; // should be x >= y + if (x > y || x == y) {}; // should be x >= y + if (m == n || m < n) {}; // should be m <= n + if (x == 11 || x < 11) {}; + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp b/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp index 944dd5bdad57f..672a7f5dc9a60 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp @@ -3,14 +3,10 @@ warning[Lint W04001]: constant should follow naming convention │ 3 │ const Another_BadName: u64 = 42; // Should trigger a warning │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 'Another_BadName' should be ALL_CAPS. Or for error constants, use PascalCase - │ - = This warning can be suppressed with '#[allow(lint(constant_naming))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W04001]: constant should follow naming convention ┌─ tests/linter/incorrect_constant_naming.move:4:5 │ 4 │ const JSON_Max_Size: u64 = 1048576; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 'JSON_Max_Size' should be ALL_CAPS. Or for error constants, use PascalCase - │ - = This warning can be suppressed with '#[allow(lint(constant_naming))]' applied to the 'module' or module member ('const', 'fun', or 'struct') diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move index a75210a0364a7..696069c180fe3 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move +++ b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move @@ -2,4 +2,9 @@ module 0x42::M { #[allow(lint(constant_naming))] const Another_BadName: u64 = 42; // Should trigger a warning + + #[allow(lint(combinable_comparison))] + public fun func1(x: u64, y: u64) { + if (x < y || x == y) {}; // should be x <= y + } } From eda788980ca3136413d7cc4bc5e72ee7b00699c7 Mon Sep 17 00:00:00 2001 From: tx-tomcat Date: Wed, 6 Nov 2024 12:01:33 +0700 Subject: [PATCH 03/20] refactor and add testcase --- .../move/crates/move-compiler/Cargo.toml | 2 +- .../src/linters/combinable_bool_conditions.rs | 212 +++++++++--------- .../crates/move-compiler/src/linters/mod.rs | 8 + .../tests/linter/correct_combinable_bool.exp | 66 ++++++ ...se_negative_combinable_bool_conditions.exp | 38 ++++ ...e_negative_combinable_bool_conditions.move | 13 ++ ...se_positive_combinable_bool_conditions.exp | 66 ++++++ ...e_positive_combinable_bool_conditions.move | 12 + .../linter/incorrect_combinable_bool.exp | 75 ++++++- .../linter/incorrect_constant_naming.exp | 4 + .../suppress_combinable_bool_conditions.exp | 22 ++ .../suppress_combinable_bool_conditions.move | 19 ++ .../tests/linter/suppressed_lints.exp | 25 +++ ...ue_negative_combinable_bool_conditions.exp | 50 +++++ ...e_negative_combinable_bool_conditions.move | 18 ++ ...ue_positive_combinable_bool_conditions.exp | 76 +++++++ ...e_positive_combinable_bool_conditions.move | 18 ++ 17 files changed, 609 insertions(+), 115 deletions(-) create mode 100644 external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move create mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move create mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move create mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move create mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp create mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move diff --git a/external-crates/move/crates/move-compiler/Cargo.toml b/external-crates/move/crates/move-compiler/Cargo.toml index b5c70b962a5ba..be56d17130762 100644 --- a/external-crates/move/crates/move-compiler/Cargo.toml +++ b/external-crates/move/crates/move-compiler/Cargo.toml @@ -24,7 +24,7 @@ serde_json.workspace = true similar.workspace = true stacker.workspace = true vfs.workspace = true - +lazy_static = "1.5.0" bcs.workspace = true diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs index bc69a0c94aa6e..e674e5bcc0bed 100644 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs @@ -1,138 +1,142 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + //! The `CombinableBool` detects and warns about boolean conditions in Move code that can be simplified. //! It identifies comparisons that are logically equivalent and suggests more concise alternatives. //! This rule focuses on simplifying expressions involving `==`, `<`, `>`, and `!=` operators to improve code readability. -use move_ir_types::location::Loc; use crate::{ diag, - diagnostics::{ - codes::{custom, DiagnosticInfo, Severity}, - WarningFilters, - }, + linters::StyleCodes, parser::ast::BinOp_, - shared::CompilationEnv, typing::{ ast::{self as T, UnannotatedExp_}, - visitor::{TypingVisitorConstructor, TypingVisitorContext}, + visitor::simple_visitor, }, }; +use lazy_static::lazy_static; +use move_ir_types::location::Loc; +use std::collections::HashMap; -use super::{LinterDiagnosticCategory, COMBINABLE_COMPARISON_DIAG_CODE, LINT_WARNING_PREFIX}; - -const COMBINABLE_BOOL_COND_DIAG: DiagnosticInfo = custom( - LINT_WARNING_PREFIX, - Severity::Warning, - LinterDiagnosticCategory::Complexity as u8, - COMBINABLE_COMPARISON_DIAG_CODE, - "", -); - -pub struct CombinableBool; - -pub struct Context<'a> { - env: &'a mut CompilationEnv, +#[derive(Debug, Clone, Copy)] +enum Simplification { + Contradiction, + UseComparison, + UseEquality, } -impl TypingVisitorConstructor for CombinableBool { - type Context<'a> = Context<'a>; - - fn context<'a>(env: &'a mut CompilationEnv, _program: &T::Program) -> Self::Context<'a> { - Context { env } +impl Simplification { + fn message(&self) -> &'static str { + match self { + Simplification::Contradiction => { + "This is always contradictory and can be simplified to false" + } + Simplification::UseComparison => "Consider simplifying to `<=` or `>=` respectively.", + Simplification::UseEquality => "Consider simplifying to `==`.", + } } } -impl TypingVisitorContext for Context<'_> { - fn visit_exp_custom(&mut self, exp: &mut T::Exp) -> bool { - let UnannotatedExp_::BinopExp(e1, op, _, e2) = &exp.exp.value else { - return false; - }; - let ( - UnannotatedExp_::BinopExp(lhs1, op1, _, rhs1), - UnannotatedExp_::BinopExp(lhs2, op2, _, rhs2), - ) = (&e1.exp.value, &e2.exp.value) - else { - return false; - }; - // Check both exp side are the same - if lhs1 == lhs2 && rhs1 == rhs2 { - if is_module_call(lhs1) || is_module_call(rhs1) { - return false; - }; - process_combinable_exp(self.env, exp.exp.loc, &op1.value, &op2.value, &op.value); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum Operator { + Eq, + Lt, + Gt, + Le, + Ge, + And, + Or, +} + +impl From<&BinOp_> for Operator { + fn from(op: &BinOp_) -> Self { + match op { + BinOp_::Eq => Operator::Eq, + BinOp_::Lt => Operator::Lt, + BinOp_::Gt => Operator::Gt, + BinOp_::Le => Operator::Le, + BinOp_::Ge => Operator::Ge, + BinOp_::And => Operator::And, + BinOp_::Or => Operator::Or, + _ => panic!("Unexpected operator"), } - false - } - 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() - } +lazy_static! { + static ref OPERATOR_COMBINATIONS: HashMap<(Operator, Operator, Operator), Simplification> = { + let mut m = HashMap::new(); + // Contradictions + for ops in [(Operator::Eq, Operator::Lt), (Operator::Eq, Operator::Gt)] { + m.insert((ops.0, ops.1, Operator::And), Simplification::Contradiction); + m.insert((ops.1, ops.0, Operator::And), Simplification::Contradiction); + } + // Use comparison operators + for ops in [(Operator::Eq, Operator::Lt), (Operator::Eq, Operator::Gt)] { + m.insert((ops.0, ops.1, Operator::Or), Simplification::UseComparison); + m.insert((ops.1, ops.0, Operator::Or), Simplification::UseComparison); + } + // Use equality + for ops in [(Operator::Ge, Operator::Eq), (Operator::Le, Operator::Eq)] { + m.insert((ops.0, ops.1, Operator::And), Simplification::UseEquality); + m.insert((ops.1, ops.0, Operator::And), Simplification::UseEquality); + } + m + }; } -fn process_combinable_exp( - env: &mut CompilationEnv, - loc: Loc, - op1: &BinOp_, - op2: &BinOp_, - parent_op: &BinOp_, -) { - match (op1, op2) { - (BinOp_::Eq, BinOp_::Lt) - | (BinOp_::Lt, BinOp_::Eq) - | (BinOp_::Eq, BinOp_::Gt) - | (BinOp_::Gt, BinOp_::Eq) - | (BinOp_::Ge, BinOp_::Eq) - | (BinOp_::Eq, BinOp_::Ge) - | (BinOp_::Le, BinOp_::Eq) - | (BinOp_::Eq, BinOp_::Le) - | (BinOp_::Neq, BinOp_::Lt) - | (BinOp_::Lt, BinOp_::Neq) - | (BinOp_::Neq, BinOp_::Gt) - | (BinOp_::Gt, BinOp_::Neq) => { - suggest_simplification(env, loc, op1, op2, parent_op); +simple_visitor!( + CombinableBoolConditionsVisitor, + fn visit_exp_custom(&mut self, exp: &T::Exp) -> bool { + if let UnannotatedExp_::BinopExp(e1, op, _, e2) = &exp.exp.value { + if let ( + UnannotatedExp_::BinopExp(lhs1, op1, _, rhs1), + UnannotatedExp_::BinopExp(lhs2, op2, _, rhs2), + ) = (&e1.exp.value, &e2.exp.value) + { + check_combinable_conditions( + self, + exp.exp.loc, + lhs1, + rhs1, + lhs2, + rhs2, + &op1.value, + &op2.value, + &op.value, + ); + } } - _ => {} + + false } -} +); -fn suggest_simplification( - env: &mut CompilationEnv, +fn check_combinable_conditions( + context: &mut Context, loc: Loc, + lhs1: &T::Exp, + rhs1: &T::Exp, + lhs2: &T::Exp, + rhs2: &T::Exp, op1: &BinOp_, op2: &BinOp_, parent_op: &BinOp_, ) { - let message = match (op1, op2, parent_op) { - (BinOp_::Eq, BinOp_::Lt, BinOp_::And) - | (BinOp_::Eq, BinOp_::Gt, BinOp_::And) - | (BinOp_::Gt, BinOp_::Eq, BinOp_::And) - | (BinOp_::Lt, BinOp_::Eq, BinOp_::And) => { - "This is always contradictory and can be simplified to false" - } - (BinOp_::Eq, BinOp_::Lt, _) - | (BinOp_::Eq, BinOp_::Gt, _) - | (BinOp_::Lt, BinOp_::Eq, _) - | (BinOp_::Gt, BinOp_::Eq, _) => "Consider simplifying to `<=` or `>=` respectively.", - (BinOp_::Ge, BinOp_::Eq, BinOp_::And) - | (BinOp_::Le, BinOp_::Eq, BinOp_::And) - | (BinOp_::Eq, BinOp_::Le, BinOp_::And) - | (BinOp_::Eq, BinOp_::Ge, BinOp_::And) => "Consider simplifying to `==`.", - (BinOp_::Neq, BinOp_::Lt, BinOp_::And) - | (BinOp_::Neq, BinOp_::Gt, BinOp_::And) - | (BinOp_::Gt, BinOp_::Neq, BinOp_::And) - | (BinOp_::Lt, BinOp_::Neq, BinOp_::And) => { - "Consider simplifying to `<` or `>` respectively." + if lhs1 == lhs2 && rhs1 == rhs2 && !is_module_call(lhs1) && !is_module_call(rhs1) { + let key = ( + Operator::from(op1), + Operator::from(op2), + Operator::from(parent_op), + ); + if let Some(simplification) = OPERATOR_COMBINATIONS.get(&key) { + let diagnostic = diag!( + StyleCodes::CombinableBoolConditions.diag_info(), + (loc, simplification.message()) + ); + context.add_diag(diagnostic); // Using context instead of self } - _ => return, - }; - add_replaceable_comparison_diag(env, loc, message); -} - -fn add_replaceable_comparison_diag(env: &mut CompilationEnv, loc: Loc, message: &str) { - let d = diag!(COMBINABLE_BOOL_COND_DIAG, (loc, message)); - env.add_diag(d); + } } fn is_module_call(exp: &T::Exp) -> bool { diff --git a/external-crates/move/crates/move-compiler/src/linters/mod.rs b/external-crates/move/crates/move-compiler/src/linters/mod.rs index 6f02e2e2cd4a9..bcfae4e862e20 100644 --- a/external-crates/move/crates/move-compiler/src/linters/mod.rs +++ b/external-crates/move/crates/move-compiler/src/linters/mod.rs @@ -14,6 +14,7 @@ use crate::{ }; pub mod abort_constant; +pub mod combinable_bool_conditions; pub mod constant_naming; pub mod loop_without_exit; pub mod meaningless_math_operation; @@ -162,6 +163,12 @@ lints!( "unnecessary_unit", "unit `()` expression can be removed or simplified" ), + ( + CombinableBoolConditions, + LinterDiagnosticCategory::Complexity, + "combinable_bool_conditions", + "boolean condition can be simplified" + ) ); pub const ALLOW_ATTR_CATEGORY: &str = "lint"; @@ -199,6 +206,7 @@ pub fn linter_visitors(level: LintLevel) -> Vec { self_assignment::SelfAssignmentVisitor.visitor(), redundant_ref_deref::RedundantRefDerefVisitor.visitor(), unnecessary_unit::UnnecessaryUnit.visitor(), + combinable_bool_conditions::CombinableBoolConditionsVisitor.visitor(), ] } } diff --git a/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp b/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp new file mode 100644 index 0000000000000..326c96976772c --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp @@ -0,0 +1,66 @@ +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/correct_combinable_bool.move:5:30 + │ +5 │ if (x == y || z < y) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/correct_combinable_bool.move:6:21 + │ +6 │ if (x <= y) {}; + │ ------ ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/correct_combinable_bool.move:7:21 + │ +7 │ if (x >= y) {}; + │ ------ ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/correct_combinable_bool.move:8:20 + │ +8 │ if (x > y) {}; + │ ----- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/correct_combinable_bool.move:9:20 + │ +9 │ if (x < y) {}; + │ ----- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/correct_combinable_bool.move:10:31 + │ +10 │ if (x == 11 || x < 3) {}; + │ ---------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp new file mode 100644 index 0000000000000..c73b8aed5c742 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp @@ -0,0 +1,38 @@ +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/false_negative_combinable_bool_conditions.move:7:13 + │ +7 │ if ((x + 5) == (y - 5) || (x + 5) < (y - 5)) {}; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/false_negative_combinable_bool_conditions.move:7:54 + │ +7 │ if ((x + 5) == (y - 5) || (x + 5) < (y - 5)) {}; + │ --------------------------------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/false_negative_combinable_bool_conditions.move:10:13 + │ +10 │ if (y > x || y == x) {}; + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/false_negative_combinable_bool_conditions.move:10:30 + │ +10 │ if (y > x || y == x) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move new file mode 100644 index 0000000000000..f7aae071f76f2 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move @@ -0,0 +1,13 @@ +module 0x42::false_negative_combinable_bool_conditions { + fun test_false_negatives() { + let x = 10; + let y = 20; + + // Case 1: Complex but equivalent expressions that could be simplified + if ((x + 5) == (y - 5) || (x + 5) < (y - 5)) {}; + + // Case 2: Reversed order of operands + if (y > x || y == x) {}; + } + +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp new file mode 100644 index 0000000000000..a144f5c0441ca --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp @@ -0,0 +1,66 @@ +error[E03005]: unbound unscoped name + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:13 + │ +7 │ if (get_value() == y || get_value() < y) {}; + │ ^^^^^^^^^ Unbound function 'get_value' in current scope + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:13 + │ +7 │ if (get_value() == y || get_value() < y) {}; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +error[E03005]: unbound unscoped name + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:33 + │ +7 │ if (get_value() == y || get_value() < y) {}; + │ ^^^^^^^^^ Unbound function 'get_value' in current scope + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:50 + │ +7 │ if (get_value() == y || get_value() < y) {}; + │ ----------------------------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +error[E13001]: feature is not supported in specified edition + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:13 + │ +10 │ if (x as u64 == y || x as u64 < y) {}; + │ ^ 'as' without parentheses is not supported by current edition 'legacy', only '2024.alpha' and '2024.beta' support this feature + │ + = You can update the edition in the 'Move.toml', or via command line flag if invoking the compiler directly. + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:13 + │ +10 │ if (x as u64 == y || x as u64 < y) {}; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +error[E13001]: feature is not supported in specified edition + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:30 + │ +10 │ if (x as u64 == y || x as u64 < y) {}; + │ ^ 'as' without parentheses is not supported by current edition 'legacy', only '2024.alpha' and '2024.beta' support this feature + │ + = You can update the edition in the 'Move.toml', or via command line flag if invoking the compiler directly. + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:44 + │ +10 │ if (x as u64 == y || x as u64 < y) {}; + │ ----------------------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move new file mode 100644 index 0000000000000..6188a4c1bb59c --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move @@ -0,0 +1,12 @@ +module 0x42::false_positive_combinable_bool_conditions { + fun test_false_positives() { + let x = 10; + let y = 20; + + // Case 1: When order matters due to side effects + if (get_value() == y || get_value() < y) {}; + + // Case 2: When precision matters in floating point comparisons + if (x as u64 == y || x as u64 < y) {}; + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp index 73b51ec36c8b7..73a38c4578166 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp @@ -1,40 +1,95 @@ -warning[Lint W01005]: +warning[Lint W01011]: boolean condition can be simplified ┌─ tests/linter/incorrect_combinable_bool.move:6:13 │ 6 │ if (x < y || x == y) {}; // should be x <= y │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. │ - = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') -warning[Lint W01005]: +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/incorrect_combinable_bool.move:6:30 + │ +6 │ if (x < y || x == y) {}; // should be x <= y + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01011]: boolean condition can be simplified ┌─ tests/linter/incorrect_combinable_bool.move:7:13 │ 7 │ if (x == y || x > y) {}; // should be x >= y │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. │ - = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/incorrect_combinable_bool.move:7:30 + │ +7 │ if (x == y || x > y) {}; // should be x >= y + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') -warning[Lint W01005]: +warning[Lint W01011]: boolean condition can be simplified ┌─ tests/linter/incorrect_combinable_bool.move:8:13 │ 8 │ if (x > y || x == y) {}; // should be x >= y │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. │ - = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/incorrect_combinable_bool.move:8:30 + │ +8 │ if (x > y || x == y) {}; // should be x >= y + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') -warning[Lint W01005]: +warning[Lint W01011]: boolean condition can be simplified ┌─ tests/linter/incorrect_combinable_bool.move:9:13 │ 9 │ if (m == n || m < n) {}; // should be m <= n │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. │ - = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/incorrect_combinable_bool.move:9:30 + │ +9 │ if (m == n || m < n) {}; // should be m <= n + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') -warning[Lint W01005]: +warning[Lint W01011]: boolean condition can be simplified ┌─ tests/linter/incorrect_combinable_bool.move:10:13 │ 10 │ if (x == 11 || x < 11) {}; │ ^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. │ - = This warning can be suppressed with '#[allow(lint(combinable_comparison))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/incorrect_combinable_bool.move:10:32 + │ +10 │ if (x == 11 || x < 11) {}; + │ ----------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp b/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp index 672a7f5dc9a60..944dd5bdad57f 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/incorrect_constant_naming.exp @@ -3,10 +3,14 @@ warning[Lint W04001]: constant should follow naming convention │ 3 │ const Another_BadName: u64 = 42; // Should trigger a warning │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 'Another_BadName' should be ALL_CAPS. Or for error constants, use PascalCase + │ + = This warning can be suppressed with '#[allow(lint(constant_naming))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W04001]: constant should follow naming convention ┌─ tests/linter/incorrect_constant_naming.move:4:5 │ 4 │ const JSON_Max_Size: u64 = 1048576; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 'JSON_Max_Size' should be ALL_CAPS. Or for error constants, use PascalCase + │ + = This warning can be suppressed with '#[allow(lint(constant_naming))]' applied to the 'module' or module member ('const', 'fun', or 'struct') diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp new file mode 100644 index 0000000000000..70ba2a5047c44 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp @@ -0,0 +1,22 @@ +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/suppress_combinable_bool_conditions.move:8:30 + │ +8 │ if (x == y || x < y) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/suppress_combinable_bool_conditions.move:11:50 + │ +11 │ if (get_value() == y || get_value() < y) {}; + │ ----------------------------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move new file mode 100644 index 0000000000000..6b1b7557048b1 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move @@ -0,0 +1,19 @@ +module 0x42::suppress_combinable_bool_conditions { + #[lint_allow(combinable_bool_conditions)] + fun test_suppressed_cases() { + let x = 10; + let y = 20; + + // Case 1: Suppressed at function level + if (x == y || x < y) {}; + + // Case 2: Explicit false positive case that we want to suppress + if (get_value() == y || get_value() < y) {}; + } + + // Helper function for demonstrating side effects + fun get_value(): u64 { + // Imagine this has side effects + 10 + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp new file mode 100644 index 0000000000000..457d4eaa6cb96 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp @@ -0,0 +1,25 @@ +warning[W10007]: issue with attribute value + ┌─ tests/linter/suppressed_lints.move:6:18 + │ +6 │ #[allow(lint(combinable_comparison))] + │ ^^^^^^^^^^^^^^^^^^^^^ Unknown warning filter 'lint(combinable_comparison)' + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/suppressed_lints.move:8:13 + │ +8 │ if (x < y || x == y) {}; // should be x <= y + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/suppressed_lints.move:8:30 + │ +8 │ if (x < y || x == y) {}; // should be x <= y + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp new file mode 100644 index 0000000000000..4183ad699246e --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp @@ -0,0 +1,50 @@ +error[E03009]: unbound variable + ┌─ tests/linter/true_negative_combinable_bool_conditions.move:7:23 + │ +7 │ if (x == y || z < y) {}; + │ ^ Unbound variable 'z' + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_negative_combinable_bool_conditions.move:7:30 + │ +7 │ if (x == y || z < y) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_negative_combinable_bool_conditions.move:10:29 + │ +10 │ if (x > y || x < y) {}; + │ -------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_negative_combinable_bool_conditions.move:13:42 + │ +13 │ if ((x + 1) == y || (x - 1) < y) {}; + │ --------------------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_negative_combinable_bool_conditions.move:16:30 + │ +16 │ if (x != y && x > 0) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move new file mode 100644 index 0000000000000..beba21ef1f96c --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move @@ -0,0 +1,18 @@ +module 0x42::true_negative_combinable_bool_conditions { + fun test_true_negatives() { + let x = 10; + let y = 20; + + // Case 1: Different variables in comparison + if (x == y || z < y) {}; + + // Case 2: Different operators that don't have simplification + if (x > y || x < y) {}; + + // Case 3: Complex expressions + if ((x + 1) == y || (x - 1) < y) {}; + + // Case 4: Non-combinable operators + if (x != y && x > 0) {}; + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp new file mode 100644 index 0000000000000..a37cdb1d23bd8 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp @@ -0,0 +1,76 @@ +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:7:13 + │ +7 │ if (x == y || x < y) {}; + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:7:30 + │ +7 │ if (x == y || x < y) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:10:13 + │ +10 │ if (x == y && x > y) {}; + │ ^^^^^^^^^^^^^^^ This is always contradictory and can be simplified to false + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:10:30 + │ +10 │ if (x == y && x > y) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:13:13 + │ +13 │ if (x >= y && x == y) {}; + │ ^^^^^^^^^^^^^^^^ Consider simplifying to `==`. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:13:31 + │ +13 │ if (x >= y && x == y) {}; + │ ---------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01011]: boolean condition can be simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:16:13 + │ +16 │ if (x == y || x > y) {}; + │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. + │ + = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W04010]: unit `()` expression can be removed or simplified + ┌─ tests/linter/true_positive_combinable_bool_conditions.move:16:30 + │ +16 │ if (x == y || x > y) {}; + │ --------------- ^^ Unnecessary unit '()' + │ │ + │ Consider negating the 'if' condition and simplifying + │ + = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' + = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move new file mode 100644 index 0000000000000..cbe39a783c7b1 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move @@ -0,0 +1,18 @@ +module 0x42::true_positive_combinable_bool_conditions { + fun test_true_positives() { + let x = 10; + let y = 20; + + // Case 1: x == y || x < y should be x <= y + if (x == y || x < y) {}; + + // Case 2: x == y && x > y is a contradiction (always false) + if (x == y && x > y) {}; + + // Case 3: x >= y && x == y should be x == y + if (x >= y && x == y) {}; + + // Case 4: x == y || x > y should be x >= y + if (x == y || x > y) {}; + } +} From c76f16883139ff192afe0a03ba4d9778ded95401 Mon Sep 17 00:00:00 2001 From: tx-tomcat Date: Wed, 6 Nov 2024 12:02:06 +0700 Subject: [PATCH 04/20] add lazy_static --- external-crates/move/Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/external-crates/move/Cargo.lock b/external-crates/move/Cargo.lock index 79134dc343a33..db78686c6a56b 100644 --- a/external-crates/move/Cargo.lock +++ b/external-crates/move/Cargo.lock @@ -1823,6 +1823,7 @@ dependencies = [ "datatest-stable", "dunce", "hex", + "lazy_static", "lsp-types", "move-binary-format", "move-borrow-graph", From e2d0c86d4909bb4991c1ad35865a60915f3151d3 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Wed, 4 Dec 2024 14:31:21 -0800 Subject: [PATCH 05/20] rename --- Cargo.lock | 1 + .../{combinable_bool_conditions.rs => combinable_conditions.rs} | 0 2 files changed, 1 insertion(+) rename external-crates/move/crates/move-compiler/src/linters/{combinable_bool_conditions.rs => combinable_conditions.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index a9dac90a8351a..012e809da72c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7595,6 +7595,7 @@ dependencies = [ "codespan-reporting", "dunce", "hex", + "lazy_static", "lsp-types", "move-binary-format", "move-borrow-graph", diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs similarity index 100% rename from external-crates/move/crates/move-compiler/src/linters/combinable_bool_conditions.rs rename to external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs From be60d7b4cdc579cedaf7a26670d64338b803c2a8 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Wed, 4 Dec 2024 19:46:32 -0800 Subject: [PATCH 06/20] rewrite --- .../src/linters/combinable_conditions.rs | 391 +++++++++++++----- 1 file changed, 285 insertions(+), 106 deletions(-) diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs index e674e5bcc0bed..3cc0aa23729a6 100644 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs @@ -6,139 +6,318 @@ //! This rule focuses on simplifying expressions involving `==`, `<`, `>`, and `!=` operators to improve code readability. use crate::{ + cfgir::visitor::{same_value_exp, simple_visitor}, diag, + hlir::ast::{self as H, UnannotatedExp_}, linters::StyleCodes, - parser::ast::BinOp_, - typing::{ - ast::{self as T, UnannotatedExp_}, - visitor::simple_visitor, - }, + parser::ast::{BinOp, BinOp_}, }; -use lazy_static::lazy_static; -use move_ir_types::location::Loc; -use std::collections::HashMap; +use move_ir_types::location::*; #[derive(Debug, Clone, Copy)] enum Simplification { - Contradiction, - UseComparison, - UseEquality, + Reducible(InnerOp_), + AlwaysTrue, + AlwaysFalse, } -impl Simplification { - fn message(&self) -> &'static str { - match self { - Simplification::Contradiction => { - "This is always contradictory and can be simplified to false" - } - Simplification::UseComparison => "Consider simplifying to `<=` or `>=` respectively.", - Simplification::UseEquality => "Consider simplifying to `==`.", - } - } +// impl Simplification { +// fn message(&self) -> &'static str { +// match self { +// Simplification::SameOp +// Simplification::Contradiction => { +// "This is always contradictory and can be simplified to false" +// } +// Simplification::UseComparison => "Consider simplifying to `<=` or `>=` respectively.", +// Simplification::UseEquality => "Consider simplifying to `==`.", +// } +// } +// } + +#[derive(Debug, Clone, Copy)] +enum OuterOp_ { + And, + Or, } +type OuterOp = Spanned; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum Operator { +#[derive(Debug, Clone, Copy)] +enum InnerOp_ { Eq, + Neq, Lt, Gt, Le, Ge, - And, - Or, -} - -impl From<&BinOp_> for Operator { - fn from(op: &BinOp_) -> Self { - match op { - BinOp_::Eq => Operator::Eq, - BinOp_::Lt => Operator::Lt, - BinOp_::Gt => Operator::Gt, - BinOp_::Le => Operator::Le, - BinOp_::Ge => Operator::Ge, - BinOp_::And => Operator::And, - BinOp_::Or => Operator::Or, - _ => panic!("Unexpected operator"), - } - } -} - -lazy_static! { - static ref OPERATOR_COMBINATIONS: HashMap<(Operator, Operator, Operator), Simplification> = { - let mut m = HashMap::new(); - // Contradictions - for ops in [(Operator::Eq, Operator::Lt), (Operator::Eq, Operator::Gt)] { - m.insert((ops.0, ops.1, Operator::And), Simplification::Contradiction); - m.insert((ops.1, ops.0, Operator::And), Simplification::Contradiction); - } - // Use comparison operators - for ops in [(Operator::Eq, Operator::Lt), (Operator::Eq, Operator::Gt)] { - m.insert((ops.0, ops.1, Operator::Or), Simplification::UseComparison); - m.insert((ops.1, ops.0, Operator::Or), Simplification::UseComparison); - } - // Use equality - for ops in [(Operator::Ge, Operator::Eq), (Operator::Le, Operator::Eq)] { - m.insert((ops.0, ops.1, Operator::And), Simplification::UseEquality); - m.insert((ops.1, ops.0, Operator::And), Simplification::UseEquality); - } - m - }; } +type InnerOp = Spanned; simple_visitor!( CombinableBoolConditionsVisitor, - fn visit_exp_custom(&mut self, exp: &T::Exp) -> bool { - if let UnannotatedExp_::BinopExp(e1, op, _, e2) = &exp.exp.value { - if let ( - UnannotatedExp_::BinopExp(lhs1, op1, _, rhs1), - UnannotatedExp_::BinopExp(lhs2, op2, _, rhs2), - ) = (&e1.exp.value, &e2.exp.value) - { - check_combinable_conditions( - self, - exp.exp.loc, - lhs1, - rhs1, - lhs2, - rhs2, - &op1.value, - &op2.value, - &op.value, - ); + fn visit_exp_custom(&mut self, exp: &H::Exp) -> bool { + use H::UnannotatedExp_ as E; + let E::BinopExp(outer_l, outer_bop, outer_r) = &exp.exp.value else { + return false; + }; + let E::BinopExp(l1, op_l, r1) = &outer_l.exp.value else { + return false; + }; + let E::BinopExp(l2, op_r, r2) = &outer_r.exp.value else { + return false; + }; + let Some((outer, inner_l, inner_r)) = binop_case(outer_bop, l1, op_l, r1, l2, op_r, r2) + else { + return false; + }; + let simplification = match outer.value { + OuterOp_::And => simplify_and(inner_l, inner_r), + OuterOp_::Or => simplify_or(inner_l, inner_r), + }; + let msg = match simplification { + Simplification::Reducible(inner_op) => { + format!("to just the operation '{}'", inner_op) } - } + Simplification::AlwaysTrue => "is always 'true'".to_string(), + Simplification::AlwaysFalse => "is always 'false'".to_string(), + }; + self.reporter.add_diag(diag!( + StyleCodes::CombinableBoolConditions.diag_info(), + (exp.exp.loc, format!("This comparison {msg}")), + )); false } ); -fn check_combinable_conditions( - context: &mut Context, - loc: Loc, - lhs1: &T::Exp, - rhs1: &T::Exp, - lhs2: &T::Exp, - rhs2: &T::Exp, - op1: &BinOp_, - op2: &BinOp_, - parent_op: &BinOp_, -) { - if lhs1 == lhs2 && rhs1 == rhs2 && !is_module_call(lhs1) && !is_module_call(rhs1) { - let key = ( - Operator::from(op1), - Operator::from(op2), - Operator::from(parent_op), - ); - if let Some(simplification) = OPERATOR_COMBINATIONS.get(&key) { - let diagnostic = diag!( - StyleCodes::CombinableBoolConditions.diag_info(), - (loc, simplification.message()) - ); - context.add_diag(diagnostic); // Using context instead of self +fn simplify_and(op1: InnerOp, op2: InnerOp) -> Simplification { + use InnerOp_ as I; + Simplification::Reducible(match (op1.value, op2.value) { + // same operation + (I::Eq, I::Eq) + | (I::Neq, I::Neq) + | (I::Ge, I::Ge) + | (I::Le, I::Le) + | (I::Lt, I::Lt) + | (I::Gt, I::Gt) => op1.value, + + // contradiction + (I::Lt, I::Gt) + | (I::Gt, I::Lt) + | (I::Lt, I::Ge) + | (I::Ge, I::Lt) + | (I::Le, I::Gt) + | (I::Gt, I::Le) + | (I::Eq, I::Lt) + | (I::Lt, I::Eq) + | (I::Eq, I::Gt) + | (I::Gt, I::Eq) + | (I::Neq, I::Eq) + | (I::Eq, I::Neq) => return Simplification::AlwaysFalse, + + // == + (I::Le, I::Ge) + | (I::Ge, I::Le) + | (I::Ge, I::Eq) + | (I::Eq, I::Ge) + | (I::Le, I::Eq) + | (I::Eq, I::Le) => I::Eq, + + // < + (I::Lt, I::Le) + | (I::Le, I::Lt) + | (I::Lt, I::Neq) + | (I::Neq, I::Lt) + | (I::Le, I::Neq) + | (I::Neq, I::Le) => I::Lt, + // > + (I::Gt, I::Ge) + | (I::Ge, I::Gt) + | (I::Gt, I::Neq) + | (I::Neq, I::Gt) + | (I::Ge, I::Neq) + | (I::Neq, I::Ge) => I::Gt, + }) +} + +fn simplify_or(op1: InnerOp, op2: InnerOp) -> Simplification { + use InnerOp_ as I; + Simplification::Reducible(match (op1.value, op2.value) { + // same operation + (I::Eq, I::Eq) + | (I::Neq, I::Neq) + | (I::Ge, I::Ge) + | (I::Le, I::Le) + | (I::Lt, I::Lt) + | (I::Gt, I::Gt) => op1.value, + + // tautology + (I::Neq, I::Le) + | (I::Neq, I::Ge) + | (I::Le, I::Neq) + | (I::Ge, I::Neq) + | (I::Gt, I::Le) + | (I::Le, I::Gt) + | (I::Lt, I::Ge) + | (I::Ge, I::Lt) + | (I::Ge, I::Le) + | (I::Le, I::Ge) + | (I::Neq, I::Eq) + | (I::Eq, I::Neq) => return Simplification::AlwaysTrue, + + // != + (I::Neq, I::Lt) + | (I::Neq, I::Gt) + | (I::Lt, I::Neq) + | (I::Gt, I::Neq) + | (I::Lt, I::Gt) + | (I::Gt, I::Lt) => I::Neq, + + // <= + (I::Lt, I::Le) + | (I::Le, I::Lt) + | (I::Eq, I::Lt) + | (I::Lt, I::Eq) + | (I::Eq, I::Le) + | (I::Le, I::Eq) => I::Le, + // >= + (I::Gt, I::Ge) + | (I::Ge, I::Gt) + | (I::Eq, I::Gt) + | (I::Eq, I::Ge) + | (I::Gt, I::Eq) + | (I::Ge, I::Eq) => I::Ge, + }) +} + +fn outer(sp!(loc, bop_): &BinOp) -> Option { + let op_ = match bop_ { + BinOp_::And => OuterOp_::And, + BinOp_::Or => OuterOp_::Or, + BinOp_::Eq + | BinOp_::Lt + | BinOp_::Gt + | BinOp_::Le + | BinOp_::Ge + | BinOp_::Add + | BinOp_::Sub + | BinOp_::Mul + | BinOp_::Mod + | BinOp_::Div + | BinOp_::BitOr + | BinOp_::BitAnd + | BinOp_::Xor + | BinOp_::Shl + | BinOp_::Shr + | BinOp_::Range + | BinOp_::Implies + | BinOp_::Iff + | BinOp_::Neq => return None, + }; + Some(sp(*loc, op_)) +} + +fn inner(sp!(loc, bop_): &BinOp) -> Option { + let op_ = match bop_ { + BinOp_::Eq => InnerOp_::Eq, + BinOp_::Neq => InnerOp_::Neq, + BinOp_::Lt => InnerOp_::Lt, + BinOp_::Gt => InnerOp_::Gt, + BinOp_::Le => InnerOp_::Le, + BinOp_::Ge => InnerOp_::Ge, + + BinOp_::Add + | BinOp_::Sub + | BinOp_::Mul + | BinOp_::Mod + | BinOp_::Div + | BinOp_::BitOr + | BinOp_::BitAnd + | BinOp_::Xor + | BinOp_::Shl + | BinOp_::Shr + | BinOp_::Range + | BinOp_::Implies + | BinOp_::Iff + | BinOp_::And + | BinOp_::Or => return None, + }; + Some(sp(*loc, op_)) +} + +fn flip(sp!(loc, op_): InnerOp) -> InnerOp { + sp( + loc, + match op_ { + InnerOp_::Eq => InnerOp_::Eq, + InnerOp_::Neq => InnerOp_::Neq, + InnerOp_::Lt => InnerOp_::Gt, + InnerOp_::Gt => InnerOp_::Lt, + InnerOp_::Le => InnerOp_::Ge, + InnerOp_::Ge => InnerOp_::Le, + }, + ) +} + +fn binop_case( + outer_bop: &BinOp, + l1: &H::Exp, + op_l: &BinOp, + r1: &H::Exp, + l2: &H::Exp, + op_r: &BinOp, + r2: &H::Exp, +) -> Option<(OuterOp, InnerOp, InnerOp)> { + let outer = outer(outer_bop)?; + let inner_l = inner(op_l)?; + let inner_r = inner(op_r)?; + let (inner_l, inner_r) = operand_case(l1, inner_l, r1, l2, inner_r, r2)?; + Some((outer, inner_l, inner_r)) +} + +fn operand_case( + l1: &H::Exp, + op1: InnerOp, + r1: &H::Exp, + l2: &H::Exp, + op2: InnerOp, + r2: &H::Exp, +) -> Option<(InnerOp, InnerOp)> { + if same_value_exp(l1, l2) && same_value_exp(r1, r2) { + // a1 := l1 + // a2 := l2 + // b1 := r1 + // b2 := r2 + if same_value_exp(l1, r1) { + // Covered by EqualOperands + None + } else { + Some((op1, op2)) } + } else if same_value_exp(l1, r2) && same_value_exp(r1, l2) { + // a1 := l1 + // a2 := r2 + // b1 := r1 + // b2 := l2 + Some((op1, flip(op2))) + } else { + None } } -fn is_module_call(exp: &T::Exp) -> bool { - matches!(exp.exp.value, UnannotatedExp_::ModuleCall(_)) +impl std::fmt::Display for InnerOp_ { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use InnerOp_ as I; + write!( + f, + "{}", + match self { + I::Eq => "==", + I::Neq => "!=", + I::Lt => "<", + I::Gt => ">", + I::Le => "<=", + I::Ge => ">=", + } + ) + } } From d19e89f12812dc9b23e1f27fb380832a0765936f Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 10:36:45 -0800 Subject: [PATCH 07/20] rename enums --- .../src/linters/combinable_comparisons.rs | 302 ++++++++++++++++ .../src/linters/combinable_conditions.rs | 323 ------------------ .../crates/move-compiler/src/linters/mod.rs | 10 +- 3 files changed, 307 insertions(+), 328 deletions(-) create mode 100644 external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs delete mode 100644 external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs new file mode 100644 index 0000000000000..cff5f30631e44 --- /dev/null +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs @@ -0,0 +1,302 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +//! The `CombinableBool` detects and warns about boolean conditions in Move code that can be simplified. +//! It identifies comparisons that are logically equivalent and suggests more concise alternatives. +//! This rule focuses on simplifying expressions involving `==`, `<`, `>`, and `!=` operators to improve code readability. + +use crate::{ + cfgir::visitor::{same_value_exp, simple_visitor}, + diag, + hlir::ast::{self as H}, + linters::StyleCodes, + parser::ast::{BinOp, BinOp_}, +}; + +#[derive(Debug, Clone, Copy)] +enum Simplification { + Reducible(CmpOp), + AlwaysTrue, + AlwaysFalse, +} + +// impl Simplification { +// fn message(&self) -> &'static str { +// match self { +// Simplification::SameOp +// Simplification::Contradiction => { +// "This is always contradictory and can be simplified to false" +// } +// Simplification::UseComparison => "Consider simplifying to `<=` or `>=` respectively.", +// Simplification::UseEquality => "Consider simplifying to `==`.", +// } +// } +// } + +#[derive(Debug, Clone, Copy)] +enum BoolOp { + And, + Or, +} + +#[derive(Debug, Clone, Copy)] +enum CmpOp { + Eq, + Neq, + Lt, + Gt, + Le, + Ge, +} + +simple_visitor!( + CombinableBoolConditionsVisitor, + fn visit_exp_custom(&mut self, exp: &H::Exp) -> bool { + use H::UnannotatedExp_ as E; + let E::BinopExp(outer_l, outer_bop, outer_r) = &exp.exp.value else { + return false; + }; + // TODO handle negation + let E::BinopExp(l1, op_l, r1) = &outer_l.exp.value else { + return false; + }; + let E::BinopExp(l2, op_r, r2) = &outer_r.exp.value else { + return false; + }; + let Some((outer, inner_l, inner_r)) = binop_case(outer_bop, l1, op_l, r1, l2, op_r, r2) + else { + return false; + }; + let simplification = match outer { + BoolOp::And => simplify_and(inner_l, inner_r), + BoolOp::Or => simplify_or(inner_l, inner_r), + }; + let msg = match simplification { + Simplification::Reducible(inner_op) => { + format!("simplifies to the operation '{}'", inner_op) + } + Simplification::AlwaysTrue => "is always 'true'".to_string(), + Simplification::AlwaysFalse => "is always 'false'".to_string(), + }; + self.reporter.add_diag(diag!( + StyleCodes::CombinableComparisons.diag_info(), + (exp.exp.loc, format!("This comparison {msg}")), + )); + + false + } +); + +fn simplify_and(op1: CmpOp, op2: CmpOp) -> Simplification { + use CmpOp as C; + Simplification::Reducible(match (op1, op2) { + // same operation + (C::Eq, C::Eq) + | (C::Neq, C::Neq) + | (C::Ge, C::Ge) + | (C::Le, C::Le) + | (C::Lt, C::Lt) + | (C::Gt, C::Gt) => op1, + + // contradiction + (C::Lt, C::Gt) + | (C::Gt, C::Lt) + | (C::Lt, C::Ge) + | (C::Ge, C::Lt) + | (C::Le, C::Gt) + | (C::Gt, C::Le) + | (C::Eq, C::Lt) + | (C::Lt, C::Eq) + | (C::Eq, C::Gt) + | (C::Gt, C::Eq) + | (C::Neq, C::Eq) + | (C::Eq, C::Neq) => return Simplification::AlwaysFalse, + + // == + (C::Le, C::Ge) + | (C::Ge, C::Le) + | (C::Ge, C::Eq) + | (C::Eq, C::Ge) + | (C::Le, C::Eq) + | (C::Eq, C::Le) => C::Eq, + + // < + (C::Lt, C::Le) + | (C::Le, C::Lt) + | (C::Lt, C::Neq) + | (C::Neq, C::Lt) + | (C::Le, C::Neq) + | (C::Neq, C::Le) => C::Lt, + // > + (C::Gt, C::Ge) + | (C::Ge, C::Gt) + | (C::Gt, C::Neq) + | (C::Neq, C::Gt) + | (C::Ge, C::Neq) + | (C::Neq, C::Ge) => C::Gt, + }) +} + +fn simplify_or(op1: CmpOp, op2: CmpOp) -> Simplification { + use CmpOp as C; + Simplification::Reducible(match (op1, op2) { + // same operation + (C::Eq, C::Eq) + | (C::Neq, C::Neq) + | (C::Ge, C::Ge) + | (C::Le, C::Le) + | (C::Lt, C::Lt) + | (C::Gt, C::Gt) => op1, + + // tautology + (C::Neq, C::Le) + | (C::Neq, C::Ge) + | (C::Le, C::Neq) + | (C::Ge, C::Neq) + | (C::Gt, C::Le) + | (C::Le, C::Gt) + | (C::Lt, C::Ge) + | (C::Ge, C::Lt) + | (C::Ge, C::Le) + | (C::Le, C::Ge) + | (C::Neq, C::Eq) + | (C::Eq, C::Neq) => return Simplification::AlwaysTrue, + + // != + (C::Neq, C::Lt) + | (C::Neq, C::Gt) + | (C::Lt, C::Neq) + | (C::Gt, C::Neq) + | (C::Lt, C::Gt) + | (C::Gt, C::Lt) => C::Neq, + + // <= + (C::Lt, C::Le) + | (C::Le, C::Lt) + | (C::Eq, C::Lt) + | (C::Lt, C::Eq) + | (C::Eq, C::Le) + | (C::Le, C::Eq) => C::Le, + // >= + (C::Gt, C::Ge) + | (C::Ge, C::Gt) + | (C::Eq, C::Gt) + | (C::Eq, C::Ge) + | (C::Gt, C::Eq) + | (C::Ge, C::Eq) => C::Ge, + }) +} + +fn bool_op(sp!(_, bop_): &BinOp) -> Option { + Some(match bop_ { + BinOp_::And => BoolOp::And, + BinOp_::Or => BoolOp::Or, + BinOp_::Eq + | BinOp_::Lt + | BinOp_::Gt + | BinOp_::Le + | BinOp_::Ge + | BinOp_::Add + | BinOp_::Sub + | BinOp_::Mul + | BinOp_::Mod + | BinOp_::Div + | BinOp_::BitOr + | BinOp_::BitAnd + | BinOp_::Xor + | BinOp_::Shl + | BinOp_::Shr + | BinOp_::Range + | BinOp_::Implies + | BinOp_::Iff + | BinOp_::Neq => return None, + }) +} + +fn cmp_op(sp!(_, bop_): &BinOp) -> Option { + Some(match bop_ { + BinOp_::Eq => CmpOp::Eq, + BinOp_::Neq => CmpOp::Neq, + BinOp_::Lt => CmpOp::Lt, + BinOp_::Gt => CmpOp::Gt, + BinOp_::Le => CmpOp::Le, + BinOp_::Ge => CmpOp::Ge, + + BinOp_::Add + | BinOp_::Sub + | BinOp_::Mul + | BinOp_::Mod + | BinOp_::Div + | BinOp_::BitOr + | BinOp_::BitAnd + | BinOp_::Xor + | BinOp_::Shl + | BinOp_::Shr + | BinOp_::Range + | BinOp_::Implies + | BinOp_::Iff + | BinOp_::And + | BinOp_::Or => return None, + }) +} + +fn flip(op: CmpOp) -> CmpOp { + match op { + CmpOp::Eq => CmpOp::Eq, + CmpOp::Neq => CmpOp::Neq, + CmpOp::Lt => CmpOp::Gt, + CmpOp::Gt => CmpOp::Lt, + CmpOp::Le => CmpOp::Ge, + CmpOp::Ge => CmpOp::Le, + } +} + +fn binop_case( + outer_bop: &BinOp, + l1: &H::Exp, + op_l: &BinOp, + r1: &H::Exp, + l2: &H::Exp, + op_r: &BinOp, + r2: &H::Exp, +) -> Option<(BoolOp, CmpOp, CmpOp)> { + let outer = bool_op(outer_bop)?; + let inner_l = cmp_op(op_l)?; + let inner_r = cmp_op(op_r)?; + let (inner_l, inner_r) = operand_case(l1, inner_l, r1, l2, inner_r, r2)?; + Some((outer, inner_l, inner_r)) +} + +fn operand_case( + l1: &H::Exp, + op1: CmpOp, + r1: &H::Exp, + l2: &H::Exp, + op2: CmpOp, + r2: &H::Exp, +) -> Option<(CmpOp, CmpOp)> { + if same_value_exp(l1, l2) && same_value_exp(r1, r2) { + Some((op1, op2)) + } else if same_value_exp(l1, r2) && same_value_exp(r1, l2) { + Some((op1, flip(op2))) + } else { + None + } +} + +impl std::fmt::Display for CmpOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + CmpOp::Eq => "==", + CmpOp::Neq => "!=", + CmpOp::Lt => "<", + CmpOp::Gt => ">", + CmpOp::Le => "<=", + CmpOp::Ge => ">=", + } + ) + } +} diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs deleted file mode 100644 index 3cc0aa23729a6..0000000000000 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_conditions.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -//! The `CombinableBool` detects and warns about boolean conditions in Move code that can be simplified. -//! It identifies comparisons that are logically equivalent and suggests more concise alternatives. -//! This rule focuses on simplifying expressions involving `==`, `<`, `>`, and `!=` operators to improve code readability. - -use crate::{ - cfgir::visitor::{same_value_exp, simple_visitor}, - diag, - hlir::ast::{self as H, UnannotatedExp_}, - linters::StyleCodes, - parser::ast::{BinOp, BinOp_}, -}; -use move_ir_types::location::*; - -#[derive(Debug, Clone, Copy)] -enum Simplification { - Reducible(InnerOp_), - AlwaysTrue, - AlwaysFalse, -} - -// impl Simplification { -// fn message(&self) -> &'static str { -// match self { -// Simplification::SameOp -// Simplification::Contradiction => { -// "This is always contradictory and can be simplified to false" -// } -// Simplification::UseComparison => "Consider simplifying to `<=` or `>=` respectively.", -// Simplification::UseEquality => "Consider simplifying to `==`.", -// } -// } -// } - -#[derive(Debug, Clone, Copy)] -enum OuterOp_ { - And, - Or, -} -type OuterOp = Spanned; - -#[derive(Debug, Clone, Copy)] -enum InnerOp_ { - Eq, - Neq, - Lt, - Gt, - Le, - Ge, -} -type InnerOp = Spanned; - -simple_visitor!( - CombinableBoolConditionsVisitor, - fn visit_exp_custom(&mut self, exp: &H::Exp) -> bool { - use H::UnannotatedExp_ as E; - let E::BinopExp(outer_l, outer_bop, outer_r) = &exp.exp.value else { - return false; - }; - let E::BinopExp(l1, op_l, r1) = &outer_l.exp.value else { - return false; - }; - let E::BinopExp(l2, op_r, r2) = &outer_r.exp.value else { - return false; - }; - let Some((outer, inner_l, inner_r)) = binop_case(outer_bop, l1, op_l, r1, l2, op_r, r2) - else { - return false; - }; - let simplification = match outer.value { - OuterOp_::And => simplify_and(inner_l, inner_r), - OuterOp_::Or => simplify_or(inner_l, inner_r), - }; - let msg = match simplification { - Simplification::Reducible(inner_op) => { - format!("to just the operation '{}'", inner_op) - } - Simplification::AlwaysTrue => "is always 'true'".to_string(), - Simplification::AlwaysFalse => "is always 'false'".to_string(), - }; - self.reporter.add_diag(diag!( - StyleCodes::CombinableBoolConditions.diag_info(), - (exp.exp.loc, format!("This comparison {msg}")), - )); - - false - } -); - -fn simplify_and(op1: InnerOp, op2: InnerOp) -> Simplification { - use InnerOp_ as I; - Simplification::Reducible(match (op1.value, op2.value) { - // same operation - (I::Eq, I::Eq) - | (I::Neq, I::Neq) - | (I::Ge, I::Ge) - | (I::Le, I::Le) - | (I::Lt, I::Lt) - | (I::Gt, I::Gt) => op1.value, - - // contradiction - (I::Lt, I::Gt) - | (I::Gt, I::Lt) - | (I::Lt, I::Ge) - | (I::Ge, I::Lt) - | (I::Le, I::Gt) - | (I::Gt, I::Le) - | (I::Eq, I::Lt) - | (I::Lt, I::Eq) - | (I::Eq, I::Gt) - | (I::Gt, I::Eq) - | (I::Neq, I::Eq) - | (I::Eq, I::Neq) => return Simplification::AlwaysFalse, - - // == - (I::Le, I::Ge) - | (I::Ge, I::Le) - | (I::Ge, I::Eq) - | (I::Eq, I::Ge) - | (I::Le, I::Eq) - | (I::Eq, I::Le) => I::Eq, - - // < - (I::Lt, I::Le) - | (I::Le, I::Lt) - | (I::Lt, I::Neq) - | (I::Neq, I::Lt) - | (I::Le, I::Neq) - | (I::Neq, I::Le) => I::Lt, - // > - (I::Gt, I::Ge) - | (I::Ge, I::Gt) - | (I::Gt, I::Neq) - | (I::Neq, I::Gt) - | (I::Ge, I::Neq) - | (I::Neq, I::Ge) => I::Gt, - }) -} - -fn simplify_or(op1: InnerOp, op2: InnerOp) -> Simplification { - use InnerOp_ as I; - Simplification::Reducible(match (op1.value, op2.value) { - // same operation - (I::Eq, I::Eq) - | (I::Neq, I::Neq) - | (I::Ge, I::Ge) - | (I::Le, I::Le) - | (I::Lt, I::Lt) - | (I::Gt, I::Gt) => op1.value, - - // tautology - (I::Neq, I::Le) - | (I::Neq, I::Ge) - | (I::Le, I::Neq) - | (I::Ge, I::Neq) - | (I::Gt, I::Le) - | (I::Le, I::Gt) - | (I::Lt, I::Ge) - | (I::Ge, I::Lt) - | (I::Ge, I::Le) - | (I::Le, I::Ge) - | (I::Neq, I::Eq) - | (I::Eq, I::Neq) => return Simplification::AlwaysTrue, - - // != - (I::Neq, I::Lt) - | (I::Neq, I::Gt) - | (I::Lt, I::Neq) - | (I::Gt, I::Neq) - | (I::Lt, I::Gt) - | (I::Gt, I::Lt) => I::Neq, - - // <= - (I::Lt, I::Le) - | (I::Le, I::Lt) - | (I::Eq, I::Lt) - | (I::Lt, I::Eq) - | (I::Eq, I::Le) - | (I::Le, I::Eq) => I::Le, - // >= - (I::Gt, I::Ge) - | (I::Ge, I::Gt) - | (I::Eq, I::Gt) - | (I::Eq, I::Ge) - | (I::Gt, I::Eq) - | (I::Ge, I::Eq) => I::Ge, - }) -} - -fn outer(sp!(loc, bop_): &BinOp) -> Option { - let op_ = match bop_ { - BinOp_::And => OuterOp_::And, - BinOp_::Or => OuterOp_::Or, - BinOp_::Eq - | BinOp_::Lt - | BinOp_::Gt - | BinOp_::Le - | BinOp_::Ge - | BinOp_::Add - | BinOp_::Sub - | BinOp_::Mul - | BinOp_::Mod - | BinOp_::Div - | BinOp_::BitOr - | BinOp_::BitAnd - | BinOp_::Xor - | BinOp_::Shl - | BinOp_::Shr - | BinOp_::Range - | BinOp_::Implies - | BinOp_::Iff - | BinOp_::Neq => return None, - }; - Some(sp(*loc, op_)) -} - -fn inner(sp!(loc, bop_): &BinOp) -> Option { - let op_ = match bop_ { - BinOp_::Eq => InnerOp_::Eq, - BinOp_::Neq => InnerOp_::Neq, - BinOp_::Lt => InnerOp_::Lt, - BinOp_::Gt => InnerOp_::Gt, - BinOp_::Le => InnerOp_::Le, - BinOp_::Ge => InnerOp_::Ge, - - BinOp_::Add - | BinOp_::Sub - | BinOp_::Mul - | BinOp_::Mod - | BinOp_::Div - | BinOp_::BitOr - | BinOp_::BitAnd - | BinOp_::Xor - | BinOp_::Shl - | BinOp_::Shr - | BinOp_::Range - | BinOp_::Implies - | BinOp_::Iff - | BinOp_::And - | BinOp_::Or => return None, - }; - Some(sp(*loc, op_)) -} - -fn flip(sp!(loc, op_): InnerOp) -> InnerOp { - sp( - loc, - match op_ { - InnerOp_::Eq => InnerOp_::Eq, - InnerOp_::Neq => InnerOp_::Neq, - InnerOp_::Lt => InnerOp_::Gt, - InnerOp_::Gt => InnerOp_::Lt, - InnerOp_::Le => InnerOp_::Ge, - InnerOp_::Ge => InnerOp_::Le, - }, - ) -} - -fn binop_case( - outer_bop: &BinOp, - l1: &H::Exp, - op_l: &BinOp, - r1: &H::Exp, - l2: &H::Exp, - op_r: &BinOp, - r2: &H::Exp, -) -> Option<(OuterOp, InnerOp, InnerOp)> { - let outer = outer(outer_bop)?; - let inner_l = inner(op_l)?; - let inner_r = inner(op_r)?; - let (inner_l, inner_r) = operand_case(l1, inner_l, r1, l2, inner_r, r2)?; - Some((outer, inner_l, inner_r)) -} - -fn operand_case( - l1: &H::Exp, - op1: InnerOp, - r1: &H::Exp, - l2: &H::Exp, - op2: InnerOp, - r2: &H::Exp, -) -> Option<(InnerOp, InnerOp)> { - if same_value_exp(l1, l2) && same_value_exp(r1, r2) { - // a1 := l1 - // a2 := l2 - // b1 := r1 - // b2 := r2 - if same_value_exp(l1, r1) { - // Covered by EqualOperands - None - } else { - Some((op1, op2)) - } - } else if same_value_exp(l1, r2) && same_value_exp(r1, l2) { - // a1 := l1 - // a2 := r2 - // b1 := r1 - // b2 := l2 - Some((op1, flip(op2))) - } else { - None - } -} - -impl std::fmt::Display for InnerOp_ { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use InnerOp_ as I; - write!( - f, - "{}", - match self { - I::Eq => "==", - I::Neq => "!=", - I::Lt => "<", - I::Gt => ">", - I::Le => "<=", - I::Ge => ">=", - } - ) - } -} diff --git a/external-crates/move/crates/move-compiler/src/linters/mod.rs b/external-crates/move/crates/move-compiler/src/linters/mod.rs index a62a4658212d5..58beaa0a046f7 100644 --- a/external-crates/move/crates/move-compiler/src/linters/mod.rs +++ b/external-crates/move/crates/move-compiler/src/linters/mod.rs @@ -14,7 +14,7 @@ use crate::{ }; pub mod abort_constant; -pub mod combinable_conditions; +pub mod combinable_comparisons; pub mod constant_naming; pub mod equal_operands; pub mod loop_without_exit; @@ -171,10 +171,10 @@ lints!( "redundant, always-equal operands for binary operation" ), ( - CombinableConditions, + CombinableComparisons, LinterDiagnosticCategory::Complexity, - "combinable_conditions", - "boolean condition can be simplified" + "combinable_comparison", + "comparison operations condition can be simplified" ) ); @@ -214,7 +214,7 @@ pub fn linter_visitors(level: LintLevel) -> Vec { redundant_ref_deref::RedundantRefDeref.visitor(), unnecessary_unit::UnnecessaryUnit.visitor(), equal_operands::EqualOperands.visitor(), - combinable_bool_conditions::CombinableBoolConditionsVisitor.visitor(), + combinable_comparisons::CombinableComparisons.visitor(), ] } } From 4e22ad5612430ad8d35ee7c77ad22621b780e719 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 12:57:16 -0800 Subject: [PATCH 08/20] cleanup toml --- Cargo.lock | 1 - external-crates/move/crates/move-compiler/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 012e809da72c1..a9dac90a8351a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7595,7 +7595,6 @@ dependencies = [ "codespan-reporting", "dunce", "hex", - "lazy_static", "lsp-types", "move-binary-format", "move-borrow-graph", diff --git a/external-crates/move/crates/move-compiler/Cargo.toml b/external-crates/move/crates/move-compiler/Cargo.toml index be56d17130762..4820f2b277887 100644 --- a/external-crates/move/crates/move-compiler/Cargo.toml +++ b/external-crates/move/crates/move-compiler/Cargo.toml @@ -24,7 +24,6 @@ serde_json.workspace = true similar.workspace = true stacker.workspace = true vfs.workspace = true -lazy_static = "1.5.0" bcs.workspace = true From 5cdba23d6e3e3c9dc65e2388b9e0b070ff227b87 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 15:08:57 -0800 Subject: [PATCH 09/20] cleanup --- .../tests/linter/correct_combinable_bool.exp | 66 ------------- .../tests/linter/correct_combinable_bool.move | 12 --- ...se_negative_combinable_bool_conditions.exp | 38 -------- ...e_negative_combinable_bool_conditions.move | 13 --- ...se_positive_combinable_bool_conditions.exp | 66 ------------- ...e_positive_combinable_bool_conditions.move | 12 --- .../linter/incorrect_combinable_bool.exp | 95 ------------------- .../linter/incorrect_combinable_bool.move | 12 --- .../suppress_combinable_bool_conditions.exp | 22 ----- .../suppress_combinable_bool_conditions.move | 19 ---- .../tests/linter/suppressed_lints.move | 5 - ...ue_negative_combinable_bool_conditions.exp | 50 ---------- ...e_negative_combinable_bool_conditions.move | 18 ---- ...ue_positive_combinable_bool_conditions.exp | 76 --------------- ...e_positive_combinable_bool_conditions.move | 18 ---- 15 files changed, 522 deletions(-) delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move diff --git a/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp b/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp deleted file mode 100644 index 326c96976772c..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.exp +++ /dev/null @@ -1,66 +0,0 @@ -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/correct_combinable_bool.move:5:30 - │ -5 │ if (x == y || z < y) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/correct_combinable_bool.move:6:21 - │ -6 │ if (x <= y) {}; - │ ------ ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/correct_combinable_bool.move:7:21 - │ -7 │ if (x >= y) {}; - │ ------ ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/correct_combinable_bool.move:8:20 - │ -8 │ if (x > y) {}; - │ ----- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/correct_combinable_bool.move:9:20 - │ -9 │ if (x < y) {}; - │ ----- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/correct_combinable_bool.move:10:31 - │ -10 │ if (x == 11 || x < 3) {}; - │ ---------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move b/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move deleted file mode 100644 index 2458c2a7ce84c..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/correct_combinable_bool.move +++ /dev/null @@ -1,12 +0,0 @@ -module 0x42::M { - const ERROR_NUM: u64 = 2; - - public fun func1(x: u64, y: u64, z: u64) { - if (x == y || z < y) {}; - if (x <= y) {}; - if (x >= y) {}; - if (x > y) {}; - if (x < y) {}; - if (x == 11 || x < 3) {}; - } -} diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp deleted file mode 100644 index c73b8aed5c742..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.exp +++ /dev/null @@ -1,38 +0,0 @@ -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/false_negative_combinable_bool_conditions.move:7:13 - │ -7 │ if ((x + 5) == (y - 5) || (x + 5) < (y - 5)) {}; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/false_negative_combinable_bool_conditions.move:7:54 - │ -7 │ if ((x + 5) == (y - 5) || (x + 5) < (y - 5)) {}; - │ --------------------------------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/false_negative_combinable_bool_conditions.move:10:13 - │ -10 │ if (y > x || y == x) {}; - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/false_negative_combinable_bool_conditions.move:10:30 - │ -10 │ if (y > x || y == x) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move deleted file mode 100644 index f7aae071f76f2..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_bool_conditions.move +++ /dev/null @@ -1,13 +0,0 @@ -module 0x42::false_negative_combinable_bool_conditions { - fun test_false_negatives() { - let x = 10; - let y = 20; - - // Case 1: Complex but equivalent expressions that could be simplified - if ((x + 5) == (y - 5) || (x + 5) < (y - 5)) {}; - - // Case 2: Reversed order of operands - if (y > x || y == x) {}; - } - -} diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp deleted file mode 100644 index a144f5c0441ca..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.exp +++ /dev/null @@ -1,66 +0,0 @@ -error[E03005]: unbound unscoped name - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:13 - │ -7 │ if (get_value() == y || get_value() < y) {}; - │ ^^^^^^^^^ Unbound function 'get_value' in current scope - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:13 - │ -7 │ if (get_value() == y || get_value() < y) {}; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -error[E03005]: unbound unscoped name - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:33 - │ -7 │ if (get_value() == y || get_value() < y) {}; - │ ^^^^^^^^^ Unbound function 'get_value' in current scope - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:7:50 - │ -7 │ if (get_value() == y || get_value() < y) {}; - │ ----------------------------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -error[E13001]: feature is not supported in specified edition - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:13 - │ -10 │ if (x as u64 == y || x as u64 < y) {}; - │ ^ 'as' without parentheses is not supported by current edition 'legacy', only '2024.alpha' and '2024.beta' support this feature - │ - = You can update the edition in the 'Move.toml', or via command line flag if invoking the compiler directly. - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:13 - │ -10 │ if (x as u64 == y || x as u64 < y) {}; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -error[E13001]: feature is not supported in specified edition - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:30 - │ -10 │ if (x as u64 == y || x as u64 < y) {}; - │ ^ 'as' without parentheses is not supported by current edition 'legacy', only '2024.alpha' and '2024.beta' support this feature - │ - = You can update the edition in the 'Move.toml', or via command line flag if invoking the compiler directly. - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/false_positive_combinable_bool_conditions.move:10:44 - │ -10 │ if (x as u64 == y || x as u64 < y) {}; - │ ----------------------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move deleted file mode 100644 index 6188a4c1bb59c..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/false_positive_combinable_bool_conditions.move +++ /dev/null @@ -1,12 +0,0 @@ -module 0x42::false_positive_combinable_bool_conditions { - fun test_false_positives() { - let x = 10; - let y = 20; - - // Case 1: When order matters due to side effects - if (get_value() == y || get_value() < y) {}; - - // Case 2: When precision matters in floating point comparisons - if (x as u64 == y || x as u64 < y) {}; - } -} diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp deleted file mode 100644 index 73a38c4578166..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.exp +++ /dev/null @@ -1,95 +0,0 @@ -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/incorrect_combinable_bool.move:6:13 - │ -6 │ if (x < y || x == y) {}; // should be x <= y - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/incorrect_combinable_bool.move:6:30 - │ -6 │ if (x < y || x == y) {}; // should be x <= y - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/incorrect_combinable_bool.move:7:13 - │ -7 │ if (x == y || x > y) {}; // should be x >= y - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/incorrect_combinable_bool.move:7:30 - │ -7 │ if (x == y || x > y) {}; // should be x >= y - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/incorrect_combinable_bool.move:8:13 - │ -8 │ if (x > y || x == y) {}; // should be x >= y - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/incorrect_combinable_bool.move:8:30 - │ -8 │ if (x > y || x == y) {}; // should be x >= y - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/incorrect_combinable_bool.move:9:13 - │ -9 │ if (m == n || m < n) {}; // should be m <= n - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/incorrect_combinable_bool.move:9:30 - │ -9 │ if (m == n || m < n) {}; // should be m <= n - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/incorrect_combinable_bool.move:10:13 - │ -10 │ if (x == 11 || x < 11) {}; - │ ^^^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/incorrect_combinable_bool.move:10:32 - │ -10 │ if (x == 11 || x < 11) {}; - │ ----------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move b/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move deleted file mode 100644 index f83ea801d9cee..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/incorrect_combinable_bool.move +++ /dev/null @@ -1,12 +0,0 @@ -module 0x42::M { - const ERROR_NUM: u64 = 2; - public fun func1(x: u64, y: u64) { - let m = 3; - let n = 4; - if (x < y || x == y) {}; // should be x <= y - if (x == y || x > y) {}; // should be x >= y - if (x > y || x == y) {}; // should be x >= y - if (m == n || m < n) {}; // should be m <= n - if (x == 11 || x < 11) {}; - } -} diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp deleted file mode 100644 index 70ba2a5047c44..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.exp +++ /dev/null @@ -1,22 +0,0 @@ -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/suppress_combinable_bool_conditions.move:8:30 - │ -8 │ if (x == y || x < y) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/suppress_combinable_bool_conditions.move:11:50 - │ -11 │ if (get_value() == y || get_value() < y) {}; - │ ----------------------------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move deleted file mode 100644 index 6b1b7557048b1..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_bool_conditions.move +++ /dev/null @@ -1,19 +0,0 @@ -module 0x42::suppress_combinable_bool_conditions { - #[lint_allow(combinable_bool_conditions)] - fun test_suppressed_cases() { - let x = 10; - let y = 20; - - // Case 1: Suppressed at function level - if (x == y || x < y) {}; - - // Case 2: Explicit false positive case that we want to suppress - if (get_value() == y || get_value() < y) {}; - } - - // Helper function for demonstrating side effects - fun get_value(): u64 { - // Imagine this has side effects - 10 - } -} diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move index 696069c180fe3..a75210a0364a7 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move +++ b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.move @@ -2,9 +2,4 @@ module 0x42::M { #[allow(lint(constant_naming))] const Another_BadName: u64 = 42; // Should trigger a warning - - #[allow(lint(combinable_comparison))] - public fun func1(x: u64, y: u64) { - if (x < y || x == y) {}; // should be x <= y - } } diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp deleted file mode 100644 index 4183ad699246e..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.exp +++ /dev/null @@ -1,50 +0,0 @@ -error[E03009]: unbound variable - ┌─ tests/linter/true_negative_combinable_bool_conditions.move:7:23 - │ -7 │ if (x == y || z < y) {}; - │ ^ Unbound variable 'z' - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_negative_combinable_bool_conditions.move:7:30 - │ -7 │ if (x == y || z < y) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_negative_combinable_bool_conditions.move:10:29 - │ -10 │ if (x > y || x < y) {}; - │ -------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_negative_combinable_bool_conditions.move:13:42 - │ -13 │ if ((x + 1) == y || (x - 1) < y) {}; - │ --------------------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_negative_combinable_bool_conditions.move:16:30 - │ -16 │ if (x != y && x > 0) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move deleted file mode 100644 index beba21ef1f96c..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/true_negative_combinable_bool_conditions.move +++ /dev/null @@ -1,18 +0,0 @@ -module 0x42::true_negative_combinable_bool_conditions { - fun test_true_negatives() { - let x = 10; - let y = 20; - - // Case 1: Different variables in comparison - if (x == y || z < y) {}; - - // Case 2: Different operators that don't have simplification - if (x > y || x < y) {}; - - // Case 3: Complex expressions - if ((x + 1) == y || (x - 1) < y) {}; - - // Case 4: Non-combinable operators - if (x != y && x > 0) {}; - } -} diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp deleted file mode 100644 index a37cdb1d23bd8..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.exp +++ /dev/null @@ -1,76 +0,0 @@ -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:7:13 - │ -7 │ if (x == y || x < y) {}; - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:7:30 - │ -7 │ if (x == y || x < y) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:10:13 - │ -10 │ if (x == y && x > y) {}; - │ ^^^^^^^^^^^^^^^ This is always contradictory and can be simplified to false - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:10:30 - │ -10 │ if (x == y && x > y) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:13:13 - │ -13 │ if (x >= y && x == y) {}; - │ ^^^^^^^^^^^^^^^^ Consider simplifying to `==`. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:13:31 - │ -13 │ if (x >= y && x == y) {}; - │ ---------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:16:13 - │ -16 │ if (x == y || x > y) {}; - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/true_positive_combinable_bool_conditions.move:16:30 - │ -16 │ if (x == y || x > y) {}; - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move deleted file mode 100644 index cbe39a783c7b1..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_bool_conditions.move +++ /dev/null @@ -1,18 +0,0 @@ -module 0x42::true_positive_combinable_bool_conditions { - fun test_true_positives() { - let x = 10; - let y = 20; - - // Case 1: x == y || x < y should be x <= y - if (x == y || x < y) {}; - - // Case 2: x == y && x > y is a contradiction (always false) - if (x == y && x > y) {}; - - // Case 3: x >= y && x == y should be x == y - if (x >= y && x == y) {}; - - // Case 4: x == y || x > y should be x >= y - if (x == y || x > y) {}; - } -} From 7e8f0c59fa2dabdd1262ca1074886fdab92a1c30 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 15:12:55 -0800 Subject: [PATCH 10/20] spelling --- external-crates/move/Cargo.lock | 1 - .../crates/move-compiler/src/linters/combinable_comparisons.rs | 2 +- external-crates/move/crates/move-compiler/src/linters/mod.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/external-crates/move/Cargo.lock b/external-crates/move/Cargo.lock index db78686c6a56b..79134dc343a33 100644 --- a/external-crates/move/Cargo.lock +++ b/external-crates/move/Cargo.lock @@ -1823,7 +1823,6 @@ dependencies = [ "datatest-stable", "dunce", "hex", - "lazy_static", "lsp-types", "move-binary-format", "move-borrow-graph", diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs index cff5f30631e44..da46090115ed5 100644 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs @@ -50,7 +50,7 @@ enum CmpOp { } simple_visitor!( - CombinableBoolConditionsVisitor, + CombinableComparisons, fn visit_exp_custom(&mut self, exp: &H::Exp) -> bool { use H::UnannotatedExp_ as E; let E::BinopExp(outer_l, outer_bop, outer_r) = &exp.exp.value else { diff --git a/external-crates/move/crates/move-compiler/src/linters/mod.rs b/external-crates/move/crates/move-compiler/src/linters/mod.rs index 58beaa0a046f7..c0a6784638608 100644 --- a/external-crates/move/crates/move-compiler/src/linters/mod.rs +++ b/external-crates/move/crates/move-compiler/src/linters/mod.rs @@ -173,7 +173,7 @@ lints!( ( CombinableComparisons, LinterDiagnosticCategory::Complexity, - "combinable_comparison", + "combinable_comparisons", "comparison operations condition can be simplified" ) ); From b297ba379a16ae637983f1352cac00716237425f Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 15:13:03 -0800 Subject: [PATCH 11/20] first test --- .../tests/linter/suppress_combinable_comparisons.move | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move new file mode 100644 index 0000000000000..8ce91c2694da4 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move @@ -0,0 +1,6 @@ + +module a::m { + fun t(x: u64, y: u64): bool { + x > y || x == y + } +} From 4679e404923a8ce17ba1b5b51c2041a9eaba29fa Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 19:09:50 -0800 Subject: [PATCH 12/20] tests --- .../src/linters/combinable_comparisons.rs | 45 +++---- .../move-compiler/src/typing/visitor.rs | 124 +++++++++++++++++- .../suppress_combinable_comparisons.move | 13 +- .../tests/linter/suppressed_lints.exp | 25 ---- 4 files changed, 151 insertions(+), 56 deletions(-) delete mode 100644 external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs index da46090115ed5..62bbcafb44f3b 100644 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs @@ -6,11 +6,13 @@ //! This rule focuses on simplifying expressions involving `==`, `<`, `>`, and `!=` operators to improve code readability. use crate::{ - cfgir::visitor::{same_value_exp, simple_visitor}, diag, - hlir::ast::{self as H}, linters::StyleCodes, parser::ast::{BinOp, BinOp_}, + typing::{ + ast::{self as T}, + visitor::{same_value_exp, simple_visitor}, + }, }; #[derive(Debug, Clone, Copy)] @@ -20,19 +22,6 @@ enum Simplification { AlwaysFalse, } -// impl Simplification { -// fn message(&self) -> &'static str { -// match self { -// Simplification::SameOp -// Simplification::Contradiction => { -// "This is always contradictory and can be simplified to false" -// } -// Simplification::UseComparison => "Consider simplifying to `<=` or `>=` respectively.", -// Simplification::UseEquality => "Consider simplifying to `==`.", -// } -// } -// } - #[derive(Debug, Clone, Copy)] enum BoolOp { And, @@ -51,16 +40,16 @@ enum CmpOp { simple_visitor!( CombinableComparisons, - fn visit_exp_custom(&mut self, exp: &H::Exp) -> bool { - use H::UnannotatedExp_ as E; - let E::BinopExp(outer_l, outer_bop, outer_r) = &exp.exp.value else { + fn visit_exp_custom(&mut self, exp: &T::Exp) -> bool { + use T::UnannotatedExp_ as E; + let E::BinopExp(outer_l, outer_bop, _, outer_r) = &exp.exp.value else { return false; }; // TODO handle negation - let E::BinopExp(l1, op_l, r1) = &outer_l.exp.value else { + let E::BinopExp(l1, op_l, _, r1) = &outer_l.exp.value else { return false; }; - let E::BinopExp(l2, op_r, r2) = &outer_r.exp.value else { + let E::BinopExp(l2, op_r, _, r2) = &outer_r.exp.value else { return false; }; let Some((outer, inner_l, inner_r)) = binop_case(outer_bop, l1, op_l, r1, l2, op_r, r2) @@ -253,12 +242,12 @@ fn flip(op: CmpOp) -> CmpOp { fn binop_case( outer_bop: &BinOp, - l1: &H::Exp, + l1: &T::Exp, op_l: &BinOp, - r1: &H::Exp, - l2: &H::Exp, + r1: &T::Exp, + l2: &T::Exp, op_r: &BinOp, - r2: &H::Exp, + r2: &T::Exp, ) -> Option<(BoolOp, CmpOp, CmpOp)> { let outer = bool_op(outer_bop)?; let inner_l = cmp_op(op_l)?; @@ -268,12 +257,12 @@ fn binop_case( } fn operand_case( - l1: &H::Exp, + l1: &T::Exp, op1: CmpOp, - r1: &H::Exp, - l2: &H::Exp, + r1: &T::Exp, + l2: &T::Exp, op2: CmpOp, - r2: &H::Exp, + r2: &T::Exp, ) -> Option<(CmpOp, CmpOp)> { if same_value_exp(l1, l2) && same_value_exp(r1, r2) { Some((op1, op2)) diff --git a/external-crates/move/crates/move-compiler/src/typing/visitor.rs b/external-crates/move/crates/move-compiler/src/typing/visitor.rs index 2dcf75d334eae..ff40807c87c44 100644 --- a/external-crates/move/crates/move-compiler/src/typing/visitor.rs +++ b/external-crates/move/crates/move-compiler/src/typing/visitor.rs @@ -4,11 +4,11 @@ use crate::{ command_line::compiler::Visitor, diagnostics::warning_filters::WarningFilters, - expansion::ast::ModuleIdent, + expansion::ast::{Fields, ModuleIdent}, naming::ast::{self as N, Var}, parser::ast::{ConstantName, DatatypeName, FunctionName, VariantName}, shared::CompilationEnv, - typing::ast as T, + typing::ast::{self as T, BuiltinFunction_}, }; use move_ir_types::location::Loc; use move_proc_macros::growing_stack; @@ -1286,3 +1286,123 @@ fn same_local_(lhs: &Var, rhs: &T::UnannotatedExp_) -> bool { _ => false, } } + +/// Assumes equal types and as such will not check type arguments for equality. +/// Assumes function calls, assignments, and similar expressions are effectful and thus not equal. +pub fn same_value_exp(e1: &T::Exp, e2: &T::Exp) -> bool { + same_value_exp_(&e1.exp.value, &e2.exp.value) +} + +#[growing_stack] +pub fn same_value_exp_(e1: &T::UnannotatedExp_, e2: &T::UnannotatedExp_) -> bool { + use T::UnannotatedExp_ as E; + macro_rules! effectful { + () => { + E::Builtin(_, _) + | E::ModuleCall(_) + | E::Assign(_, _, _) + | E::Mutate(_, _) + | E::Return(_) + | E::Abort(_) + | E::Give(_, _) + }; + } + macro_rules! brittle { + () => { + E::ErrorConstant { .. } + | E::IfElse(_, _, _) + | E::Match(_, _) + | E::VariantMatch(_, _, _) + | E::While(_, _, _) + | E::Loop { .. } + }; + } + match (e1, e2) { + (E::Value(v1), E::Value(v2)) => v1 == v2, + (E::Unit { .. }, E::Unit { .. }) => true, + (E::Constant(m1, c1), E::Constant(m2, c2)) => m1 == m2 && c1 == c2, + ( + E::Move { var, .. } | E::Copy { var, .. } | E::Use(var) | E::BorrowLocal(_, var), + other, + ) + | ( + other, + E::Move { var, .. } | E::Copy { var, .. } | E::Use(var) | E::BorrowLocal(_, var), + ) => same_local_(var, other), + + (E::Vector(_, _, _, e1), E::Vector(_, _, _, e2)) => same_value_exp(e1, e2), + + (E::Builtin(b, e), other) | (other, E::Builtin(b, e)) + if matches!(&b.value, BuiltinFunction_::Freeze(_)) => + { + same_value_exp_(&e.exp.value, other) + } + (E::Dereference(e) | E::TempBorrow(_, e) | E::Cast(e, _) | E::Annotate(e, _), other) + | (other, E::Dereference(e) | E::TempBorrow(_, e) | E::Cast(e, _) | E::Annotate(e, _)) => { + same_value_exp_(&e.exp.value, other) + } + (E::NamedBlock(_, s) | E::Block(s), other) | (other, E::NamedBlock(_, s) | E::Block(s)) => { + same_value_seq_exp_(s, other) + } + (E::ExpList(l1), E::ExpList(l2)) => same_value_exp_list(l1, l2), + (E::ExpList(l), other) | (other, E::ExpList(l)) if l.len() == 1 => match &l[0] { + T::ExpListItem::Single(e, _) => same_value_exp_(&e.exp.value, other), + T::ExpListItem::Splat(_, e, _) => same_value_exp_(&e.exp.value, other), + }, + + (E::UnaryExp(op1, e1), E::UnaryExp(op2, e2)) => op1 == op2 && same_value_exp(e1, e2), + (E::BinopExp(l1, op1, _, r1), E::BinopExp(l2, op2, _, r2)) => { + op1 == op2 && same_value_exp(l1, l2) && same_value_exp(r1, r2) + } + + (E::Pack(m1, n1, _, fields1), E::Pack(m2, n2, _, fields2)) => { + m1 == m2 && n1 == n2 && same_value_fields(fields1, fields2) + } + (E::PackVariant(m1, n1, v1, _, fields1), E::PackVariant(m2, n2, v2, _, fields2)) => { + m1 == m2 && n1 == n2 && v1 == v2 && same_value_fields(fields1, fields2) + } + + (E::Borrow(_, e1, f1), E::Borrow(_, e2, f2)) => f1 == f2 && same_value_exp(e1, e2), + + // false for anything effectful + (effectful!(), _) | (_, effectful!()) => false, + + // TODO there is some potential for equality here, but a bit too brittle now + (brittle!(), _) | (_, brittle!()) => false, + + _ => false, + } +} + +fn same_value_fields( + fields1: &Fields<(N::Type, T::Exp)>, + fields2: &Fields<(N::Type, T::Exp)>, +) -> bool { + fields1.key_cloned_iter().all(|(f1, (_, (_, e1)))| { + fields2 + .get(&f1) + .is_some_and(|(_, (_, e2))| same_value_exp(e1, e2)) + }) +} + +fn same_value_exp_list(l1: &[T::ExpListItem], l2: &[T::ExpListItem]) -> bool { + l1.len() == l2.len() + && l1.iter().zip(l2).all(|(i1, i2)| match (i1, i2) { + (T::ExpListItem::Single(e1, _), T::ExpListItem::Single(e2, _)) => { + same_value_exp(e1, e2) + } + // TODO handle splat + _ => false, + }) +} + +fn same_value_seq_exp_((_, seq_): &T::Sequence, other: &T::UnannotatedExp_) -> bool { + match seq_.len() { + 0 => panic!("ICE should not have empty sequence"), + 1 => match &seq_[0].value { + T::SequenceItem_::Seq(e) => same_value_exp_(&e.exp.value, other), + _ => false, + }, + _ => false, + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move index 8ce91c2694da4..48a47ff5e1a70 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move +++ b/external-crates/move/crates/move-compiler/tests/linter/suppress_combinable_comparisons.move @@ -1,6 +1,17 @@ - +#[allow(lint(combinable_comparisons))] module a::m { fun t(x: u64, y: u64): bool { x > y || x == y } } + + +module a::n { + #[allow(lint(combinable_comparisons))] + const C: bool = 5 > 3 || 5 == 3; + + #[allow(lint(combinable_comparisons))] + fun t(x: u64, y: u64): bool { + x > y || x == y + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp b/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp deleted file mode 100644 index 457d4eaa6cb96..0000000000000 --- a/external-crates/move/crates/move-compiler/tests/linter/suppressed_lints.exp +++ /dev/null @@ -1,25 +0,0 @@ -warning[W10007]: issue with attribute value - ┌─ tests/linter/suppressed_lints.move:6:18 - │ -6 │ #[allow(lint(combinable_comparison))] - │ ^^^^^^^^^^^^^^^^^^^^^ Unknown warning filter 'lint(combinable_comparison)' - -warning[Lint W01011]: boolean condition can be simplified - ┌─ tests/linter/suppressed_lints.move:8:13 - │ -8 │ if (x < y || x == y) {}; // should be x <= y - │ ^^^^^^^^^^^^^^^ Consider simplifying to `<=` or `>=` respectively. - │ - = This warning can be suppressed with '#[allow(lint(combinable_bool_conditions))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - -warning[Lint W04010]: unit `()` expression can be removed or simplified - ┌─ tests/linter/suppressed_lints.move:8:30 - │ -8 │ if (x < y || x == y) {}; // should be x <= y - │ --------------- ^^ Unnecessary unit '()' - │ │ - │ Consider negating the 'if' condition and simplifying - │ - = For example 'if (cond) () else e' can be simplified to 'if (!cond) e' - = This warning can be suppressed with '#[allow(lint(unnecessary_unit))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - From b92bd09faeb07b6849a9a53435b1ba4041b1b842 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 19:23:46 -0800 Subject: [PATCH 13/20] new test --- .../true_positive_combinable_comparisons.move | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move new file mode 100644 index 0000000000000..c1e87199d423b --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move @@ -0,0 +1,78 @@ +module a::m { + fun t(x: u64, y: u64): bool { + x == y || x > y; + x == y && x != y; + x == y && x > y; + x == y && x < y; + x == y && x >= y; + x == y && x <= y; + x != y && x > y; + x != y && x < y; + x != y && x >= y; + x != y && x <= y; + x > y && x < y; + x > y && x >= y; + x > y && x <= y; + x < y && x >= y; + x < y && x <= y; + x >= y && x <= y; + x == y || x != y; + x == y || x > y; + x == y || x < y; + x == y || x >= y; + x == y || x <= y; + x != y || x > y; + x != y || x < y; + x != y || x >= y; + x != y || x <= y; + x > y || x < y; + x > y || x >= y; + x > y || x <= y; + x < y || x >= y; + x < y || x <= y; + x >= y || x <= y; + } + + // fun flipped(x: u64, y: u64): bool { + // x == y && y != x; + // x == y && y > x; + // x == y && y < x; + // x == y && y >= x; + // x == y && y <= x; + // x != y && y > x; + // x != y && y < x; + // x != y && y >= x; + // x != y && y <= x; + // x > y && y < x; + // x > y && y >= x; + // x > y && y <= x; + // x < y && y >= x; + // x < y && y <= x; + // x >= y && y <= x; + // x == y || y != x; + // x == y || y > x; + // x == y || y < x; + // x == y || y >= x; + // x == y || y <= x; + // x != y || y > x; + // x != y || y < x; + // x != y || y >= x; + // x != y || y <= x; + // x > y || y < x; + // x > y || y >= x; + // x > y || y <= x; + // x < y || y >= x; + // x < y || y <= x; + // x >= y || y <= x; + // } + + // const Values: bool = 5 > 3 || 5 == 3; + + // fun values(x: u64, y: u64): bool { + // 5 != 3 && 5 > 3 + // } + + // fun refs(x: u64, y: u64): bool { + // &x == &y || x > y; + // } +} From 86b18d9661605ab31250d55a319ec6b4210b9976 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 19:48:15 -0800 Subject: [PATCH 14/20] true positive --- .../move-compiler/src/typing/visitor.rs | 24 +- .../true_positive_combinable_comparisons.exp | 992 ++++++++++++++++++ .../true_positive_combinable_comparisons.move | 143 ++- 3 files changed, 1107 insertions(+), 52 deletions(-) create mode 100644 external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp diff --git a/external-crates/move/crates/move-compiler/src/typing/visitor.rs b/external-crates/move/crates/move-compiler/src/typing/visitor.rs index ff40807c87c44..4fe015d236f7e 100644 --- a/external-crates/move/crates/move-compiler/src/typing/visitor.rs +++ b/external-crates/move/crates/move-compiler/src/typing/visitor.rs @@ -1318,6 +1318,18 @@ pub fn same_value_exp_(e1: &T::UnannotatedExp_, e2: &T::UnannotatedExp_) -> bool }; } match (e1, e2) { + (E::Dereference(e) | E::TempBorrow(_, e) | E::Cast(e, _) | E::Annotate(e, _), other) + | (other, E::Dereference(e) | E::TempBorrow(_, e) | E::Cast(e, _) | E::Annotate(e, _)) => { + same_value_exp_(&e.exp.value, other) + } + (E::NamedBlock(_, s) | E::Block(s), other) | (other, E::NamedBlock(_, s) | E::Block(s)) => { + same_value_seq_exp_(s, other) + } + (E::ExpList(l), other) | (other, E::ExpList(l)) if l.len() == 1 => match &l[0] { + T::ExpListItem::Single(e, _) => same_value_exp_(&e.exp.value, other), + T::ExpListItem::Splat(_, e, _) => same_value_exp_(&e.exp.value, other), + }, + (E::Value(v1), E::Value(v2)) => v1 == v2, (E::Unit { .. }, E::Unit { .. }) => true, (E::Constant(m1, c1), E::Constant(m2, c2)) => m1 == m2 && c1 == c2, @@ -1337,18 +1349,8 @@ pub fn same_value_exp_(e1: &T::UnannotatedExp_, e2: &T::UnannotatedExp_) -> bool { same_value_exp_(&e.exp.value, other) } - (E::Dereference(e) | E::TempBorrow(_, e) | E::Cast(e, _) | E::Annotate(e, _), other) - | (other, E::Dereference(e) | E::TempBorrow(_, e) | E::Cast(e, _) | E::Annotate(e, _)) => { - same_value_exp_(&e.exp.value, other) - } - (E::NamedBlock(_, s) | E::Block(s), other) | (other, E::NamedBlock(_, s) | E::Block(s)) => { - same_value_seq_exp_(s, other) - } + (E::ExpList(l1), E::ExpList(l2)) => same_value_exp_list(l1, l2), - (E::ExpList(l), other) | (other, E::ExpList(l)) if l.len() == 1 => match &l[0] { - T::ExpListItem::Single(e, _) => same_value_exp_(&e.exp.value, other), - T::ExpListItem::Splat(_, e, _) => same_value_exp_(&e.exp.value, other), - }, (E::UnaryExp(op1, e1), E::UnaryExp(op2, e2)) => op1 == op2 && same_value_exp(e1, e2), (E::BinopExp(l1, op1, _, r1), E::BinopExp(l2, op2, _, r2)) => { diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp new file mode 100644 index 0000000000000..9a69a35a469e2 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp @@ -0,0 +1,992 @@ +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:3:9 + │ +3 │ x == y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:4:9 + │ +4 │ x == y && x > y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:5:9 + │ +5 │ x == y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:6:9 + │ +6 │ x == y && x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:7:9 + │ +7 │ x == y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:8:9 + │ +8 │ x != y && x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:9:9 + │ +9 │ x != y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:10:9 + │ +10 │ x != y && x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:11:9 + │ +11 │ x != y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:12:9 + │ +12 │ x > y && x < y; + │ ^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:13:9 + │ +13 │ x > y && x >= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:14:9 + │ +14 │ x > y && x <= y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:15:9 + │ +15 │ x < y && x >= y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:16:9 + │ +16 │ x < y && x <= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:17:9 + │ +17 │ x >= y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:18:9 + │ +18 │ x == y || x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:19:9 + │ +19 │ x == y || x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:20:9 + │ +20 │ x == y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:21:9 + │ +21 │ x == y || x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:22:9 + │ +22 │ x == y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:23:9 + │ +23 │ x != y || x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:24:9 + │ +24 │ x != y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:25:9 + │ +25 │ x != y || x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:26:9 + │ +26 │ x != y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:27:9 + │ +27 │ x > y || x < y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:28:9 + │ +28 │ x > y || x >= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:29:9 + │ +29 │ x > y || x <= y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:30:9 + │ +30 │ x < y || x >= y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:31:9 + │ +31 │ x < y || x <= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:32:9 + │ +32 │ x >= y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:33:9 + │ +33 │ x != y && x == y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:34:9 + │ +34 │ x > y && x == y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:35:9 + │ +35 │ x < y && x == y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:36:9 + │ +36 │ x >= y && x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:37:9 + │ +37 │ x <= y && x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:38:9 + │ +38 │ x > y && x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:39:9 + │ +39 │ x < y && x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:40:9 + │ +40 │ x >= y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:41:9 + │ +41 │ x <= y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:42:9 + │ +42 │ x < y && x > y; + │ ^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:43:9 + │ +43 │ x >= y && x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:44:9 + │ +44 │ x <= y && x > y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:45:9 + │ +45 │ x >= y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:46:9 + │ +46 │ x <= y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:47:9 + │ +47 │ x <= y && x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:48:9 + │ +48 │ x != y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:49:9 + │ +49 │ x > y || x == y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:50:9 + │ +50 │ x < y || x == y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:51:9 + │ +51 │ x >= y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:52:9 + │ +52 │ x <= y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:53:9 + │ +53 │ x > y || x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:54:9 + │ +54 │ x < y || x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:55:9 + │ +55 │ x >= y || x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:56:9 + │ +56 │ x <= y || x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:57:9 + │ +57 │ x < y || x > y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:58:9 + │ +58 │ x >= y || x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:59:9 + │ +59 │ x <= y || x > y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:60:9 + │ +60 │ x >= y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:61:9 + │ +61 │ x <= y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:62:9 + │ +62 │ x <= y || x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:66:9 + │ +66 │ x == y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:67:9 + │ +67 │ x == y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:68:9 + │ +68 │ x == y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:69:9 + │ +69 │ x == y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:70:9 + │ +70 │ x == y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:71:9 + │ +71 │ x != y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:72:9 + │ +72 │ x != y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:73:9 + │ +73 │ x != y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:74:9 + │ +74 │ x != y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:75:9 + │ +75 │ x > y && y < x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:76:9 + │ +76 │ x > y && y >= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:77:9 + │ +77 │ x > y && y <= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:78:9 + │ +78 │ x < y && y >= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:79:9 + │ +79 │ x < y && y <= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:80:9 + │ +80 │ x >= y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:81:9 + │ +81 │ x == y || y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:82:9 + │ +82 │ x == y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:83:9 + │ +83 │ x == y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:84:9 + │ +84 │ x == y || y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:85:9 + │ +85 │ x == y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:86:9 + │ +86 │ x != y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:87:9 + │ +87 │ x != y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:88:9 + │ +88 │ x != y || y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:89:9 + │ +89 │ x != y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:90:9 + │ +90 │ x > y || y < x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:91:9 + │ +91 │ x > y || y >= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:92:9 + │ +92 │ x > y || y <= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:93:9 + │ +93 │ x < y || y >= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:94:9 + │ +94 │ x < y || y <= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:95:9 + │ +95 │ x >= y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:96:9 + │ +96 │ x != y && y == x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:97:9 + │ +97 │ x > y && y == x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:98:9 + │ +98 │ x < y && y == x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:99:9 + │ +99 │ x >= y && y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:100:9 + │ +100 │ x <= y && y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:101:9 + │ +101 │ x > y && y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:102:9 + │ +102 │ x < y && y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:103:9 + │ +103 │ x >= y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:104:9 + │ +104 │ x <= y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:105:9 + │ +105 │ x < y && y > x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:106:9 + │ +106 │ x >= y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:107:9 + │ +107 │ x <= y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:108:9 + │ +108 │ x >= y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:109:9 + │ +109 │ x <= y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:110:9 + │ +110 │ x <= y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:111:9 + │ +111 │ x != y || y == x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:112:9 + │ +112 │ x > y || y == x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:113:9 + │ +113 │ x < y || y == x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:114:9 + │ +114 │ x >= y || y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:115:9 + │ +115 │ x <= y || y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:116:9 + │ +116 │ x > y || y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:117:9 + │ +117 │ x < y || y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:118:9 + │ +118 │ x >= y || y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:119:9 + │ +119 │ x <= y || y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:120:9 + │ +120 │ x < y || y > x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:121:9 + │ +121 │ x >= y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:122:9 + │ +122 │ x <= y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:123:9 + │ +123 │ x >= y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:124:9 + │ +124 │ x <= y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:125:9 + │ +125 │ x <= y || y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:128:26 + │ +128 │ const Values: bool = 5 > 3 || 5 == 3; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:131:9 + │ +131 │ 5 != 3 && 5 > 3 + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:136:9 + │ +136 │ {&x} == &y || (x as u64) > (*&y:u64); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:137:9 + │ +137 │ © x == &y || x < move y; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move index c1e87199d423b..a136e27e17a21 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move @@ -1,6 +1,5 @@ module a::m { - fun t(x: u64, y: u64): bool { - x == y || x > y; + fun t(x: u64, y: u64) { x == y && x != y; x == y && x > y; x == y && x < y; @@ -31,48 +30,110 @@ module a::m { x < y || x >= y; x < y || x <= y; x >= y || x <= y; + x != y && x == y; + x > y && x == y; + x < y && x == y; + x >= y && x == y; + x <= y && x == y; + x > y && x != y; + x < y && x != y; + x >= y && x != y; + x <= y && x != y; + x < y && x > y; + x >= y && x > y; + x <= y && x > y; + x >= y && x < y; + x <= y && x < y; + x <= y && x >= y; + x != y || x == y; + x > y || x == y; + x < y || x == y; + x >= y || x == y; + x <= y || x == y; + x > y || x != y; + x < y || x != y; + x >= y || x != y; + x <= y || x != y; + x < y || x > y; + x >= y || x > y; + x <= y || x > y; + x >= y || x < y; + x <= y || x < y; + x <= y || x >= y; } - // fun flipped(x: u64, y: u64): bool { - // x == y && y != x; - // x == y && y > x; - // x == y && y < x; - // x == y && y >= x; - // x == y && y <= x; - // x != y && y > x; - // x != y && y < x; - // x != y && y >= x; - // x != y && y <= x; - // x > y && y < x; - // x > y && y >= x; - // x > y && y <= x; - // x < y && y >= x; - // x < y && y <= x; - // x >= y && y <= x; - // x == y || y != x; - // x == y || y > x; - // x == y || y < x; - // x == y || y >= x; - // x == y || y <= x; - // x != y || y > x; - // x != y || y < x; - // x != y || y >= x; - // x != y || y <= x; - // x > y || y < x; - // x > y || y >= x; - // x > y || y <= x; - // x < y || y >= x; - // x < y || y <= x; - // x >= y || y <= x; - // } + fun flipped(x: u64, y: u64) { + x == y && y != x; + x == y && y > x; + x == y && y < x; + x == y && y >= x; + x == y && y <= x; + x != y && y > x; + x != y && y < x; + x != y && y >= x; + x != y && y <= x; + x > y && y < x; + x > y && y >= x; + x > y && y <= x; + x < y && y >= x; + x < y && y <= x; + x >= y && y <= x; + x == y || y != x; + x == y || y > x; + x == y || y < x; + x == y || y >= x; + x == y || y <= x; + x != y || y > x; + x != y || y < x; + x != y || y >= x; + x != y || y <= x; + x > y || y < x; + x > y || y >= x; + x > y || y <= x; + x < y || y >= x; + x < y || y <= x; + x >= y || y <= x; + x != y && y == x; + x > y && y == x; + x < y && y == x; + x >= y && y == x; + x <= y && y == x; + x > y && y != x; + x < y && y != x; + x >= y && y != x; + x <= y && y != x; + x < y && y > x; + x >= y && y > x; + x <= y && y > x; + x >= y && y < x; + x <= y && y < x; + x <= y && y >= x; + x != y || y == x; + x > y || y == x; + x < y || y == x; + x >= y || y == x; + x <= y || y == x; + x > y || y != x; + x < y || y != x; + x >= y || y != x; + x <= y || y != x; + x < y || y > x; + x >= y || y > x; + x <= y || y > x; + x >= y || y < x; + x <= y || y < x; + x <= y || y >= x; + } - // const Values: bool = 5 > 3 || 5 == 3; + const Values: bool = 5 > 3 || 5 == 3; - // fun values(x: u64, y: u64): bool { - // 5 != 3 && 5 > 3 - // } + fun values(): bool { + 5 != 3 && 5 > 3 + } - // fun refs(x: u64, y: u64): bool { - // &x == &y || x > y; - // } + #[allow(lint(redundant_ref_deref))] + fun mismatched(x: u64, y: u64) { + {&x} == &y || (x as u64) > (*&y:u64); + © x == &y || x < move y; + } } From e40b463d51da58c91231a4482edea14ac6e05bbd Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Thu, 5 Dec 2024 20:03:35 -0800 Subject: [PATCH 15/20] false negative --- .../crates/move-compiler/src/cfgir/visitor.rs | 7 +- ...false_negative_combinable_comparisons.move | 7 + .../true_positive_combinable_comparisons.exp | 468 +++++++++--------- .../true_positive_combinable_comparisons.move | 1 + 4 files changed, 246 insertions(+), 237 deletions(-) create mode 100644 external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_comparisons.move diff --git a/external-crates/move/crates/move-compiler/src/cfgir/visitor.rs b/external-crates/move/crates/move-compiler/src/cfgir/visitor.rs index 45c832cf254ac..839498650092f 100644 --- a/external-crates/move/crates/move-compiler/src/cfgir/visitor.rs +++ b/external-crates/move/crates/move-compiler/src/cfgir/visitor.rs @@ -949,6 +949,10 @@ pub fn same_value_exp(e1: &H::Exp, e2: &H::Exp) -> bool { pub fn same_value_exp_(e1: &H::UnannotatedExp_, e2: &H::UnannotatedExp_) -> bool { use H::UnannotatedExp_ as E; match (e1, e2) { + (E::Dereference(e) | E::Freeze(e), other) | (other, E::Dereference(e) | E::Freeze(e)) => { + same_value_exp_(&e.exp.value, other) + } + (E::Value(v1), E::Value(v2)) => v1 == v2, (E::Unit { .. }, E::Unit { .. }) => true, (E::Constant(c1), E::Constant(c2)) => c1 == c2, @@ -965,9 +969,6 @@ pub fn same_value_exp_(e1: &H::UnannotatedExp_, e2: &H::UnannotatedExp_) -> bool .all(|(e1, e2)| same_value_exp(e1, e2)) } - (E::Dereference(e) | E::Freeze(e), other) | (other, E::Dereference(e) | E::Freeze(e)) => { - same_value_exp_(&e.exp.value, other) - } (E::UnaryExp(op1, e1), E::UnaryExp(op2, e2)) => op1 == op2 && same_value_exp(e1, e2), (E::BinopExp(l1, op1, r1), E::BinopExp(l2, op2, r2)) => { op1 == op2 && same_value_exp(l1, l2) && same_value_exp(r1, r2) diff --git a/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_comparisons.move new file mode 100644 index 0000000000000..4df6ba1a675ec --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/linter/false_negative_combinable_comparisons.move @@ -0,0 +1,7 @@ +// tests lints against combinable comparisons that can be simplified to a single comparison. +// these cases should work but do not +module a::m { + fun negated(x: u64, y: u64) { + !(x == y) || x > y; + } +} diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp index 9a69a35a469e2..acada3edbb5ac 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp @@ -1,23 +1,15 @@ -warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:3:9 - │ -3 │ x == y && x != y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' - │ - = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') - warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:4:9 │ -4 │ x == y && x > y; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +4 │ x == y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:5:9 │ -5 │ x == y && x < y; +5 │ x == y && x > y; │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -25,15 +17,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:6:9 │ -6 │ x == y && x >= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' +6 │ x == y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:7:9 │ -7 │ x == y && x <= y; +7 │ x == y && x >= y; │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -41,63 +33,63 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:8:9 │ -8 │ x != y && x > y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +8 │ x == y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:9:9 │ -9 │ x != y && x < y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +9 │ x != y && x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:10:9 │ -10 │ x != y && x >= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +10 │ x != y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:11:9 │ -11 │ x != y && x <= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +11 │ x != y && x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:12:9 │ -12 │ x > y && x < y; - │ ^^^^^^^^^^^^^^ This comparison is always 'false' +12 │ x != y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:13:9 │ -13 │ x > y && x >= y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +13 │ x > y && x < y; + │ ^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:14:9 │ -14 │ x > y && x <= y; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +14 │ x > y && x >= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:15:9 │ -15 │ x < y && x >= y; +15 │ x > y && x <= y; │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -105,71 +97,71 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:16:9 │ -16 │ x < y && x <= y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +16 │ x < y && x >= y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:17:9 │ -17 │ x >= y && x <= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' +17 │ x < y && x <= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:18:9 │ -18 │ x == y || x != y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +18 │ x >= y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:19:9 │ -19 │ x == y || x > y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +19 │ x == y || x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:20:9 │ -20 │ x == y || x < y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +20 │ x == y || x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:21:9 │ -21 │ x == y || x >= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +21 │ x == y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:22:9 │ -22 │ x == y || x <= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +22 │ x == y || x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:23:9 │ -23 │ x != y || x > y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' +23 │ x == y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:24:9 │ -24 │ x != y || x < y; +24 │ x != y || x > y; │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -177,15 +169,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:25:9 │ -25 │ x != y || x >= y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +25 │ x != y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:26:9 │ -26 │ x != y || x <= y; +26 │ x != y || x >= y; │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -193,31 +185,31 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:27:9 │ -27 │ x > y || x < y; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' +27 │ x != y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:28:9 │ -28 │ x > y || x >= y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +28 │ x > y || x < y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:29:9 │ -29 │ x > y || x <= y; - │ ^^^^^^^^^^^^^^^ This comparison is always 'true' +29 │ x > y || x >= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:30:9 │ -30 │ x < y || x >= y; +30 │ x > y || x <= y; │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -225,39 +217,39 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:31:9 │ -31 │ x < y || x <= y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +31 │ x < y || x >= y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:32:9 │ -32 │ x >= y || x <= y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +32 │ x < y || x <= y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:33:9 │ -33 │ x != y && x == y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' +33 │ x >= y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:34:9 │ -34 │ x > y && x == y; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +34 │ x != y && x == y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:35:9 │ -35 │ x < y && x == y; +35 │ x > y && x == y; │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -265,15 +257,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:36:9 │ -36 │ x >= y && x == y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' +36 │ x < y && x == y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:37:9 │ -37 │ x <= y && x == y; +37 │ x >= y && x == y; │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -281,63 +273,63 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:38:9 │ -38 │ x > y && x != y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +38 │ x <= y && x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:39:9 │ -39 │ x < y && x != y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +39 │ x > y && x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:40:9 │ -40 │ x >= y && x != y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +40 │ x < y && x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:41:9 │ -41 │ x <= y && x != y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +41 │ x >= y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:42:9 │ -42 │ x < y && x > y; - │ ^^^^^^^^^^^^^^ This comparison is always 'false' +42 │ x <= y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:43:9 │ -43 │ x >= y && x > y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +43 │ x < y && x > y; + │ ^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:44:9 │ -44 │ x <= y && x > y; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +44 │ x >= y && x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:45:9 │ -45 │ x >= y && x < y; +45 │ x <= y && x > y; │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -345,71 +337,71 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:46:9 │ -46 │ x <= y && x < y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +46 │ x >= y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:47:9 │ -47 │ x <= y && x >= y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' +47 │ x <= y && x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:48:9 │ -48 │ x != y || x == y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +48 │ x <= y && x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:49:9 │ -49 │ x > y || x == y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +49 │ x != y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:50:9 │ -50 │ x < y || x == y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +50 │ x > y || x == y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:51:9 │ -51 │ x >= y || x == y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +51 │ x < y || x == y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:52:9 │ -52 │ x <= y || x == y; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +52 │ x >= y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:53:9 │ -53 │ x > y || x != y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' +53 │ x <= y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:54:9 │ -54 │ x < y || x != y; +54 │ x > y || x != y; │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -417,15 +409,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:55:9 │ -55 │ x >= y || x != y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +55 │ x < y || x != y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:56:9 │ -56 │ x <= y || x != y; +56 │ x >= y || x != y; │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -433,31 +425,31 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:57:9 │ -57 │ x < y || x > y; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' +57 │ x <= y || x != y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:58:9 │ -58 │ x >= y || x > y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +58 │ x < y || x > y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:59:9 │ -59 │ x <= y || x > y; - │ ^^^^^^^^^^^^^^^ This comparison is always 'true' +59 │ x >= y || x > y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:60:9 │ -60 │ x >= y || x < y; +60 │ x <= y || x > y; │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -465,39 +457,39 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:61:9 │ -61 │ x <= y || x < y; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +61 │ x >= y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:62:9 │ -62 │ x <= y || x >= y; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +62 │ x <= y || x < y; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:66:9 + ┌─ tests/linter/true_positive_combinable_comparisons.move:63:9 │ -66 │ x == y && y != x; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' +63 │ x <= y || x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:67:9 │ -67 │ x == y && y > x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +67 │ x == y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:68:9 │ -68 │ x == y && y < x; +68 │ x == y && y > x; │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -505,15 +497,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:69:9 │ -69 │ x == y && y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' +69 │ x == y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:70:9 │ -70 │ x == y && y <= x; +70 │ x == y && y >= x; │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -521,135 +513,135 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:71:9 │ -71 │ x != y && y > x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +71 │ x == y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:72:9 │ -72 │ x != y && y < x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +72 │ x != y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:73:9 │ -73 │ x != y && y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +73 │ x != y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:74:9 │ -74 │ x != y && y <= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +74 │ x != y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:75:9 │ -75 │ x > y && y < x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +75 │ x != y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:76:9 │ -76 │ x > y && y >= x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +76 │ x > y && y < x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:77:9 │ -77 │ x > y && y <= x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +77 │ x > y && y >= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:78:9 │ -78 │ x < y && y >= x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +78 │ x > y && y <= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:79:9 │ -79 │ x < y && y <= x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +79 │ x < y && y >= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:80:9 │ -80 │ x >= y && y <= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +80 │ x < y && y <= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:81:9 │ -81 │ x == y || y != x; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +81 │ x >= y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:82:9 │ -82 │ x == y || y > x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +82 │ x == y || y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:83:9 │ -83 │ x == y || y < x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +83 │ x == y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:84:9 │ -84 │ x == y || y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +84 │ x == y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:85:9 │ -85 │ x == y || y <= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +85 │ x == y || y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:86:9 │ -86 │ x != y || y > x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' +86 │ x == y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:87:9 │ -87 │ x != y || y < x; +87 │ x != y || y > x; │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -657,15 +649,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:88:9 │ -88 │ x != y || y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +88 │ x != y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:89:9 │ -89 │ x != y || y <= x; +89 │ x != y || y >= x; │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -673,71 +665,71 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:90:9 │ -90 │ x > y || y < x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +90 │ x != y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:91:9 │ -91 │ x > y || y >= x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'true' +91 │ x > y || y < x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:92:9 │ -92 │ x > y || y <= x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +92 │ x > y || y >= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:93:9 │ -93 │ x < y || y >= x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +93 │ x > y || y <= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:94:9 │ -94 │ x < y || y <= x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'true' +94 │ x < y || y >= x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:95:9 │ -95 │ x >= y || y <= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +95 │ x < y || y <= x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:96:9 │ -96 │ x != y && y == x; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' +96 │ x >= y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:97:9 │ -97 │ x > y && y == x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +97 │ x != y && y == x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:98:9 │ -98 │ x < y && y == x; +98 │ x > y && y == x; │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -745,15 +737,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:99:9 │ -99 │ x >= y && y == x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' +99 │ x < y && y == x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:100:9 │ -100 │ x <= y && y == x; +100 │ x >= y && y == x; │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -761,135 +753,135 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:101:9 │ -101 │ x > y && y != x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +101 │ x <= y && y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:102:9 │ -102 │ x < y && y != x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +102 │ x > y && y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:103:9 │ -103 │ x >= y && y != x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +103 │ x < y && y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:104:9 │ -104 │ x <= y && y != x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +104 │ x >= y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:105:9 │ -105 │ x < y && y > x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +105 │ x <= y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:106:9 │ -106 │ x >= y && y > x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +106 │ x < y && y > x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:107:9 │ -107 │ x <= y && y > x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +107 │ x >= y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:108:9 │ -108 │ x >= y && y < x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +108 │ x <= y && y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:109:9 │ -109 │ x <= y && y < x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'false' +109 │ x >= y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:110:9 │ -110 │ x <= y && y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +110 │ x <= y && y < x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:111:9 │ -111 │ x != y || y == x; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +111 │ x <= y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:112:9 │ -112 │ x > y || y == x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +112 │ x != y || y == x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:113:9 │ -113 │ x < y || y == x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +113 │ x > y || y == x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:114:9 │ -114 │ x >= y || y == x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +114 │ x < y || y == x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:115:9 │ -115 │ x <= y || y == x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +115 │ x >= y || y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:116:9 │ -116 │ x > y || y != x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' +116 │ x <= y || y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:117:9 │ -117 │ x < y || y != x; +117 │ x > y || y != x; │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -897,15 +889,15 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:118:9 │ -118 │ x >= y || y != x; - │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' +118 │ x < y || y != x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:119:9 │ -119 │ x <= y || y != x; +119 │ x >= y || y != x; │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -913,79 +905,87 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:120:9 │ -120 │ x < y || y > x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +120 │ x <= y || y != x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:121:9 │ -121 │ x >= y || y > x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'true' +121 │ x < y || y > x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:122:9 │ -122 │ x <= y || y > x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +122 │ x >= y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:123:9 │ -123 │ x >= y || y < x; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +123 │ x <= y || y > x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:124:9 │ -124 │ x <= y || y < x; - │ ^^^^^^^^^^^^^^^ This comparison is always 'true' +124 │ x >= y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:125:9 │ -125 │ x <= y || y >= x; +125 │ x <= y || y < x; + │ ^^^^^^^^^^^^^^^ This comparison is always 'true' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:126:9 + │ +126 │ x <= y || y >= x; │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:128:26 + ┌─ tests/linter/true_positive_combinable_comparisons.move:129:26 │ -128 │ const Values: bool = 5 > 3 || 5 == 3; +129 │ const Values: bool = 5 > 3 || 5 == 3; │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:131:9 + ┌─ tests/linter/true_positive_combinable_comparisons.move:132:9 │ -131 │ 5 != 3 && 5 > 3 +132 │ 5 != 3 && 5 > 3 │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:136:9 + ┌─ tests/linter/true_positive_combinable_comparisons.move:137:9 │ -136 │ {&x} == &y || (x as u64) > (*&y:u64); +137 │ {&x} == &y || (x as u64) > (*&y:u64); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:137:9 + ┌─ tests/linter/true_positive_combinable_comparisons.move:138:9 │ -137 │ © x == &y || x < move y; +138 │ © x == &y || x < move y; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move index a136e27e17a21..16a7161ec39f2 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move @@ -1,3 +1,4 @@ +// tests lints against combinable comparisons that can be simplified to a single comparison. module a::m { fun t(x: u64, y: u64) { x == y && x != y; From 7bec775dcd6722ebae7fbffb5c5977160485d651 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Fri, 6 Dec 2024 10:39:37 -0800 Subject: [PATCH 16/20] simplify logic --- .../src/linters/combinable_comparisons.rs | 162 ++++++------------ 1 file changed, 54 insertions(+), 108 deletions(-) diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs index 62bbcafb44f3b..9be50b08f7afd 100644 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs @@ -28,16 +28,28 @@ enum BoolOp { Or, } +/// See `simplify` for how these values are used. +#[repr(u8)] #[derive(Debug, Clone, Copy)] enum CmpOp { - Eq, - Neq, - Lt, - Gt, - Le, - Ge, + Lt = LT, + Eq = EQ, + Le = LE, + Gt = GT, + Neq = NEQ, + Ge = GE, } +// See `simplify` for how these values are used. +const FALSE: u8 = 0b000; +const LT: u8 = 0b001; +const EQ: u8 = 0b010; +const LE: u8 = 0b011; +const GT: u8 = 0b100; +const NEQ: u8 = 0b101; +const GE: u8 = 0b110; +const TRUE: u8 = 0b111; + simple_visitor!( CombinableComparisons, fn visit_exp_custom(&mut self, exp: &T::Exp) -> bool { @@ -56,10 +68,7 @@ simple_visitor!( else { return false; }; - let simplification = match outer { - BoolOp::And => simplify_and(inner_l, inner_r), - BoolOp::Or => simplify_or(inner_l, inner_r), - }; + let simplification = simplify(outer, inner_l, inner_r); let msg = match simplification { Simplification::Reducible(inner_op) => { format!("simplifies to the operation '{}'", inner_op) @@ -76,104 +85,41 @@ simple_visitor!( } ); -fn simplify_and(op1: CmpOp, op2: CmpOp) -> Simplification { - use CmpOp as C; - Simplification::Reducible(match (op1, op2) { - // same operation - (C::Eq, C::Eq) - | (C::Neq, C::Neq) - | (C::Ge, C::Ge) - | (C::Le, C::Le) - | (C::Lt, C::Lt) - | (C::Gt, C::Gt) => op1, - - // contradiction - (C::Lt, C::Gt) - | (C::Gt, C::Lt) - | (C::Lt, C::Ge) - | (C::Ge, C::Lt) - | (C::Le, C::Gt) - | (C::Gt, C::Le) - | (C::Eq, C::Lt) - | (C::Lt, C::Eq) - | (C::Eq, C::Gt) - | (C::Gt, C::Eq) - | (C::Neq, C::Eq) - | (C::Eq, C::Neq) => return Simplification::AlwaysFalse, - - // == - (C::Le, C::Ge) - | (C::Ge, C::Le) - | (C::Ge, C::Eq) - | (C::Eq, C::Ge) - | (C::Le, C::Eq) - | (C::Eq, C::Le) => C::Eq, - - // < - (C::Lt, C::Le) - | (C::Le, C::Lt) - | (C::Lt, C::Neq) - | (C::Neq, C::Lt) - | (C::Le, C::Neq) - | (C::Neq, C::Le) => C::Lt, - // > - (C::Gt, C::Ge) - | (C::Ge, C::Gt) - | (C::Gt, C::Neq) - | (C::Neq, C::Gt) - | (C::Ge, C::Neq) - | (C::Neq, C::Ge) => C::Gt, - }) -} - -fn simplify_or(op1: CmpOp, op2: CmpOp) -> Simplification { - use CmpOp as C; - Simplification::Reducible(match (op1, op2) { - // same operation - (C::Eq, C::Eq) - | (C::Neq, C::Neq) - | (C::Ge, C::Ge) - | (C::Le, C::Le) - | (C::Lt, C::Lt) - | (C::Gt, C::Gt) => op1, - - // tautology - (C::Neq, C::Le) - | (C::Neq, C::Ge) - | (C::Le, C::Neq) - | (C::Ge, C::Neq) - | (C::Gt, C::Le) - | (C::Le, C::Gt) - | (C::Lt, C::Ge) - | (C::Ge, C::Lt) - | (C::Ge, C::Le) - | (C::Le, C::Ge) - | (C::Neq, C::Eq) - | (C::Eq, C::Neq) => return Simplification::AlwaysTrue, - - // != - (C::Neq, C::Lt) - | (C::Neq, C::Gt) - | (C::Lt, C::Neq) - | (C::Gt, C::Neq) - | (C::Lt, C::Gt) - | (C::Gt, C::Lt) => C::Neq, - - // <= - (C::Lt, C::Le) - | (C::Le, C::Lt) - | (C::Eq, C::Lt) - | (C::Lt, C::Eq) - | (C::Eq, C::Le) - | (C::Le, C::Eq) => C::Le, - // >= - (C::Gt, C::Ge) - | (C::Ge, C::Gt) - | (C::Eq, C::Gt) - | (C::Eq, C::Ge) - | (C::Gt, C::Eq) - | (C::Ge, C::Eq) => C::Ge, - }) +/// Each binary operator is represented as a 3-bit number where each bit represents a range of +/// possible values. With three bits, 0bLEG we are "drawing" an interval of ranges. The comparison +/// `true` if the value is within the interval. so for `x cmp y`` +/// ```text +/// G E L +/// ^ this bit represents x < y (less than the equal bit) +/// ^ this bit represents x == y (the equal bit) +/// ^ this bit represents x > y (greater than the equal bit) +/// ``` +/// We then take the disjunction of intervals by the bits--creating a bitset. +/// So for example, `>=` is 0b110 since the interval is either greater OR equal. +/// And for `!=` is 0b101 since the interval is either not equal OR less than. We are only dealing +/// with primitives so we know the values are well ordered. +/// From there we can then bitwise-or the bits (set union) when the outer operation is `||` and +/// bitwise-and the bits (set intersection) when the outer operation is `&&` to get the final +/// "simplified" operation. If all bits are set, then the operation is always true. If no bits are +/// set, then the operation is always false. +fn simplify(outer: BoolOp, inner_l: CmpOp, inner_r: CmpOp) -> Simplification { + let lbits = inner_l as u8; + let rbits = inner_r as u8; + let simplification = match outer { + BoolOp::And => lbits & rbits, + BoolOp::Or => lbits | rbits, + }; + match simplification { + FALSE => Simplification::AlwaysFalse, + LT => Simplification::Reducible(CmpOp::Lt), + EQ => Simplification::Reducible(CmpOp::Eq), + LE => Simplification::Reducible(CmpOp::Le), + GT => Simplification::Reducible(CmpOp::Gt), + NEQ => Simplification::Reducible(CmpOp::Neq), + GE => Simplification::Reducible(CmpOp::Ge), + TRUE => Simplification::AlwaysTrue, + _ => unreachable!(), + } } fn bool_op(sp!(_, bop_): &BinOp) -> Option { From c915f9d32f7a48520e545de86b18b78f72075851 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Fri, 6 Dec 2024 10:45:09 -0800 Subject: [PATCH 17/20] revert toml change --- external-crates/move/crates/move-compiler/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/external-crates/move/crates/move-compiler/Cargo.toml b/external-crates/move/crates/move-compiler/Cargo.toml index 4820f2b277887..b5c70b962a5ba 100644 --- a/external-crates/move/crates/move-compiler/Cargo.toml +++ b/external-crates/move/crates/move-compiler/Cargo.toml @@ -25,6 +25,7 @@ similar.workspace = true stacker.workspace = true vfs.workspace = true + bcs.workspace = true move-binary-format.workspace = true From c1b5bbe0eabe63043e5bca39c411e8de3d8dab65 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Fri, 6 Dec 2024 10:47:09 -0800 Subject: [PATCH 18/20] fix comment --- .../crates/move-compiler/src/linters/combinable_comparisons.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs index 9be50b08f7afd..c98ce81a0196f 100644 --- a/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs +++ b/external-crates/move/crates/move-compiler/src/linters/combinable_comparisons.rs @@ -86,7 +86,7 @@ simple_visitor!( ); /// Each binary operator is represented as a 3-bit number where each bit represents a range of -/// possible values. With three bits, 0bLEG we are "drawing" an interval of ranges. The comparison +/// possible values. With three bits, 0bGEL we are "drawing" an interval of ranges. The comparison /// `true` if the value is within the interval. so for `x cmp y`` /// ```text /// G E L From 202a8c9ee79d5ede65bac26cd9b6b1b4553dc907 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Fri, 6 Dec 2024 11:13:31 -0800 Subject: [PATCH 19/20] more tests --- .../true_positive_combinable_comparisons.exp | 160 +++++++++++++++++- .../true_positive_combinable_comparisons.move | 21 +++ 2 files changed, 173 insertions(+), 8 deletions(-) diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp index acada3edbb5ac..2a7bc44596916 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp @@ -959,33 +959,177 @@ warning[Lint W01012]: comparison operations condition can be simplified = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified - ┌─ tests/linter/true_positive_combinable_comparisons.move:129:26 + ┌─ tests/linter/true_positive_combinable_comparisons.move:130:9 │ -129 │ const Values: bool = 5 > 3 || 5 == 3; - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +130 │ x == y && x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:131:9 + │ +131 │ x != y && x != y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:132:9 │ -132 │ 5 != 3 && 5 > 3 - │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +132 │ x > y && x > y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:133:9 + │ +133 │ x < y && x < y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:134:9 + │ +134 │ x >= y && x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:135:9 + │ +135 │ x <= y && x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:136:9 + │ +136 │ x == y || x == y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:137:9 │ -137 │ {&x} == &y || (x as u64) > (*&y:u64); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +137 │ x != y || x != y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:138:9 │ -138 │ © x == &y || x < move y; +138 │ x > y || x > y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:139:9 + │ +139 │ x < y || x < y; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:140:9 + │ +140 │ x >= y || x >= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:141:9 + │ +141 │ x <= y || x <= y; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:142:9 + │ +142 │ x == y && y == x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:143:9 + │ +143 │ x != y && y != x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:144:9 + │ +144 │ x > y && y < x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:145:9 + │ +145 │ x < y && y > x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:146:9 + │ +146 │ x >= y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:147:9 + │ +147 │ x <= y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:150:26 + │ +150 │ const Values: bool = 5 > 3 || 5 == 3; + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:153:9 + │ +153 │ 5 != 3 && 5 > 3 + │ ^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:158:9 + │ +158 │ {&x} == &y || (x as u64) > (*&y:u64); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' + │ + = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[Lint W01012]: comparison operations condition can be simplified + ┌─ tests/linter/true_positive_combinable_comparisons.move:159:9 + │ +159 │ © x == &y || x < move y; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move index 16a7161ec39f2..855676a1286ce 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move @@ -126,6 +126,27 @@ module a::m { x <= y || y >= x; } + fun same_op(x: u64, y: u64) { + x == y && x == y; + x != y && x != y; + x > y && x > y; + x < y && x < y; + x >= y && x >= y; + x <= y && x <= y; + x == y || x == y; + x != y || x != y; + x > y || x > y; + x < y || x < y; + x >= y || x >= y; + x <= y || x <= y; + x == y && y == x; + x != y && y != x; + x > y && y < x; + x < y && y > x; + x >= y && y <= x; + x <= y && y >= x; + } + const Values: bool = 5 > 3 || 5 == 3; fun values(): bool { From ce236aa3cdaf74a98e4f545ca9dbc65832a1c493 Mon Sep 17 00:00:00 2001 From: Todd Nowacki Date: Fri, 6 Dec 2024 11:22:11 -0800 Subject: [PATCH 20/20] fix flipped cases --- .../true_positive_combinable_comparisons.exp | 32 +++++++++---------- .../true_positive_combinable_comparisons.move | 16 +++++----- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp index 2a7bc44596916..45d20929184be 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.exp @@ -553,8 +553,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:76:9 │ -76 │ x > y && y < x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +76 │ x > y && y > x; + │ ^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -593,8 +593,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:81:9 │ -81 │ x >= y && y <= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +81 │ x >= y && y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -673,8 +673,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:91:9 │ -91 │ x > y || y < x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '>' +91 │ x > y || y > x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -713,8 +713,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:96:9 │ -96 │ x >= y || y <= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '>=' +96 │ x >= y || y >= x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -793,8 +793,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:106:9 │ -106 │ x < y && y > x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +106 │ x < y && y < x; + │ ^^^^^^^^^^^^^^ This comparison is always 'false' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -833,8 +833,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:111:9 │ -111 │ x <= y && y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +111 │ x <= y && y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '==' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -913,8 +913,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:121:9 │ -121 │ x < y || y > x; - │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '<' +121 │ x < y || y < x; + │ ^^^^^^^^^^^^^^ This comparison simplifies to the operation '!=' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') @@ -953,8 +953,8 @@ warning[Lint W01012]: comparison operations condition can be simplified warning[Lint W01012]: comparison operations condition can be simplified ┌─ tests/linter/true_positive_combinable_comparisons.move:126:9 │ -126 │ x <= y || y >= x; - │ ^^^^^^^^^^^^^^^^ This comparison simplifies to the operation '<=' +126 │ x <= y || y <= x; + │ ^^^^^^^^^^^^^^^^ This comparison is always 'true' │ = This warning can be suppressed with '#[allow(lint(combinable_comparisons))]' applied to the 'module' or module member ('const', 'fun', or 'struct') diff --git a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move index 855676a1286ce..4f209cb586457 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move +++ b/external-crates/move/crates/move-compiler/tests/linter/true_positive_combinable_comparisons.move @@ -73,12 +73,12 @@ module a::m { x != y && y < x; x != y && y >= x; x != y && y <= x; - x > y && y < x; + x > y && y > x; x > y && y >= x; x > y && y <= x; x < y && y >= x; x < y && y <= x; - x >= y && y <= x; + x >= y && y >= x; x == y || y != x; x == y || y > x; x == y || y < x; @@ -88,12 +88,12 @@ module a::m { x != y || y < x; x != y || y >= x; x != y || y <= x; - x > y || y < x; + x > y || y > x; x > y || y >= x; x > y || y <= x; x < y || y >= x; x < y || y <= x; - x >= y || y <= x; + x >= y || y >= x; x != y && y == x; x > y && y == x; x < y && y == x; @@ -103,12 +103,12 @@ module a::m { x < y && y != x; x >= y && y != x; x <= y && y != x; - x < y && y > x; + x < y && y < x; x >= y && y > x; x <= y && y > x; x >= y && y < x; x <= y && y < x; - x <= y && y >= x; + x <= y && y <= x; x != y || y == x; x > y || y == x; x < y || y == x; @@ -118,12 +118,12 @@ module a::m { x < y || y != x; x >= y || y != x; x <= y || y != x; - x < y || y > x; + x < y || y < x; x >= y || y > x; x <= y || y > x; x >= y || y < x; x <= y || y < x; - x <= y || y >= x; + x <= y || y <= x; } fun same_op(x: u64, y: u64) {