From 8249a1362b8773888018629cfb69c391499f3b76 Mon Sep 17 00:00:00 2001 From: Esorat Date: Mon, 21 Oct 2024 13:15:13 +0700 Subject: [PATCH 01/14] fix: add command: yarn misti --list-detectors --- src/cli/cli.ts | 15 +++++++++++++++ src/cli/options.ts | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 697493a6..7ecc332f 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -13,6 +13,7 @@ import { } from "./result"; import { Logger } from "../internals/logger"; import { Command } from "commander"; +import { BuiltInDetectors } from "../detectors/detector"; /** * Creates and configures the Misti CLI command. @@ -36,10 +37,24 @@ export function createMistiCommand(): Command { createDetector(options.newDetector); return; } + if (options.listDetectors) { + listAvailableDetectors(); + process.exit(0); + } }); return command; } +/** + * Function to list available detectors. + */ +function listAvailableDetectors() { + console.log("Available Detectors:"); + for (const detectorName in BuiltInDetectors) { + console.log(`- ${detectorName}`); + } +} + /** * Runs the Misti CLI command with the provided arguments. * @param args The list of arguments to pass to the CLI command. diff --git a/src/cli/options.ts b/src/cli/options.ts index 4a920afb..ab1cb3c9 100644 --- a/src/cli/options.ts +++ b/src/cli/options.ts @@ -22,6 +22,7 @@ export interface CLIOptions { allDetectors: boolean; config: string | undefined; newDetector: string | undefined; + listDetectors: boolean; } export const cliOptionDefaults: Required = { @@ -42,6 +43,7 @@ export const cliOptionDefaults: Required = { allDetectors: false, config: undefined, newDetector: undefined, + listDetectors: false, }; export const cliOptions = [ @@ -70,6 +72,9 @@ export const cliOptions = [ new Option("--list-tools", "List available tools and their options.").default( cliOptionDefaults.listTools, ), + new Option("--list-detectors", "List available detectors.").default( + cliOptionDefaults.listDetectors, + ), new Option( "-o, --output-format ", "Set the output format for all tools and warnings", From 4a3dbf1f7f8ca944dd3ef98cb94ddc6478d3a317 Mon Sep 17 00:00:00 2001 From: Esorat Date: Mon, 21 Oct 2024 16:33:46 +0700 Subject: [PATCH 02/14] fix: add needed to cli --- src/cli/cli.ts | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 7ecc332f..bdd2ae79 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -2,6 +2,7 @@ import { Driver } from "./driver"; import { cliOptions, STDOUT_PATH } from "./options"; import { OutputFormat } from "../cli"; import { createDetector } from "../createDetector"; +import { BuiltInDetectors } from "../detectors/detector"; import { unreachable } from "../internals/util"; import { generateToolsHelpMessage } from "../tools/tool"; import { MISTI_VERSION, TACT_VERSION } from "../version"; @@ -13,7 +14,6 @@ import { } from "./result"; import { Logger } from "../internals/logger"; import { Command } from "commander"; -import { BuiltInDetectors } from "../detectors/detector"; /** * Creates and configures the Misti CLI command. @@ -27,34 +27,25 @@ export function createMistiCommand(): Command { .arguments("[TACT_CONFIG_PATH|TACT_FILE_PATH]"); cliOptions.forEach((option) => command.addOption(option)); command.action(async (_tactPath, options) => { + const logger = new Logger(); if (options.listTools) { const toolsHelpMessage = await generateToolsHelpMessage(); - // eslint-disable-next-line no-console - console.log(toolsHelpMessage); + logger.info(toolsHelpMessage); + process.exit(0); + } + if (options.listDetectors) { + const detectorNames = Object.keys(BuiltInDetectors); + detectorNames.forEach((name) => logger.info(`- ${name}`)); process.exit(0); } if (options.newDetector) { createDetector(options.newDetector); return; } - if (options.listDetectors) { - listAvailableDetectors(); - process.exit(0); - } }); return command; } -/** - * Function to list available detectors. - */ -function listAvailableDetectors() { - console.log("Available Detectors:"); - for (const detectorName in BuiltInDetectors) { - console.log(`- ${detectorName}`); - } -} - /** * Runs the Misti CLI command with the provided arguments. * @param args The list of arguments to pass to the CLI command. From 36efa2b45e9aeca2a83eb29c8c72fb926c1fcc0e Mon Sep 17 00:00:00 2001 From: Esorat Date: Mon, 21 Oct 2024 22:36:20 +0700 Subject: [PATCH 03/14] WIP: add new detector suspiciousMessageMode --- .../builtin/suspiciousMessageMode.ts | 133 ++++++++++++++++++ src/detectors/detector.ts | 7 + .../SuspiciousMessageMode.expected.out | 71 ++++++++++ test/detectors/SuspiciousMessageMode.tact | 112 +++++++++++++++ 4 files changed, 323 insertions(+) create mode 100644 src/detectors/builtin/suspiciousMessageMode.ts create mode 100644 test/detectors/SuspiciousMessageMode.expected.out create mode 100644 test/detectors/SuspiciousMessageMode.tact diff --git a/src/detectors/builtin/suspiciousMessageMode.ts b/src/detectors/builtin/suspiciousMessageMode.ts new file mode 100644 index 00000000..7788b3f5 --- /dev/null +++ b/src/detectors/builtin/suspiciousMessageMode.ts @@ -0,0 +1,133 @@ +import { CompilationUnit } from "../../internals/ir"; +import { foldExpressions, foldStatements } from "../../internals/tact"; +import { MistiTactWarning, Severity } from "../../internals/warnings"; +import { ASTDetector } from "../detector"; +import { + AstExpression, + AstStructInstance, + idText, + AstOpBinary, + AstId, + AstStaticCall, +} from "@tact-lang/compiler/dist/grammar/ast"; + +export class SuspiciousMessageMode extends ASTDetector { + severity = Severity.MEDIUM; + + async check(cu: CompilationUnit): Promise { + const warnings: MistiTactWarning[] = []; + Array.from(cu.ast.getProgramEntries()).forEach((node) => { + foldStatements( + node, + (acc, stmt) => { + foldExpressions( + stmt, + (acc, expr) => { + if (this.isSendParametersStruct(expr)) { + this.checkSendParameters(expr, acc); + } + return acc; + }, + acc, + ); + return acc; + }, + warnings, + ); + }); + return warnings; + } + + private isSendParametersStruct(expr: AstExpression): boolean { + if (expr.kind === "struct_instance") { + return idText((expr as AstStructInstance).type) === "SendParameters"; + } + if (expr.kind === "static_call") { + return idText((expr as AstStaticCall).function) === "SendParameters"; + } + return false; + } + + private checkSendParameters( + expr: AstExpression, + warnings: MistiTactWarning[], + ): void { + let args: any[] = []; + if (expr.kind === "struct_instance") { + args = (expr as AstStructInstance).args; + } else if (expr.kind === "static_call") { + args = (expr as AstStaticCall).args; + } + const modeField = args.find((arg) => { + if (arg.kind === "struct_field_initializer") { + return idText(arg.field) === "mode"; + } + if (arg.kind === "named_argument") { + return idText(arg.name) === "mode"; + } + return false; + }); + if (modeField && modeField.initializer) { + this.checkModeExpression(modeField.initializer, warnings); + } + } + + private checkModeExpression( + expr: AstExpression, + warnings: MistiTactWarning[], + ): void { + const flagsUsed = new Set(); + const traverse = (expr: AstExpression): void => { + switch (expr.kind) { + case "op_binary": + const opBinary = expr as AstOpBinary; + if (opBinary.op !== "|") { + warnings.push( + this.makeWarning( + "Mode expression should only contain the '|' operator", + expr.loc, + { + suggestion: + "Use the '|' operator (bitwise OR) to combine flags", + }, + ), + ); + } + traverse(opBinary.left); + traverse(opBinary.right); + break; + case "id": + const flagName = idText(expr as AstId); + if (flagsUsed.has(flagName)) { + warnings.push( + this.makeWarning( + `Flag '${flagName}' is used multiple times in mode expression`, + expr.loc, + { + suggestion: `Use each flag at most once in the mode expression`, + }, + ), + ); + } else { + flagsUsed.add(flagName); + } + break; + case "number": + warnings.push( + this.makeWarning( + "Integer literals should not be used in mode expression; use symbolic constants instead", + expr.loc, + { + suggestion: + "Replace integer literals with symbolic flag constants", + }, + ), + ); + break; + default: + break; + } + }; + traverse(expr); + } +} diff --git a/src/detectors/detector.ts b/src/detectors/detector.ts index 3ea2d2ae..2fe575eb 100644 --- a/src/detectors/detector.ts +++ b/src/detectors/detector.ts @@ -378,6 +378,13 @@ export const BuiltInDetectors: Record = { ), enabledByDefault: true, }, + SuspiciousMessageMode: { + loader: (ctx: MistiContext) => + import("./builtin/suspiciousMessageMode").then( + (module) => new module.SuspiciousMessageMode(ctx), + ), + enabledByDefault: true, + }, }; /** diff --git a/test/detectors/SuspiciousMessageMode.expected.out b/test/detectors/SuspiciousMessageMode.expected.out new file mode 100644 index 00000000..52429708 --- /dev/null +++ b/test/detectors/SuspiciousMessageMode.expected.out @@ -0,0 +1,71 @@ +[MEDIUM] SuspiciousMessageMode: Flag 'CustomSendRemainingValue' is used multiple times in mode expression +test/detectors/SuspiciousMessageMode.tact:21:46: + 20 | value: 0, +> 21 | mode: CustomSendRemainingValue | CustomSendRemainingValue + ^ + 22 | }); +Help: Use each flag at most once in the mode expression +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Mode expression should only contain the '|' operator +test/detectors/SuspiciousMessageMode.tact:30:19: + 29 | value: 0, +> 30 | mode: CustomSendRemainingValue + CustomSendAllBalance + ^ + 31 | }); +Help: Use the '|' operator (bitwise OR) to combine flags +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Integer literals should not be used in mode expression; use symbolic constants instead +test/detectors/SuspiciousMessageMode.tact:39:19: + 38 | value: 0, +> 39 | mode: 64 // Integer literal instead of symbolic constant + ^ + 40 | }); +Help: Replace integer literals with symbolic flag constants +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Mode expression should only contain the '|' operator +test/detectors/SuspiciousMessageMode.tact:57:19: + 56 | value: 0, +> 57 | mode: CustomSendRemainingValue + CustomSendRemainingValue + 64 // Duplicate flags, '+' operator, integer literal + ^ + 58 | }); +Help: Use the '|' operator (bitwise OR) to combine flags +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Flag 'CustomSendRemainingValue' is used multiple times in mode expression +test/detectors/SuspiciousMessageMode.tact:57:46: + 56 | value: 0, +> 57 | mode: CustomSendRemainingValue + CustomSendRemainingValue + 64 // Duplicate flags, '+' operator, integer literal + ^ + 58 | }); +Help: Use each flag at most once in the mode expression +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Integer literals should not be used in mode expression; use symbolic constants instead +test/detectors/SuspiciousMessageMode.tact:57:73: + 56 | value: 0, +> 57 | mode: CustomSendRemainingValue + CustomSendRemainingValue + 64 // Duplicate flags, '+' operator, integer literal + ^ + 58 | }); +Help: Replace integer literals with symbolic flag constants +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Mode expression should only contain the '|' operator +test/detectors/SuspiciousMessageMode.tact:66:19: + 65 | value: 0, +> 66 | mode: (CustomSendRemainingValue * CustomSendAllBalance) - CustomSendIgnoreErrors + ^ + 67 | }); +Help: Use the '|' operator (bitwise OR) to combine flags +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Mode expression should only contain the '|' operator +test/detectors/SuspiciousMessageMode.tact:66:20: + 65 | value: 0, +> 66 | mode: (CustomSendRemainingValue * CustomSendAllBalance) - CustomSendIgnoreErrors + ^ + 67 | }); +Help: Use the '|' operator (bitwise OR) to combine flags +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode \ No newline at end of file diff --git a/test/detectors/SuspiciousMessageMode.tact b/test/detectors/SuspiciousMessageMode.tact new file mode 100644 index 00000000..c5c976da --- /dev/null +++ b/test/detectors/SuspiciousMessageMode.tact @@ -0,0 +1,112 @@ +// Define custom constants +const CustomSendRemainingValue: Int = 64; +const CustomSendAllBalance: Int = 128; +const CustomSendIgnoreErrors: Int = 1; + +contract SendParametersTestContract { + // Correct usage: should not trigger any warnings + fun correctUsage() { + send(SendParameters{ + to: sender(), + value: 0, + mode: CustomSendRemainingValue + }); + } + + // Duplicate flag usage: should trigger a warning about flags used multiple times + fun duplicateFlagUsage() { + send(SendParameters{ + to: sender(), + value: 0, + mode: CustomSendRemainingValue | CustomSendRemainingValue + }); + } + + // Invalid operator usage: should trigger a warning about using '+' instead of '|' + fun invalidOperatorUsage() { + send(SendParameters{ + to: sender(), + value: 0, + mode: CustomSendRemainingValue + CustomSendAllBalance + }); + } + + // Integer literal usage: should trigger a warning about using integer literals + fun integerLiteralUsage() { + send(SendParameters{ + to: sender(), + value: 0, + mode: 64 // Integer literal instead of symbolic constant + }); + } + + // Correct combination usage: should not trigger any warnings + fun correctCombinationUsage() { + send(SendParameters{ + to: sender(), + value: 0, + mode: CustomSendRemainingValue | CustomSendAllBalance | CustomSendIgnoreErrors + }); + } + + // Multiple issues: should trigger multiple warnings + fun multipleIssues() { + send(SendParameters{ + to: sender(), + value: 0, + mode: CustomSendRemainingValue + CustomSendRemainingValue + 64 // Duplicate flags, '+' operator, integer literal + }); + } + + // Complex expression with nested invalid operators + fun complexInvalidOperator() { + send(SendParameters{ + to: sender(), + value: 0, + mode: (CustomSendRemainingValue * CustomSendAllBalance) - CustomSendIgnoreErrors + }); + } + + // Define functionReturningLiteral within the contract scope + fun functionReturningLiteral(): Int { + return 64; + } + + // Using a function call that returns an integer literal: should trigger a warning + fun functionCallWithLiteral() { + send(SendParameters{ + to: sender(), + value: 0, + mode: self.functionReturningLiteral() // Uses integer literal instead of symbolic constant + }); + } + +// Using undefined symbolic constants: should trigger a warning if the constant is not recognized + fun undefinedSymbolicConstant() { + send(SendParameters{ + to: sender(), + value: 0, + mode: CustomSendIgnoreErrors | CustomSendAllBalance + }); +} + + // Correct usage with variables + fun correctUsageWithVariables() { + let modeFlag: Int = CustomSendRemainingValue | CustomSendIgnoreErrors; + send(SendParameters{ + to: sender(), + value: 0, + mode: modeFlag + }); + } + + // Invalid usage with variables containing integer literals + fun invalidUsageWithVariableLiteral() { + let modeFlag: Int = 64; + send(SendParameters{ + to: sender(), + value: 0, + mode: modeFlag // modeFlag contains an integer literal + }); + } +} From 23b30537173af23c3264f8c019c88c4b52c43dfe Mon Sep 17 00:00:00 2001 From: Esorat Date: Tue, 22 Oct 2024 12:11:02 +0700 Subject: [PATCH 04/14] fix: refactoring --- .../builtin/suspiciousMessageMode.ts | 51 ++++--------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/src/detectors/builtin/suspiciousMessageMode.ts b/src/detectors/builtin/suspiciousMessageMode.ts index 7788b3f5..7dc9d33e 100644 --- a/src/detectors/builtin/suspiciousMessageMode.ts +++ b/src/detectors/builtin/suspiciousMessageMode.ts @@ -1,5 +1,5 @@ import { CompilationUnit } from "../../internals/ir"; -import { foldExpressions, foldStatements } from "../../internals/tact"; +import { forEachExpression } from "../../internals/tact"; import { MistiTactWarning, Severity } from "../../internals/warnings"; import { ASTDetector } from "../detector"; import { @@ -8,7 +8,6 @@ import { idText, AstOpBinary, AstId, - AstStaticCall, } from "@tact-lang/compiler/dist/grammar/ast"; export class SuspiciousMessageMode extends ASTDetector { @@ -17,34 +16,18 @@ export class SuspiciousMessageMode extends ASTDetector { async check(cu: CompilationUnit): Promise { const warnings: MistiTactWarning[] = []; Array.from(cu.ast.getProgramEntries()).forEach((node) => { - foldStatements( - node, - (acc, stmt) => { - foldExpressions( - stmt, - (acc, expr) => { - if (this.isSendParametersStruct(expr)) { - this.checkSendParameters(expr, acc); - } - return acc; - }, - acc, - ); - return acc; - }, - warnings, - ); + forEachExpression(node, (expr) => { + if (this.isSendParametersStruct(expr)) { + this.checkSendParameters(expr, warnings); + } + }); }); return warnings; } - private isSendParametersStruct(expr: AstExpression): boolean { if (expr.kind === "struct_instance") { return idText((expr as AstStructInstance).type) === "SendParameters"; } - if (expr.kind === "static_call") { - return idText((expr as AstStaticCall).function) === "SendParameters"; - } return false; } @@ -52,22 +35,9 @@ export class SuspiciousMessageMode extends ASTDetector { expr: AstExpression, warnings: MistiTactWarning[], ): void { - let args: any[] = []; - if (expr.kind === "struct_instance") { - args = (expr as AstStructInstance).args; - } else if (expr.kind === "static_call") { - args = (expr as AstStaticCall).args; - } - const modeField = args.find((arg) => { - if (arg.kind === "struct_field_initializer") { - return idText(arg.field) === "mode"; - } - if (arg.kind === "named_argument") { - return idText(arg.name) === "mode"; - } - return false; - }); - if (modeField && modeField.initializer) { + const args = (expr as AstStructInstance).args; + const modeField = args.find((arg) => idText(arg.field) === "mode"); + if (modeField) { this.checkModeExpression(modeField.initializer, warnings); } } @@ -104,7 +74,8 @@ export class SuspiciousMessageMode extends ASTDetector { `Flag '${flagName}' is used multiple times in mode expression`, expr.loc, { - suggestion: `Use each flag at most once in the mode expression`, + suggestion: + "Use each flag at most once in the mode expression", }, ), ); From 9b88f7600adbf19979e71fdf0c13a18a68fe2acb Mon Sep 17 00:00:00 2001 From: Esorat Date: Tue, 22 Oct 2024 20:11:18 +0700 Subject: [PATCH 05/14] WIP: detector EtaLikeSimplifications --- .../builtin/etaLikeSimplifications.ts | 172 ++++++++++++++++++ src/detectors/detector.ts | 7 + test/detectors/EtaLikeSimplifications.tact | 25 +++ 3 files changed, 204 insertions(+) create mode 100644 src/detectors/builtin/etaLikeSimplifications.ts create mode 100644 test/detectors/EtaLikeSimplifications.tact diff --git a/src/detectors/builtin/etaLikeSimplifications.ts b/src/detectors/builtin/etaLikeSimplifications.ts new file mode 100644 index 00000000..5e199cc4 --- /dev/null +++ b/src/detectors/builtin/etaLikeSimplifications.ts @@ -0,0 +1,172 @@ +// src/detectors/builtin/EtaLikeSimplifications.ts + +import { CompilationUnit } from "../../internals/ir"; +import { forEachStatement, forEachExpression } from "../../internals/tact"; +import { MistiTactWarning, Severity } from "../../internals/warnings"; +import { ASTDetector } from "../detector"; +import { + AstNode, + AstStatement, + AstExpression, + AstOpBinary, + idText, + AstStatementReturn, + AstConditional, +} from "@tact-lang/compiler/dist/grammar/ast"; + +export class EtaLikeSimplifications extends ASTDetector { + severity = Severity.LOW; + + async check(cu: CompilationUnit): Promise { + console.log("EtaLikeSimplifications detector is running"); + const warnings: MistiTactWarning[] = []; + + const entries = cu.ast.getProgramEntries(); + console.log("Number of program entries:", entries.length); + + for (const node of entries) { + this.analyzeNode(node, warnings); + } + + return warnings; + } + + private analyzeNode(node: AstNode, warnings: MistiTactWarning[]): void { + console.log("Analyzing node:", node.kind); + + forEachStatement(node, (stmt) => { + console.log("Statement kind:", stmt.kind); + this.checkStatement(stmt, warnings); + }); + + forEachExpression(node, (expr) => { + console.log("Expression kind:", expr.kind); + this.checkExpression(expr, warnings); + }); + } + + private checkStatement( + stmt: AstStatement, + warnings: MistiTactWarning[], + ): void { + if (stmt.kind === "statement_condition") { + const ifStmt = stmt; + + if ( + ifStmt.trueStatements.length === 1 && + ifStmt.falseStatements && + ifStmt.falseStatements.length === 1 && + ifStmt.trueStatements[0].kind === "statement_return" && + ifStmt.falseStatements[0].kind === "statement_return" + ) { + const trueReturn = ifStmt.trueStatements[0] as AstStatementReturn; + const falseReturn = ifStmt.falseStatements[0] as AstStatementReturn; + + if ( + this.isBooleanLiteral(trueReturn.expression, true) && + this.isBooleanLiteral(falseReturn.expression, false) + ) { + warnings.push( + this.makeWarning( + "Simplify 'if' statement by returning the condition directly", + stmt.loc, + { + suggestion: "Replace with 'return condition;'", + }, + ), + ); + } + } + } + } + + private checkExpression( + expr: AstExpression, + warnings: MistiTactWarning[], + ): void { + // Check for `boolean_expression == true` or `boolean_expression == false` + if (expr.kind === "op_binary") { + const binaryExpr = expr as AstOpBinary; + if (binaryExpr.op === "==" || binaryExpr.op === "!=") { + const { left, right } = binaryExpr; + if (this.isBooleanLiteral(right)) { + warnings.push( + this.makeWarning( + `Redundant comparison with boolean literal`, + expr.loc, + { + suggestion: `Use '${this.getSimplifiedBooleanExpression( + binaryExpr, + )}' instead`, + }, + ), + ); + } + } + } + + // Check for conditional expressions like `cond ? true : false` + if (expr.kind === "conditional") { + const conditionalExpr = expr as AstConditional; + if ( + this.isBooleanLiteral(conditionalExpr.thenBranch, true) && + this.isBooleanLiteral(conditionalExpr.elseBranch, false) + ) { + warnings.push( + this.makeWarning( + "Simplify conditional expression by using the condition directly", + expr.loc, + { + suggestion: `Use '${this.getConditionText(conditionalExpr.condition)}' instead`, + }, + ), + ); + } + } + } + + private isBooleanLiteral( + expr: AstExpression | null | undefined, + value?: boolean, + ): boolean { + if (!expr) return false; + if (expr.kind === "boolean") { + if (value === undefined) { + return true; + } + return expr.value === value; + } + return false; + } + + private getSimplifiedBooleanExpression(binaryExpr: AstOpBinary): string { + const exprText = (expr: AstExpression): string => { + if (expr.kind === "id") { + return idText(expr); + } + return "expression"; + }; + + if (this.isBooleanLiteral(binaryExpr.right, true)) { + if (binaryExpr.op === "==") { + return exprText(binaryExpr.left); + } else { + return `!${exprText(binaryExpr.left)}`; + } + } else if (this.isBooleanLiteral(binaryExpr.right, false)) { + if (binaryExpr.op === "==") { + return `!${exprText(binaryExpr.left)}`; + } else { + return exprText(binaryExpr.left); + } + } + return "expression"; + } + + private getConditionText(expr: AstExpression): string { + if (expr.kind === "id") { + return idText(expr); + } + return "condition"; + } +} diff --git a/src/detectors/detector.ts b/src/detectors/detector.ts index 2fe575eb..e764d252 100644 --- a/src/detectors/detector.ts +++ b/src/detectors/detector.ts @@ -385,6 +385,13 @@ export const BuiltInDetectors: Record = { ), enabledByDefault: true, }, + EtaLikeSimplifications: { + loader: (ctx: MistiContext) => + import("./builtin/etaLikeSimplifications").then( + (module) => new module.EtaLikeSimplifications(ctx), + ), + enabledByDefault: false, + }, }; /** diff --git a/test/detectors/EtaLikeSimplifications.tact b/test/detectors/EtaLikeSimplifications.tact new file mode 100644 index 00000000..bdbc1093 --- /dev/null +++ b/test/detectors/EtaLikeSimplifications.tact @@ -0,0 +1,25 @@ +contract TestContract { + // Example of redundant if statement + fun redundantIf(condition: Bool): Bool { + if (condition) { + return true; + } else { + return false; + } + } + + // Example of redundant boolean comparison + fun redundantComparison(a: Bool): Bool { + return a == true; + } + + // Example of redundant ternary expression + fun redundantTernary(b: Bool): Bool { + return b ? true : false; + } + + // Correct usage (should not trigger warnings) + fun correctUsage(condition: Bool): Bool { + return condition; + } +} From 4134e5aa51b2bc2f699fffb9840b798c291eb839 Mon Sep 17 00:00:00 2001 From: Esorat Date: Thu, 24 Oct 2024 19:48:50 +0700 Subject: [PATCH 06/14] WIP: Create detector etaLikeSimplifications --- .../builtin/etaLikeSimplifications.ts | 60 ++++++++++++------- src/detectors/detector.ts | 2 +- .../EtaLikeSimplifications.expected.out | 26 ++++++++ test/detectors/EtaLikeSimplifications.tact | 8 +-- 4 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 test/detectors/EtaLikeSimplifications.expected.out diff --git a/src/detectors/builtin/etaLikeSimplifications.ts b/src/detectors/builtin/etaLikeSimplifications.ts index 5e199cc4..1f0adeca 100644 --- a/src/detectors/builtin/etaLikeSimplifications.ts +++ b/src/detectors/builtin/etaLikeSimplifications.ts @@ -1,5 +1,3 @@ -// src/detectors/builtin/EtaLikeSimplifications.ts - import { CompilationUnit } from "../../internals/ir"; import { forEachStatement, forEachExpression } from "../../internals/tact"; import { MistiTactWarning, Severity } from "../../internals/warnings"; @@ -14,33 +12,58 @@ import { AstConditional, } from "@tact-lang/compiler/dist/grammar/ast"; +/** + * Detects opportunities for simplifying code by eliminating redundant boolean expressions and statements. + * + * ## Why is it bad? + * Redundant code can make programs less efficient and harder to read. Simplifying such code improves readability, + * maintainability, and can prevent potential logical errors. + * + * **What it checks:** + * - `if` statements that return boolean literals directly based on a condition. + * - Comparisons of boolean expressions with boolean literals (`true` or `false`). + * - Conditional expressions (ternary operators) that return boolean literals. + * + * ## Example + * + * ```tact + * // Redundant 'if' statement: + * if (condition) { + * return true; + * } else { + * return false; + * } + * // Simplify to: + * return condition; + * + * // Redundant comparison: + * return a == true; + * // Simplify to: + * return a; + * + * // Redundant conditional expression: + * return b ? true : false; + * // Simplify to: + * return b; + * ``` + */ export class EtaLikeSimplifications extends ASTDetector { severity = Severity.LOW; async check(cu: CompilationUnit): Promise { - console.log("EtaLikeSimplifications detector is running"); const warnings: MistiTactWarning[] = []; - const entries = cu.ast.getProgramEntries(); - console.log("Number of program entries:", entries.length); - for (const node of entries) { this.analyzeNode(node, warnings); } - return warnings; } private analyzeNode(node: AstNode, warnings: MistiTactWarning[]): void { - console.log("Analyzing node:", node.kind); - forEachStatement(node, (stmt) => { - console.log("Statement kind:", stmt.kind); this.checkStatement(stmt, warnings); }); - forEachExpression(node, (expr) => { - console.log("Expression kind:", expr.kind); this.checkExpression(expr, warnings); }); } @@ -51,7 +74,6 @@ export class EtaLikeSimplifications extends ASTDetector { ): void { if (stmt.kind === "statement_condition") { const ifStmt = stmt; - if ( ifStmt.trueStatements.length === 1 && ifStmt.falseStatements && @@ -61,7 +83,6 @@ export class EtaLikeSimplifications extends ASTDetector { ) { const trueReturn = ifStmt.trueStatements[0] as AstStatementReturn; const falseReturn = ifStmt.falseStatements[0] as AstStatementReturn; - if ( this.isBooleanLiteral(trueReturn.expression, true) && this.isBooleanLiteral(falseReturn.expression, false) @@ -84,15 +105,14 @@ export class EtaLikeSimplifications extends ASTDetector { expr: AstExpression, warnings: MistiTactWarning[], ): void { - // Check for `boolean_expression == true` or `boolean_expression == false` if (expr.kind === "op_binary") { const binaryExpr = expr as AstOpBinary; if (binaryExpr.op === "==" || binaryExpr.op === "!=") { - const { left, right } = binaryExpr; + const { right } = binaryExpr; if (this.isBooleanLiteral(right)) { warnings.push( this.makeWarning( - `Redundant comparison with boolean literal`, + "Redundant comparison with boolean literal", expr.loc, { suggestion: `Use '${this.getSimplifiedBooleanExpression( @@ -104,8 +124,6 @@ export class EtaLikeSimplifications extends ASTDetector { } } } - - // Check for conditional expressions like `cond ? true : false` if (expr.kind === "conditional") { const conditionalExpr = expr as AstConditional; if ( @@ -117,7 +135,9 @@ export class EtaLikeSimplifications extends ASTDetector { "Simplify conditional expression by using the condition directly", expr.loc, { - suggestion: `Use '${this.getConditionText(conditionalExpr.condition)}' instead`, + suggestion: `Use '${this.getConditionText( + conditionalExpr.condition, + )}' instead`, }, ), ); diff --git a/src/detectors/detector.ts b/src/detectors/detector.ts index e764d252..2971cea9 100644 --- a/src/detectors/detector.ts +++ b/src/detectors/detector.ts @@ -390,7 +390,7 @@ export const BuiltInDetectors: Record = { import("./builtin/etaLikeSimplifications").then( (module) => new module.EtaLikeSimplifications(ctx), ), - enabledByDefault: false, + enabledByDefault: true, }, }; diff --git a/test/detectors/EtaLikeSimplifications.expected.out b/test/detectors/EtaLikeSimplifications.expected.out new file mode 100644 index 00000000..7b571509 --- /dev/null +++ b/test/detectors/EtaLikeSimplifications.expected.out @@ -0,0 +1,26 @@ +[LOW] EtaLikeSimplifications: Simplify 'if' statement by returning the condition directly +test/detectors/EtaLikeSimplifications.tact:4:9: + 3 | fun redundantIf(condition: Bool): Bool { +> 4 | if (condition) { + ^ + 5 | return true; +Help: Replace with 'return condition;' +See: https://nowarp.io/tools/misti/docs/detectors/EtaLikeSimplifications + +[LOW] EtaLikeSimplifications: Redundant comparison with boolean literal +test/detectors/EtaLikeSimplifications.tact:13:16: + 12 | fun redundantComparison(a: Bool): Bool { +> 13 | return a == true; + ^ + 14 | } +Help: Use 'a' instead +See: https://nowarp.io/tools/misti/docs/detectors/EtaLikeSimplifications + +[LOW] EtaLikeSimplifications: Simplify conditional expression by using the condition directly +test/detectors/EtaLikeSimplifications.tact:18:16: + 17 | fun redundantTernary(b: Bool): Bool { +> 18 | return b ? true : false; + ^ + 19 | } +Help: Use 'b' instead +See: https://nowarp.io/tools/misti/docs/detectors/EtaLikeSimplifications \ No newline at end of file diff --git a/test/detectors/EtaLikeSimplifications.tact b/test/detectors/EtaLikeSimplifications.tact index bdbc1093..6513e683 100644 --- a/test/detectors/EtaLikeSimplifications.tact +++ b/test/detectors/EtaLikeSimplifications.tact @@ -1,5 +1,5 @@ contract TestContract { - // Example of redundant if statement + // Bad: Example of redundant if statement fun redundantIf(condition: Bool): Bool { if (condition) { return true; @@ -8,17 +8,17 @@ contract TestContract { } } - // Example of redundant boolean comparison + // Bad: Example of redundant boolean comparison fun redundantComparison(a: Bool): Bool { return a == true; } - // Example of redundant ternary expression + // Bad: Example of redundant ternary expression fun redundantTernary(b: Bool): Bool { return b ? true : false; } - // Correct usage (should not trigger warnings) + // Ok: Correct usage (should not trigger warnings) fun correctUsage(condition: Bool): Bool { return condition; } From 28b0a2849e7cdc71b0b8c2f7afebae0708602845 Mon Sep 17 00:00:00 2001 From: Esorat Date: Thu, 24 Oct 2024 22:17:18 +0700 Subject: [PATCH 07/14] fix: delete dublicate --- src/detectors/detector.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/detectors/detector.ts b/src/detectors/detector.ts index f0ad2cda..2971cea9 100644 --- a/src/detectors/detector.ts +++ b/src/detectors/detector.ts @@ -385,13 +385,6 @@ export const BuiltInDetectors: Record = { ), enabledByDefault: true, }, - SuspiciousMessageMode: { - loader: (ctx: MistiContext) => - import("./builtin/suspiciousMessageMode").then( - (module) => new module.SuspiciousMessageMode(ctx), - ), - enabledByDefault: true, - }, EtaLikeSimplifications: { loader: (ctx: MistiContext) => import("./builtin/etaLikeSimplifications").then( From 167872863cf13aab4049b1d6a6f5c4de142bc5bc Mon Sep 17 00:00:00 2001 From: Esorat Date: Fri, 25 Oct 2024 13:55:03 +0700 Subject: [PATCH 08/14] fix: remove dublicate --- src/cli/options.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cli/options.ts b/src/cli/options.ts index f7adf3ef..a982c77d 100644 --- a/src/cli/options.ts +++ b/src/cli/options.ts @@ -72,9 +72,6 @@ export const cliOptions = [ new Option("--list-tools", "List available tools and their options.").default( cliOptionDefaults.listTools, ), - new Option("--list-detectors", "List available detectors.").default( - cliOptionDefaults.listDetectors, - ), new Option( "-o, --output-format ", "Set the output format for all tools and warnings", From b4a8dbcb060a3edbcf20866a51a588e07d9aa29c Mon Sep 17 00:00:00 2001 From: Esorat Date: Fri, 25 Oct 2024 13:57:22 +0700 Subject: [PATCH 09/14] chore: Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfa1904..ae18b7e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- `EtaLikeSimplifications` detector: PR [#198](https://github.com/nowarp/misti/pull/198) - `SuspiciousMessageMode` detector: PR [#193](https://github.com/nowarp/misti/pull/193) - `SendInLoop` detector: PR [#168](https://github.com/nowarp/misti/pull/168) - `CellOverflow` detector: PR [#177](https://github.com/nowarp/misti/pull/177) From 801086e4e061b575a445884bfa0a01f8035810f0 Mon Sep 17 00:00:00 2001 From: Esorat Date: Fri, 25 Oct 2024 14:17:36 +0700 Subject: [PATCH 10/14] Fix: Added mode: 0 detection in SuspiciousMessageMode detector - Implemented a check for mode: 0 in the `SuspiciousMessageMode.ts` to trigger warnings on redundant mode settings. - Updated test cases in `SuspiciousMessageMode.tact` to ensure mode: 0 is flagged as unnecessary. - Adjusted expected output in `SuspiciousMessageMode.expected` to reflect the new checks. --- src/detectors/builtin/suspiciousMessageMode.ts | 14 ++++++++++++++ test/detectors/SuspiciousMessageMode.expected.out | 9 +++++++++ test/detectors/SuspiciousMessageMode.tact | 8 ++++++++ 3 files changed, 31 insertions(+) diff --git a/src/detectors/builtin/suspiciousMessageMode.ts b/src/detectors/builtin/suspiciousMessageMode.ts index 7ed77e32..29919a01 100644 --- a/src/detectors/builtin/suspiciousMessageMode.ts +++ b/src/detectors/builtin/suspiciousMessageMode.ts @@ -72,6 +72,20 @@ export class SuspiciousMessageMode extends ASTDetector { expr: AstExpression, warnings: MistiTactWarning[], ): void { + if (expr.kind === "number" && expr.value === 0n) { + warnings.push( + this.makeWarning( + "Setting `mode` to `0` is redundant as it has no effect.", + expr.loc, + { + suggestion: + "Remove the `mode` field or set it to a meaningful value.", + }, + ), + ); + return; + } + const flagsUsed = new Set(); forEachExpression(expr, (e) => { switch (e.kind) { diff --git a/test/detectors/SuspiciousMessageMode.expected.out b/test/detectors/SuspiciousMessageMode.expected.out index 2f8a7ca5..4451694d 100644 --- a/test/detectors/SuspiciousMessageMode.expected.out +++ b/test/detectors/SuspiciousMessageMode.expected.out @@ -68,4 +68,13 @@ test/detectors/SuspiciousMessageMode.tact:61:21: ^ 62 | }); Help: Use the '|' operator (bitwise OR) to combine flags +See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode + +[MEDIUM] SuspiciousMessageMode: Setting `mode` to `0` is redundant as it has no effect. +test/detectors/SuspiciousMessageMode.tact:79:15: + 78 | value: 0, +> 79 | mode: 0 // Bad: Should trigger warning about `mode: 0` being redundant + ^ + 80 | }); +Help: Remove the `mode` field or set it to a meaningful value. See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode \ No newline at end of file diff --git a/test/detectors/SuspiciousMessageMode.tact b/test/detectors/SuspiciousMessageMode.tact index a6dc898b..836c2e70 100644 --- a/test/detectors/SuspiciousMessageMode.tact +++ b/test/detectors/SuspiciousMessageMode.tact @@ -71,4 +71,12 @@ contract SendParametersTestContract { mode: modeFlag // Ok }); } + + fun modeZeroUsage() { + send(SendParameters{ + to: sender(), + value: 0, + mode: 0 // Bad: Should trigger warning about `mode: 0` being redundant + }); +} } From dc03d48e1e424b026e67f4c0db21dfd385f0b038 Mon Sep 17 00:00:00 2001 From: Esorat Date: Fri, 25 Oct 2024 16:43:11 +0700 Subject: [PATCH 11/14] fix: remove irrelevant changes --- CHANGELOG.md | 1 - .../builtin/etaLikeSimplifications.ts | 192 ------------------ src/detectors/detector.ts | 7 - .../EtaLikeSimplifications.expected.out | 26 --- test/detectors/EtaLikeSimplifications.tact | 25 --- 5 files changed, 251 deletions(-) delete mode 100644 src/detectors/builtin/etaLikeSimplifications.ts delete mode 100644 test/detectors/EtaLikeSimplifications.expected.out delete mode 100644 test/detectors/EtaLikeSimplifications.tact diff --git a/CHANGELOG.md b/CHANGELOG.md index ae18b7e4..9bfa1904 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- `EtaLikeSimplifications` detector: PR [#198](https://github.com/nowarp/misti/pull/198) - `SuspiciousMessageMode` detector: PR [#193](https://github.com/nowarp/misti/pull/193) - `SendInLoop` detector: PR [#168](https://github.com/nowarp/misti/pull/168) - `CellOverflow` detector: PR [#177](https://github.com/nowarp/misti/pull/177) diff --git a/src/detectors/builtin/etaLikeSimplifications.ts b/src/detectors/builtin/etaLikeSimplifications.ts deleted file mode 100644 index 1f0adeca..00000000 --- a/src/detectors/builtin/etaLikeSimplifications.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { CompilationUnit } from "../../internals/ir"; -import { forEachStatement, forEachExpression } from "../../internals/tact"; -import { MistiTactWarning, Severity } from "../../internals/warnings"; -import { ASTDetector } from "../detector"; -import { - AstNode, - AstStatement, - AstExpression, - AstOpBinary, - idText, - AstStatementReturn, - AstConditional, -} from "@tact-lang/compiler/dist/grammar/ast"; - -/** - * Detects opportunities for simplifying code by eliminating redundant boolean expressions and statements. - * - * ## Why is it bad? - * Redundant code can make programs less efficient and harder to read. Simplifying such code improves readability, - * maintainability, and can prevent potential logical errors. - * - * **What it checks:** - * - `if` statements that return boolean literals directly based on a condition. - * - Comparisons of boolean expressions with boolean literals (`true` or `false`). - * - Conditional expressions (ternary operators) that return boolean literals. - * - * ## Example - * - * ```tact - * // Redundant 'if' statement: - * if (condition) { - * return true; - * } else { - * return false; - * } - * // Simplify to: - * return condition; - * - * // Redundant comparison: - * return a == true; - * // Simplify to: - * return a; - * - * // Redundant conditional expression: - * return b ? true : false; - * // Simplify to: - * return b; - * ``` - */ -export class EtaLikeSimplifications extends ASTDetector { - severity = Severity.LOW; - - async check(cu: CompilationUnit): Promise { - const warnings: MistiTactWarning[] = []; - const entries = cu.ast.getProgramEntries(); - for (const node of entries) { - this.analyzeNode(node, warnings); - } - return warnings; - } - - private analyzeNode(node: AstNode, warnings: MistiTactWarning[]): void { - forEachStatement(node, (stmt) => { - this.checkStatement(stmt, warnings); - }); - forEachExpression(node, (expr) => { - this.checkExpression(expr, warnings); - }); - } - - private checkStatement( - stmt: AstStatement, - warnings: MistiTactWarning[], - ): void { - if (stmt.kind === "statement_condition") { - const ifStmt = stmt; - if ( - ifStmt.trueStatements.length === 1 && - ifStmt.falseStatements && - ifStmt.falseStatements.length === 1 && - ifStmt.trueStatements[0].kind === "statement_return" && - ifStmt.falseStatements[0].kind === "statement_return" - ) { - const trueReturn = ifStmt.trueStatements[0] as AstStatementReturn; - const falseReturn = ifStmt.falseStatements[0] as AstStatementReturn; - if ( - this.isBooleanLiteral(trueReturn.expression, true) && - this.isBooleanLiteral(falseReturn.expression, false) - ) { - warnings.push( - this.makeWarning( - "Simplify 'if' statement by returning the condition directly", - stmt.loc, - { - suggestion: "Replace with 'return condition;'", - }, - ), - ); - } - } - } - } - - private checkExpression( - expr: AstExpression, - warnings: MistiTactWarning[], - ): void { - if (expr.kind === "op_binary") { - const binaryExpr = expr as AstOpBinary; - if (binaryExpr.op === "==" || binaryExpr.op === "!=") { - const { right } = binaryExpr; - if (this.isBooleanLiteral(right)) { - warnings.push( - this.makeWarning( - "Redundant comparison with boolean literal", - expr.loc, - { - suggestion: `Use '${this.getSimplifiedBooleanExpression( - binaryExpr, - )}' instead`, - }, - ), - ); - } - } - } - if (expr.kind === "conditional") { - const conditionalExpr = expr as AstConditional; - if ( - this.isBooleanLiteral(conditionalExpr.thenBranch, true) && - this.isBooleanLiteral(conditionalExpr.elseBranch, false) - ) { - warnings.push( - this.makeWarning( - "Simplify conditional expression by using the condition directly", - expr.loc, - { - suggestion: `Use '${this.getConditionText( - conditionalExpr.condition, - )}' instead`, - }, - ), - ); - } - } - } - - private isBooleanLiteral( - expr: AstExpression | null | undefined, - value?: boolean, - ): boolean { - if (!expr) return false; - if (expr.kind === "boolean") { - if (value === undefined) { - return true; - } - return expr.value === value; - } - return false; - } - - private getSimplifiedBooleanExpression(binaryExpr: AstOpBinary): string { - const exprText = (expr: AstExpression): string => { - if (expr.kind === "id") { - return idText(expr); - } - return "expression"; - }; - - if (this.isBooleanLiteral(binaryExpr.right, true)) { - if (binaryExpr.op === "==") { - return exprText(binaryExpr.left); - } else { - return `!${exprText(binaryExpr.left)}`; - } - } else if (this.isBooleanLiteral(binaryExpr.right, false)) { - if (binaryExpr.op === "==") { - return `!${exprText(binaryExpr.left)}`; - } else { - return exprText(binaryExpr.left); - } - } - return "expression"; - } - - private getConditionText(expr: AstExpression): string { - if (expr.kind === "id") { - return idText(expr); - } - return "condition"; - } -} diff --git a/src/detectors/detector.ts b/src/detectors/detector.ts index 2971cea9..2fe575eb 100644 --- a/src/detectors/detector.ts +++ b/src/detectors/detector.ts @@ -385,13 +385,6 @@ export const BuiltInDetectors: Record = { ), enabledByDefault: true, }, - EtaLikeSimplifications: { - loader: (ctx: MistiContext) => - import("./builtin/etaLikeSimplifications").then( - (module) => new module.EtaLikeSimplifications(ctx), - ), - enabledByDefault: true, - }, }; /** diff --git a/test/detectors/EtaLikeSimplifications.expected.out b/test/detectors/EtaLikeSimplifications.expected.out deleted file mode 100644 index 7b571509..00000000 --- a/test/detectors/EtaLikeSimplifications.expected.out +++ /dev/null @@ -1,26 +0,0 @@ -[LOW] EtaLikeSimplifications: Simplify 'if' statement by returning the condition directly -test/detectors/EtaLikeSimplifications.tact:4:9: - 3 | fun redundantIf(condition: Bool): Bool { -> 4 | if (condition) { - ^ - 5 | return true; -Help: Replace with 'return condition;' -See: https://nowarp.io/tools/misti/docs/detectors/EtaLikeSimplifications - -[LOW] EtaLikeSimplifications: Redundant comparison with boolean literal -test/detectors/EtaLikeSimplifications.tact:13:16: - 12 | fun redundantComparison(a: Bool): Bool { -> 13 | return a == true; - ^ - 14 | } -Help: Use 'a' instead -See: https://nowarp.io/tools/misti/docs/detectors/EtaLikeSimplifications - -[LOW] EtaLikeSimplifications: Simplify conditional expression by using the condition directly -test/detectors/EtaLikeSimplifications.tact:18:16: - 17 | fun redundantTernary(b: Bool): Bool { -> 18 | return b ? true : false; - ^ - 19 | } -Help: Use 'b' instead -See: https://nowarp.io/tools/misti/docs/detectors/EtaLikeSimplifications \ No newline at end of file diff --git a/test/detectors/EtaLikeSimplifications.tact b/test/detectors/EtaLikeSimplifications.tact deleted file mode 100644 index 6513e683..00000000 --- a/test/detectors/EtaLikeSimplifications.tact +++ /dev/null @@ -1,25 +0,0 @@ -contract TestContract { - // Bad: Example of redundant if statement - fun redundantIf(condition: Bool): Bool { - if (condition) { - return true; - } else { - return false; - } - } - - // Bad: Example of redundant boolean comparison - fun redundantComparison(a: Bool): Bool { - return a == true; - } - - // Bad: Example of redundant ternary expression - fun redundantTernary(b: Bool): Bool { - return b ? true : false; - } - - // Ok: Correct usage (should not trigger warnings) - fun correctUsage(condition: Bool): Bool { - return condition; - } -} From a525155a1af75eece2f44724b3fe590f1cdac6e5 Mon Sep 17 00:00:00 2001 From: Esorat Date: Sat, 2 Nov 2024 18:03:42 +0700 Subject: [PATCH 12/14] fix: update suggestion --- src/detectors/builtin/suspiciousMessageMode.ts | 2 +- test/detectors/SuspiciousMessageMode.expected.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detectors/builtin/suspiciousMessageMode.ts b/src/detectors/builtin/suspiciousMessageMode.ts index c5e47eea..05b7c06b 100644 --- a/src/detectors/builtin/suspiciousMessageMode.ts +++ b/src/detectors/builtin/suspiciousMessageMode.ts @@ -79,7 +79,7 @@ export class SuspiciousMessageMode extends ASTDetector { expr.loc, { suggestion: - "Remove the `mode` field or set it to a meaningful value.", + "Remove the `mode` field or set it to `SendDefaultMode`.", }, ), ); diff --git a/test/detectors/SuspiciousMessageMode.expected.out b/test/detectors/SuspiciousMessageMode.expected.out index 6f105956..ec311b5c 100644 --- a/test/detectors/SuspiciousMessageMode.expected.out +++ b/test/detectors/SuspiciousMessageMode.expected.out @@ -76,5 +76,5 @@ test/detectors/SuspiciousMessageMode.tact:79:15: > 79 | mode: 0 // Bad: Should trigger warning about `mode: 0` being redundant ^ 80 | }); -Help: Remove the `mode` field or set it to a meaningful value. +Help: Remove the `mode` field or set it to `SendDefaultMode`. See: https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageMode \ No newline at end of file From 8e98af2f4dd00b3358a17271d40fe390dd6da4c8 Mon Sep 17 00:00:00 2001 From: Esorat Date: Sat, 2 Nov 2024 19:14:22 +0700 Subject: [PATCH 13/14] Chore: Update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af4d05f..d5ce1beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `ShortCircuitCondition` detector: PR [#202](https://github.com/nowarp/misti/pull/202) - +### Changed +- `SuspiciousMessageMode` detector now suggests using SendDefaultMode instead of 0 for mode: PR [#199](https://github.com/nowarp/misti/pull/199/) ## [0.5.0] - 2024-10-31 ### Added From e389a260bb09a76a87c1bd1915efeb585fa6b3f0 Mon Sep 17 00:00:00 2001 From: Georgiy Komarov Date: Sat, 2 Nov 2024 08:17:46 -0400 Subject: [PATCH 14/14] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5ce1beb..1eb6381f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ShortCircuitCondition` detector: PR [#202](https://github.com/nowarp/misti/pull/202) ### Changed - `SuspiciousMessageMode` detector now suggests using SendDefaultMode instead of 0 for mode: PR [#199](https://github.com/nowarp/misti/pull/199/) + ## [0.5.0] - 2024-10-31 ### Added