From 5090679c767855484744bb7879758d471029c633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E6=9F=A0?= Date: Thu, 3 Jul 2025 16:26:03 +0800 Subject: [PATCH] fix issue for arkts-runtime-array-check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICJQCA Test scenarios: arkts-runtime-array-check Signed-off-by: 钟柠 --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 100 +++++++++++++++++- .../linter/test/main/runtime_array_bound.ets | 16 ++- .../main/runtime_array_bound.ets.arkts2.json | 70 ++++++++++++ .../main/runtime_array_bound.ets.migrate.ets | 16 ++- .../main/runtime_array_bound.ets.migrate.json | 20 ++++ 5 files changed, 219 insertions(+), 3 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 70ab7059c24..f55388cfac5 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -10214,7 +10214,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if ( this.isInMaxLengthControlledLoop(accessExpr) || TypeScriptLinter.hasDefaultValueProtection(accessExpr) || - this.isInLengthCheckedBlock(accessExpr) + this.isInLengthCheckedBlock(accessExpr) || + this.isInStandardLengthControlledLoop(accessExpr) ) { return true; } @@ -11108,4 +11109,101 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return false; } + + private isInStandardLengthControlledLoop(accessExpr: ts.ElementAccessExpression): boolean { + const arrayAccessInfo = this.getArrayAccessInfo(accessExpr); + if (!arrayAccessInfo) { + return false; + } + let parent: ts.Node | undefined = accessExpr; + while (parent && !ts.isForStatement(parent)) { + parent = parent.parent; + } + if (!parent) { + return false + }; + + const forStmt = parent; + + if (!forStmt.condition || !ts.isBinaryExpression(forStmt.condition)) { + return false; + } + + const condition = forStmt.condition; + const isStandardLoop = ( + (condition.operatorToken.kind === ts.SyntaxKind.LessThanToken || + condition.operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken) && + ts.isPropertyAccessExpression(condition.right) && + condition.right.name.text === LENGTH_IDENTIFIER + ); + + if (!isStandardLoop) { + return false; + } + + return !this.hasDangerousArrayOperationsInForLoop(forStmt, arrayAccessInfo.arrayIdent.text); + } + + private hasDangerousArrayOperationsInForLoop(forStmt: ts.ForStatement, arrayName: string): boolean { + if (this.checkArrayModifications(forStmt.statement, arrayName)) { + return true; + } + + if (forStmt.initializer && ts.isVariableDeclarationList(forStmt.initializer)) { + const indexVar = forStmt.initializer.declarations[0]?.name.getText(); + if (indexVar && this.checkIndexModifications(forStmt.statement, indexVar)) { + return true; + } + } + + if (this.checkOutOfBoundAccess(forStmt.statement, arrayName)) { + return true; + } + + return false; + } + private checkArrayModifications(node: ts.Node, arrayName: string): boolean { + let hasModification = false; + ts.forEachChild(node, child => { + if (TypeScriptLinter.isArrayModification(child, arrayName)) { + hasModification = true; + } + if (!hasModification) { + hasModification = this.checkArrayModifications(child, arrayName); + } + }); + return hasModification; + } + + private checkIndexModifications(node: ts.Node, indexVar: string): boolean { + let hasModification = false; + ts.forEachChild(node, child => { + if (ts.isBinaryExpression(child) && + child.operatorToken.kind === ts.SyntaxKind.EqualsToken && + ts.isIdentifier(child.left) && + child.left.text === indexVar) { + hasModification = true; + } + if (!hasModification) { + hasModification = this.checkIndexModifications(child, indexVar); + } + }); + return hasModification; + } + + private checkOutOfBoundAccess(node: ts.Node, arrayName: string): boolean { + let hasOutOfBound = false; + ts.forEachChild(node, child => { + if (ts.isElementAccessExpression(child) && + ts.isIdentifier(child.expression) && + child.expression.text === arrayName && + ts.isNumericLiteral(child.argumentExpression)) { + hasOutOfBound = true; + } + if (!hasOutOfBound) { + hasOutOfBound = this.checkOutOfBoundAccess(child, arrayName); + } + }); + return hasOutOfBound; + } } diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets b/ets2panda/linter/test/main/runtime_array_bound.ets index 94234312eb3..934e9df563e 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets +++ b/ets2panda/linter/test/main/runtime_array_bound.ets @@ -280,4 +280,18 @@ function test7(config: Record, name: string) { function getValue(): string { return ''; -} \ No newline at end of file +} + +const arr: Record = {}; +let keys: string[] = Object.keys(arr); +let values: string[] = Object.values(arr); +for (let i = 0; i < keys.length; i++) { + values[i]; +} + +const arr: Map = new Map(); +let keys: string[] = Object.keys(arr); +let values: string[] = Object.values(arr); +for (let i = 0; i < keys.length; i++) { + values[i]; +} diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json b/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json index 801d14b2604..1c6c7709e36 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json @@ -2433,6 +2433,76 @@ "suggest": "", "rule": "Indexed access is not supported for fields (arkts-no-props-by-index)", "severity": "ERROR" + }, + { + "line": 287, + "column": 5, + "endLine": 287, + "endColumn": 42, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" + }, + { + "line": 288, + "column": 10, + "endLine": 288, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 288, + "column": 14, + "endLine": 288, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 292, + "column": 34, + "endLine": 292, + "endColumn": 43, + "problem": "GenericCallNoTypeArgs", + "suggest": "", + "rule": "Type inference in case of generic function calls is limited (arkts-no-inferred-generic-params)", + "severity": "ERROR" + }, + { + "line": 294, + "column": 5, + "endLine": 294, + "endColumn": 42, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" + }, + { + "line": 295, + "column": 10, + "endLine": 295, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 295, + "column": 14, + "endLine": 295, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" } ] } \ No newline at end of file diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets index 62220b36c26..2dbaad2e11b 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets @@ -280,4 +280,18 @@ function test7(config: Record, name: string) { function getValue(): string { return ''; -} \ No newline at end of file +} + +const arr: Record = {}; +let keys: string[] = Object.keys(arr); +let values: string[] = Object.values(arr); +for (let i: number = 0.0; i < keys.length; i++) { + values[i as int]; +} + +const arr: Map = new Map(); +let keys: string[] = Object.keys(arr); +let values: string[] = Object.values(arr); +for (let i: number = 0.0; i < keys.length; i++) { + values[i as int]; +} diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json index 7862ff0a076..c9862ab6cde 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json @@ -193,6 +193,26 @@ "suggest": "", "rule": "Indexed access is not supported for fields (arkts-no-props-by-index)", "severity": "ERROR" + }, + { + "line": 287, + "column": 5, + "endLine": 287, + "endColumn": 42, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" + }, + { + "line": 294, + "column": 5, + "endLine": 294, + "endColumn": 42, + "problem": "ArrayTypeImmutable", + "suggest": "", + "rule": "Array type is immutable in ArkTS1.2 (arkts-array-type-immutable)", + "severity": "ERROR" } ] } -- Gitee