From ac276644e3d8ed6d650c05225583e5e9cb4aaf1e Mon Sep 17 00:00:00 2001 From: Raif Mirza Erten Date: Fri, 22 Aug 2025 11:13:48 +0300 Subject: [PATCH] arkts-no-ts-like-smart-type for loop fix Description: fix missed case for "for loop" Issue: ICU9UE Signed-off-by: Raif Mirza Erten --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 86 ++++++++++----- .../test/main/no_ts_like_smart_type.ets | 62 ++++++++++- .../no_ts_like_smart_type.ets.arkts2.json | 44 +++++--- .../test/main/no_ts_like_smart_type.ets.json | 104 +++++++++++++++--- 4 files changed, 240 insertions(+), 56 deletions(-) mode change 100755 => 100644 ets2panda/linter/test/main/no_ts_like_smart_type.ets.arkts2.json mode change 100755 => 100644 ets2panda/linter/test/main/no_ts_like_smart_type.ets.json diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index c4edcff3b3..cd882dff73 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -2018,40 +2018,38 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleNoDeprecatedApi(node); if (!this.options.arkts2) { - this.handleLiteralAsPropertyNameForPropertyAssignment(node); - } + this.handleLiteralAsPropertyNameForPropertyAssignment(node); + } } private handleLiteralAsPropertyNameForPropertyAssignment(node: ts.PropertyAssignment): void { - const propName = node.name; - if (!propName || !(ts.isNumericLiteral(propName) || ts.isStringLiteral(propName))) { - return; - } - - /* - * We can use literals as property names only when creating Record or any interop instances. - * We can also initialize with constant string literals. - * Assignment with string enum values is handled in handleComputedPropertyName - */ - let isRecordObjectInitializer = false; - let isLibraryType = false; - let isDynamic = false; - const objectLiteralType = this.tsTypeChecker.getContextualType(node.parent); + const propName = node.name; + if (!propName || !(ts.isNumericLiteral(propName) || ts.isStringLiteral(propName))) { + return; + } - if (objectLiteralType) { - isRecordObjectInitializer = this.tsUtils.checkTypeSet(objectLiteralType, this.tsUtils.isStdRecordType); - isLibraryType = this.tsUtils.isLibraryType(objectLiteralType); + /* + * We can use literals as property names only when creating Record or any interop instances. + * We can also initialize with constant string literals. + * Assignment with string enum values is handled in handleComputedPropertyName + */ + let isRecordObjectInitializer = false; + let isLibraryType = false; + let isDynamic = false; + const objectLiteralType = this.tsTypeChecker.getContextualType(node.parent); - } + if (objectLiteralType) { + isRecordObjectInitializer = this.tsUtils.checkTypeSet(objectLiteralType, this.tsUtils.isStdRecordType); + isLibraryType = this.tsUtils.isLibraryType(objectLiteralType); + } - isDynamic = isLibraryType || this.tsUtils.isDynamicLiteralInitializer(node.parent); + isDynamic = isLibraryType || this.tsUtils.isDynamicLiteralInitializer(node.parent); - if (!isRecordObjectInitializer && !isDynamic) { - const autofix = this.autofixer?.fixLiteralAsPropertyNamePropertyAssignment(node); - this.incrementCounters(node.name, FaultID.LiteralAsPropertyName, autofix); + if (!isRecordObjectInitializer && !isDynamic) { + const autofix = this.autofixer?.fixLiteralAsPropertyNamePropertyAssignment(node); + this.incrementCounters(node.name, FaultID.LiteralAsPropertyName, autofix); + } } -} - private static getAllClassesFromSourceFile(sourceFile: ts.SourceFile): ts.ClassDeclaration[] { const allClasses: ts.ClassDeclaration[] = []; @@ -12457,6 +12455,14 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!this.options.arkts2) { return; } + + if (TypeScriptLinter.isInForLoopBody(tsAsExpr)) { + const identifier = TypeScriptLinter.getIdentifierFromAsExpression(tsAsExpr); + if (identifier && this.isDeclaredOutsideForLoop(identifier)) { + return; + } + } + const asType = this.tsTypeChecker.getTypeAtLocation(tsAsExpr.type); const originType = this.tsTypeChecker.getTypeAtLocation(tsAsExpr.expression); const originTypeStr = this.tsTypeChecker.typeToString(originType); @@ -12465,6 +12471,34 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } + private isDeclaredOutsideForLoop(identifier: ts.Identifier): boolean { + const symbol = this.tsTypeChecker.getSymbolAtLocation(identifier); + if (!symbol) { + return false; + } + + const declarations = symbol.declarations ?? []; + for (const decl of declarations) { + if (ts.findAncestor(decl, ts.isForStatement)) { + return false; + } + } + + return true; + } + + private static getIdentifierFromAsExpression(asExpr: ts.AsExpression): ts.Identifier | undefined { + const expr = asExpr.expression; + if (ts.isIdentifier(expr)) { + // case: data as Type + return expr; + } else if (ts.isElementAccessExpression(expr) && ts.isIdentifier(expr.expression)) { + // case: data[i] as Type + return expr.expression; + } + return undefined; + } + private handleAssignmentNotsLikeSmartType(tsBinaryExpr: ts.BinaryExpression): void { if (!this.options.arkts2) { return; diff --git a/ets2panda/linter/test/main/no_ts_like_smart_type.ets b/ets2panda/linter/test/main/no_ts_like_smart_type.ets index 8a353aff28..d7b51db205 100755 --- a/ets2panda/linter/test/main/no_ts_like_smart_type.ets +++ b/ets2panda/linter/test/main/no_ts_like_smart_type.ets @@ -249,7 +249,7 @@ export class AB { return this.count_; //legal }) } -} +} class AG { h?: number; @@ -306,4 +306,62 @@ if (obj && obj.h == 3) { // valid(guarded) function check43(obj?: AG) { const val = obj.h; // NOT guarded return val; -} \ No newline at end of file +} + +} + +let NextID: number = 1; + +class downloadFilesData { + id: number; + url: string; + fileStatus: number; + downloadTime: number; + + constructor( + url: string = '', + fileStatus: number = 0, + downloadTime: number = 0, + ) { + this.id = NextID++; + this.url = url; + this.fileStatus = fileStatus; + this.downloadTime = downloadTime; + } +} + +class Downloader { + downloadFileArray: downloadFilesData[] = []; + + loadInitializationDataSource() { + let stringData = JSON.stringify([ + { + "url": "https://example.com/file1.zip", + "fileStatus": 1, + "downloadTime": 1734931200 + }, + { + "url": "https://example.com/file2.mp4", + "fileStatus": 0, + "downloadTime": 0 + }, + { + "url": "https://example.com/file3.pdf", + "fileStatus": 2, + "downloadTime": 1734931300 + } + ]); + + let data: [] = JSON.parse(stringData) as []; + + for (let i = 0; i < data.length; i++) { + const downloadItemData = data[i] as downloadFilesData; + let downloadData: downloadFilesData = new downloadFilesData( + downloadItemData.url, + downloadItemData.fileStatus, + downloadItemData.downloadTime + ); + this.downloadFileArray.push(downloadData); + } + } +} diff --git a/ets2panda/linter/test/main/no_ts_like_smart_type.ets.arkts2.json b/ets2panda/linter/test/main/no_ts_like_smart_type.ets.arkts2.json old mode 100755 new mode 100644 index d5577d300c..14bb6037da --- a/ets2panda/linter/test/main/no_ts_like_smart_type.ets.arkts2.json +++ b/ets2panda/linter/test/main/no_ts_like_smart_type.ets.arkts2.json @@ -1,18 +1,4 @@ { - "copyright": [ - "Copyright (c) 2025 Huawei Device Co., Ltd.", - "Licensed under the Apache License, Version 2.0 (the 'License');", - "you may not use this file except in compliance with the License.", - "You may obtain a copy of the License at", - "", - "http://www.apache.org/licenses/LICENSE-2.0", - "", - "Unless required by applicable law or agreed to in writing, software", - "distributed under the License is distributed on an 'AS IS' BASIS,", - "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", - "See the License for the specific language governing permissions and", - "limitations under the License." - ], "result": [ { "line": 30, @@ -294,6 +280,36 @@ "rule": "Smart type differences (arkts-no-ts-like-smart-type)", "severity": "ERROR" }, + { + "line": 337, + "column": 27, + "endLine": 337, + "endColumn": 36, + "problem": "SdkCommonApiWhiteList", + "suggest": "", + "rule": "The \"stringify\" in SDK is no longer supported.(sdk-method-not-supported)", + "severity": "ERROR" + }, + { + "line": 337, + "column": 27, + "endLine": 337, + "endColumn": 36, + "problem": "BuiltinNarrowTypes", + "suggest": "", + "rule": "Using narrowing of types is not allowed in this API (arkts-builtin-narrow-types)", + "severity": "ERROR" + }, + { + "line": 357, + "column": 25, + "endLine": 357, + "endColumn": 36, + "problem": "NoTuplesArrays", + "suggest": "", + "rule": "Array and tuple are different type(arkts-no-tuples-arrays)", + "severity": "ERROR" + }, { "line": 137, "column": 5, diff --git a/ets2panda/linter/test/main/no_ts_like_smart_type.ets.json b/ets2panda/linter/test/main/no_ts_like_smart_type.ets.json old mode 100755 new mode 100644 index f892c8a98b..1956437aee --- a/ets2panda/linter/test/main/no_ts_like_smart_type.ets.json +++ b/ets2panda/linter/test/main/no_ts_like_smart_type.ets.json @@ -1,19 +1,95 @@ { - "copyright": [ - "Copyright (c) 2025 Huawei Device Co., Ltd.", - "Licensed under the Apache License, Version 2.0 (the 'License');", - "you may not use this file except in compliance with the License.", - "You may obtain a copy of the License at", - "", - "http://www.apache.org/licenses/LICENSE-2.0", - "", - "Unless required by applicable law or agreed to in writing, software", - "distributed under the License is distributed on an 'AS IS' BASIS,", - "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", - "See the License for the specific language governing permissions and", - "limitations under the License." - ], "result": [ + { + "line": 339, + "column": 9, + "endLine": 339, + "endColumn": 14, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 340, + "column": 9, + "endLine": 340, + "endColumn": 21, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 341, + "column": 9, + "endLine": 341, + "endColumn": 23, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 344, + "column": 9, + "endLine": 344, + "endColumn": 14, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 345, + "column": 9, + "endLine": 345, + "endColumn": 21, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 346, + "column": 9, + "endLine": 346, + "endColumn": 23, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 349, + "column": 9, + "endLine": 349, + "endColumn": 14, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 350, + "column": 9, + "endLine": 350, + "endColumn": 21, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, + { + "line": 351, + "column": 9, + "endLine": 351, + "endColumn": 23, + "problem": "LiteralAsPropertyName", + "suggest": "", + "rule": "Objects with property names that are not identifiers are not supported (arkts-identifiers-as-prop-names)", + "severity": "ERROR" + }, { "line": 137, "column": 5, -- Gitee