From e7c78639db871f1c264ca70c9d4dfe715203d77a Mon Sep 17 00:00:00 2001 From: sefayilmazunal Date: Thu, 31 Jul 2025 13:29:57 +0300 Subject: [PATCH 1/5] arkts-concurrent-deprecated-apis impl Description: arkts-concurrent-deprecated-apis rule implemented Issue: ICNZN3 Signed-off-by: sefayilmazunal --- ets2panda/linter/rule-config.json | 1 + ets2panda/linter/src/lib/CookBookMsg.ts | 2 + ets2panda/linter/src/lib/FaultAttrs.ts | 1 + ets2panda/linter/src/lib/FaultDesc.ts | 1 + ets2panda/linter/src/lib/Problems.ts | 1 + ets2panda/linter/src/lib/TypeScriptLinter.ts | 50 ++++++----- .../src/lib/utils/consts/LimitedStdAPI.ts | 13 ++- .../concurrent_process_deprecated_apis.ets | 27 ++++++ ...rent_process_deprecated_apis.ets.args.json | 19 ++++ ...nt_process_deprecated_apis.ets.arkts2.json | 88 +++++++++++++++++++ ...oncurrent_process_deprecated_apis.ets.json | 17 ++++ .../test/main/oh_modules/@kit.ArkTS.d.ets | 3 +- .../test/main/oh_modules/@ohos.process.d.ets | 24 +++++ 13 files changed, 225 insertions(+), 22 deletions(-) create mode 100644 ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets create mode 100644 ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.args.json create mode 100644 ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json create mode 100644 ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.json create mode 100644 ets2panda/linter/test/main/oh_modules/@ohos.process.d.ets diff --git a/ets2panda/linter/rule-config.json b/ets2panda/linter/rule-config.json index 611a033828..346a6ee6fc 100644 --- a/ets2panda/linter/rule-config.json +++ b/ets2panda/linter/rule-config.json @@ -15,6 +15,7 @@ "arkts-limited-stdlib", "arkts-no-class-add-super-prop-with-readonly", "arkts-var-assignment-before-use", + "arkts-concurrent-deprecated-apis", "arkts-no-classes-as-obj", "arkts-obj-literal-props", "arkts-no-template-string-type", diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index f0b8e41253..54b797cf89 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -296,6 +296,8 @@ cookBookTag[269] = cookBookTag[270] = 'ArkTS1.2 cannot catch a non Error instance thrown from JS code (arkts-interop-js2s-js-exception)'; cookBookTag[271] = 'After a variable is declared, a value must be assigned before using it (arkts-var-assignment-before-use)'; +cookBookTag[272] = + 'This API of process is obsolete in ArkTS 1.1. It\'s no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)'; cookBookTag[274] = 'The subclass constructor must call the parent class\'s parametered constructor (arkts-subclass-must-call-super-constructor-with-args)'; cookBookTag[275] = diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 8ace468f16..197af41f90 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -202,6 +202,7 @@ faultsAttrs[FaultID.InteropJsObjectConditionJudgment] = new FaultAttributes(268) faultsAttrs[FaultID.InteropJsObjectExpandStaticInstance] = new FaultAttributes(269); faultsAttrs[FaultID.InteropJSFunctionInvoke] = new FaultAttributes(270); faultsAttrs[FaultID.VariableMissingInitializer] = new FaultAttributes(271); +faultsAttrs[FaultID.DeprecatedProcessApi] = new FaultAttributes(272); faultsAttrs[FaultID.MissingSuperCall] = new FaultAttributes(274); faultsAttrs[FaultID.CustomLayoutNeedAddDecorator] = new FaultAttributes(275); faultsAttrs[FaultID.InterfaceFieldNotImplemented] = new FaultAttributes(276); diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index d812eab323..011b01a034 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -170,6 +170,7 @@ faultDesc[FaultID.InteropJsObjectConditionJudgment] = 'Interop JS Object usage i faultDesc[FaultID.InteropJsObjectExpandStaticInstance] = 'Interop JS function usage'; faultDesc[FaultID.InteropJSFunctionInvoke] = 'Interop JS function invoke'; faultDesc[FaultID.VariableMissingInitializer] = 'Value must be assigned to variable'; +faultDesc[FaultID.DeprecatedProcessApi] = 'This process Api no longer supported in ArkTS 1.2'; faultDesc[FaultID.ExplicitFunctionType] = 'Not explicit function type'; faultDesc[FaultID.ClassstaticInitialization] = 'The static properties of a class need to have initial values'; faultDesc[FaultID.AvoidUnionTypes] = 'Union types'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index dd700b4ed5..1497b09c7e 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -190,6 +190,7 @@ export enum FaultID { InteropTSFunctionInvoke, InteropJSFunctionInvoke, VariableMissingInitializer, + DeprecatedProcessApi, LimitedVoidTypeFromSdk, EntryAnnotation, SdkAbilityLifecycleMonitor, diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index fb73dd0e1c..467c8a0c45 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -76,7 +76,9 @@ import { LIMITED_STD_REFLECT_API, MODULE_IMPORTS, ARKTSUTILS_MODULES, - ARKTSUTILS_LOCKS_MEMBER + ARKTSUTILS_LOCKS_MEMBER, + ARKTSUTILS_PROCESS_MEMBER, + PROCESS_DEPRECATED_INTERFACES } from './utils/consts/LimitedStdAPI'; import { SupportedStdCallApiChecker } from './utils/functions/SupportedStdCallAPI'; import { identiferUseInValueContext } from './utils/functions/identiferUseInValueContext'; @@ -8111,7 +8113,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { res = true; }; if (symbol) { - this.checkSymbolAndExecute(symbol, identifier.text, SYSTEM_MODULES, cb); + this.checkSymbolAndExecute(symbol, [identifier.text], SYSTEM_MODULES, cb); } return res; } @@ -8446,50 +8448,58 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.incrementCounters(node, FaultID.NoNeedStdlibWorker); }; - this.checkSymbolAndExecute(symbol, WORKER_TEXT, WORKER_MODULES, cb); + this.checkSymbolAndExecute(symbol, [WORKER_TEXT], WORKER_MODULES, cb); } private checkConcurrencySymbol(symbol: ts.Symbol, node: ts.Node): void { const cb = (): void => { const parent = node.parent; + if (!ts.isPropertyAccessExpression(parent)) { return; } + if (parent.name.text === ARKTSUTILS_LOCKS_MEMBER) { const autofix = this.autofixer?.fixConcurrencyLock(parent); this.incrementCounters(node, FaultID.LimitedStdLibNoImportConcurrency, autofix); } + + if (PROCESS_DEPRECATED_INTERFACES.includes(parent.name.text)) { + this.incrementCounters(node, FaultID.DeprecatedProcessApi); + } }; - this.checkSymbolAndExecute(symbol, ARKTSUTILS_LOCKS_MEMBER, ARKTSUTILS_MODULES, cb); + this.checkSymbolAndExecute(symbol, [ARKTSUTILS_LOCKS_MEMBER, ARKTSUTILS_PROCESS_MEMBER], ARKTSUTILS_MODULES, cb); } - private checkSymbolAndExecute(symbol: ts.Symbol, symbolName: string, modules: string[], cb: () => void): void { + private checkSymbolAndExecute(symbol: ts.Symbol, symbolNames: string[], modules: string[], cb: () => void): void { void this; - if (symbol.name === symbolName) { - const decl = TsUtils.getDeclaration(symbol); - if (!decl) { - cb(); - return; - } + // Only execute if the provided list contains the symbol’s actual name + if (!symbolNames.includes(symbol.name)) { + return; + } - const fileName = TypeScriptLinter.getFileName(decl); + const decl = TsUtils.getDeclaration(symbol); + if (!decl) { + cb(); + return; + } - if ( - modules.some((moduleName) => { - return fileName.startsWith(moduleName); - }) - ) { - cb(); - } + const fileName = TypeScriptLinter.getFileName(decl); + if ( + modules.some((moduleName) => { + return fileName.startsWith(moduleName); + }) + ) { + cb(); } } private checkNodeForUsage(node: ts.Node, symbolName: string, modules: string[], cb: () => void): void { const symbol = this.tsUtils.trueSymbolAtLocation(node); if (symbol) { - this.checkSymbolAndExecute(symbol, symbolName, modules, cb); + this.checkSymbolAndExecute(symbol, [symbolName], modules, cb); return; } diff --git a/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts b/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts index 3149a493a1..5051185d47 100644 --- a/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts +++ b/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts @@ -160,5 +160,16 @@ export const MODULE_IMPORTS: Record = { '@arkts.collections': ['collections'] }; -export const ARKTSUTILS_MODULES = ['@arkts.utils', '@kit.ArkTS']; +export const ARKTSUTILS_MODULES = ['@arkts.utils', '@ohos.process', '@kit.ArkTS']; export const ARKTSUTILS_LOCKS_MEMBER = 'locks'; +export const ARKTSUTILS_PROCESS_MEMBER = 'process'; + +export const PROCESS_DEPRECATED_INTERFACES = [ + 'isAppUid', + 'getUidForName', + 'getThreadPriority', + 'getSystemConfig', + 'getEnvironmentVar', + 'exit', + 'kill' +]; diff --git a/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets new file mode 100644 index 0000000000..c743b39bc2 --- /dev/null +++ b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets @@ -0,0 +1,27 @@ +/* + * 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. + */ + +import { process } from '../main/oh_modules/@kit.ArkTS'; + +// Deprecated APIs +process.isAppUid(12.0); // error +process.getUidForName('root'); // error +process.getThreadPriority(1.0); // error +process.getSystemConfig(1.0); // error +process.getEnvironmentVar('PATH'); // error +process.exit(0.0); // error +process.kill(6.0, 1.0); // error + +process.anyOtherMethod() // ok diff --git a/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.args.json b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.args.json new file mode 100644 index 0000000000..bc4d2071da --- /dev/null +++ b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.args.json @@ -0,0 +1,19 @@ +{ + "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." + ], + "mode": { + "arkts2": "" + } +} diff --git a/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json new file mode 100644 index 0000000000..56cdb58228 --- /dev/null +++ b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json @@ -0,0 +1,88 @@ +{ + "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": 19, + "column": 1, + "endLine": 19, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + }, + { + "line": 20, + "column": 1, + "endLine": 20, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + }, + { + "line": 21, + "column": 1, + "endLine": 21, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 1, + "endLine": 22, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + }, + { + "line": 23, + "column": 1, + "endLine": 23, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + }, + { + "line": 24, + "column": 1, + "endLine": 24, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + }, + { + "line": 25, + "column": 1, + "endLine": 25, + "endColumn": 8, + "problem": "DeprecatedProcessApi", + "suggest": "", + "rule": "This API of process is obsolete in ArkTS 1.1. It's no longer supported in ArkTS 1.2 (arkts-concurrent-deprecated-apis)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.json b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.json new file mode 100644 index 0000000000..ca88f857e9 --- /dev/null +++ b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.json @@ -0,0 +1,17 @@ +{ + "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": [] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/oh_modules/@kit.ArkTS.d.ets b/ets2panda/linter/test/main/oh_modules/@kit.ArkTS.d.ets index fdb4d44008..48d558071e 100644 --- a/ets2panda/linter/test/main/oh_modules/@kit.ArkTS.d.ets +++ b/ets2panda/linter/test/main/oh_modules/@kit.ArkTS.d.ets @@ -17,4 +17,5 @@ export { worker } from '../oh_modules/@ohos.worker'; export { collections } from '../oh_modules/@arkts.collections'; export { utils } from '../oh_modules/@arkts.utils'; export { taskpool } from '../oh_modules/@ohos.taskpool'; -export { ArkTSUtils } from '../oh_modules/@arkts.utils'; \ No newline at end of file +export { ArkTSUtils } from '../oh_modules/@arkts.utils'; +export { process } from '../oh_modules/@ohos.process'; diff --git a/ets2panda/linter/test/main/oh_modules/@ohos.process.d.ets b/ets2panda/linter/test/main/oh_modules/@ohos.process.d.ets new file mode 100644 index 0000000000..33507584b0 --- /dev/null +++ b/ets2panda/linter/test/main/oh_modules/@ohos.process.d.ets @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export namespace process { + function isAppUid(v: number): boolean; + function getUidForName(v: string): number; + function getThreadPriority(v: number): number; + function getSystemConfig(name: number): number; + function getEnvironmentVar(name: string): string; + function exit(code: number): void; + function kill(signal: number, pid: number): boolean; +} -- Gitee From f946599d306232dc903301eed5a8f191831b5a52 Mon Sep 17 00:00:00 2001 From: muratcimen_9be2 Date: Fri, 1 Aug 2025 09:16:36 +0300 Subject: [PATCH 2/5] Rule arkts-not-support-tuple-generic-validation Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICPIGX Signed-off-by: muratcimen_9be2 --- ets2panda/linter/rule-config.json | 3 +- ets2panda/linter/src/lib/CookBookMsg.ts | 2 + ets2panda/linter/src/lib/FaultAttrs.ts | 1 + ets2panda/linter/src/lib/FaultDesc.ts | 2 + ets2panda/linter/src/lib/Problems.ts | 1 + ets2panda/linter/src/lib/TypeScriptLinter.ts | 31 ++++++- ets2panda/linter/src/lib/utils/TsUtils.ts | 1 + ...s-not-support-tuple-generic-validation.ets | 25 ++++++ ...ort-tuple-generic-validation.ets.args.json | 19 ++++ ...t-tuple-generic-validation.ets.arkts2.json | 88 +++++++++++++++++++ ...-support-tuple-generic-validation.ets.json | 18 ++++ 11 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets create mode 100644 ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.args.json create mode 100644 ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json create mode 100644 ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.json diff --git a/ets2panda/linter/rule-config.json b/ets2panda/linter/rule-config.json index 346a6ee6fc..ba9a6ee7ea 100644 --- a/ets2panda/linter/rule-config.json +++ b/ets2panda/linter/rule-config.json @@ -71,7 +71,8 @@ "arkts-no-duplicate-function-name", "arkts-require-func-arg-type", "arkts-subclass-must-call-super-constructor-with-args", - "arkts-no-esobject-support" + "arkts-no-esobject-support", + "arkts-not-support-tuple-generic-validation" ], "interop": [ "arkts-interop-js2s-inherit-js-class", diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index 54b797cf89..96815f211e 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -312,6 +312,8 @@ cookBookTag[284] = '"prop" function is not supported (arkui-no-prop-function)'; cookBookTag[285] = '"setAndProp" function is not supported (arkui-no-setandprop-function)'; cookBookTag[286] = 'Parameters decorated with "@Prop" need to call the specific method when receiving data to ensure deep copy of the data (arkui-prop-need-call-method-for-deep-copy)'; +cookBookTag[290] = + 'Tuple type cannot be used in generic type parameters of Promise static methods (arkts-not-support-tuple-generic-validation)'; cookBookTag[300] = 'The function type should be explicit (arkts-no-ts-like-function-call)'; cookBookTag[301] = 'Importing from "oh module" requires specifying full path (arkts-require-fullpath-name)'; cookBookTag[302] = diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 197af41f90..14a34b34f3 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -213,6 +213,7 @@ faultsAttrs[FaultID.LocalStoragePropDecoratorNotSupported] = new FaultAttributes faultsAttrs[FaultID.PropFunctionNotSupported] = new FaultAttributes(284); faultsAttrs[FaultID.SetAndPropFunctionNotSupported] = new FaultAttributes(285); faultsAttrs[FaultID.PropNeedCallMethodForDeepCopy] = new FaultAttributes(286); +faultsAttrs[FaultID.NotSupportTupleGenericValidation] = new FaultAttributes(290); faultsAttrs[FaultID.ExplicitFunctionType] = new FaultAttributes(300); faultsAttrs[FaultID.OhmUrlFullPath] = new FaultAttributes(301); faultsAttrs[FaultID.InteropCallObjectParam] = new FaultAttributes(302); diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index 011b01a034..cfe14cd28e 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -170,6 +170,8 @@ faultDesc[FaultID.InteropJsObjectConditionJudgment] = 'Interop JS Object usage i faultDesc[FaultID.InteropJsObjectExpandStaticInstance] = 'Interop JS function usage'; faultDesc[FaultID.InteropJSFunctionInvoke] = 'Interop JS function invoke'; faultDesc[FaultID.VariableMissingInitializer] = 'Value must be assigned to variable'; +faultDesc[FaultID.NotSupportTupleGenericValidation] = + 'Tuple type cannot be used in generic type parameters of Promise static methods'; faultDesc[FaultID.DeprecatedProcessApi] = 'This process Api no longer supported in ArkTS 1.2'; faultDesc[FaultID.ExplicitFunctionType] = 'Not explicit function type'; faultDesc[FaultID.ClassstaticInitialization] = 'The static properties of a class need to have initial values'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index 1497b09c7e..3d58b31926 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -168,6 +168,7 @@ export enum FaultID { MethodOverridingField, InteropJsObjectConditionJudgment, InteropJsObjectExpandStaticInstance, + NotSupportTupleGenericValidation, ExplicitFunctionType, ClassstaticInitialization, TaggedTemplates, diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 467c8a0c45..c3b30d9890 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -19,7 +19,7 @@ import { FaultID } from './Problems'; import { TypeScriptLinterConfig } from './TypeScriptLinterConfig'; import type { Autofix } from './autofixes/Autofixer'; import { Autofixer } from './autofixes/Autofixer'; -import { PROMISE_METHODS, SYMBOL, SYMBOL_CONSTRUCTOR, TsUtils } from './utils/TsUtils'; +import { PROMISE_METHODS, PROMISE_METHODS_WITH_NO_TUPLE_SUPPORT, SYMBOL, SYMBOL_CONSTRUCTOR, TsUtils } from './utils/TsUtils'; import { FUNCTION_HAS_NO_RETURN_ERROR_CODE } from './utils/consts/FunctionHasNoReturnErrorCode'; import { LIMITED_STANDARD_UTILITY_TYPES, @@ -5317,6 +5317,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.checkRestrictedAPICall(tsCallExpr); this.handleNoDeprecatedApi(tsCallExpr); this.handleFunctionReturnThisCall(tsCallExpr); + this.handlePromiseTupleGeneric(tsCallExpr); } private handleCallExpressionForUI(node: ts.CallExpression): void { @@ -13580,4 +13581,32 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } return false; } + + private handlePromiseTupleGeneric(node: ts.CallExpression): void { + if (!this.options.arkts2) { + return; + } + + if ( + ts.isPropertyAccessExpression(node.expression) && + ts.isIdentifier(node.expression.expression) && + node.expression.expression.text === PROMISE + ) { + const methodName = node.expression.name.text; + + if (!PROMISE_METHODS_WITH_NO_TUPLE_SUPPORT.has(methodName)) { + return; + } + + const typeArguments = node.typeArguments; + if (!typeArguments || typeArguments.length === 0) { + return; + } + + const firstArg = typeArguments[0]; + if (ts.isTupleTypeNode(firstArg)) { + this.incrementCounters(firstArg, FaultID.NotSupportTupleGenericValidation); + } + } + } } diff --git a/ets2panda/linter/src/lib/utils/TsUtils.ts b/ets2panda/linter/src/lib/utils/TsUtils.ts index 54a6bf48a0..fb3a664f71 100644 --- a/ets2panda/linter/src/lib/utils/TsUtils.ts +++ b/ets2panda/linter/src/lib/utils/TsUtils.ts @@ -49,6 +49,7 @@ import { EXTNAME_ETS, EXTNAME_JS, EXTNAME_D_ETS } from './consts/ExtensionName'; import { CONCAT_ARRAY, STRING_ERROR_LITERAL } from './consts/Literals'; export const PROMISE_METHODS = new Set(['all', 'race', 'any', 'resolve', 'allSettled']); +export const PROMISE_METHODS_WITH_NO_TUPLE_SUPPORT = new Set(['all', 'race', 'any', 'allSettled']); export const SYMBOL = 'Symbol'; export const SYMBOL_CONSTRUCTOR = 'SymbolConstructor'; const ITERATOR = 'iterator'; diff --git a/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets new file mode 100644 index 0000000000..5f1044a71a --- /dev/null +++ b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +let p1: Promise = new Promise((resolve) => resolve("ok")); +let p2: Promise = new Promise((resolve) => resolve(1)); + +Promise.all<[Promise, Promise]>([p1, p2]); // error +Promise.any<[Promise, Promise]>([p1, p2]); // error +Promise.race<[Promise, Promise]>([p1, p2]); // error +Promise.allSettled<[Promise, Promise]>([p1, p2]); // error + +Promise.all([p1, p2]); // valid +Promise.any([p1, p2]); // valid diff --git a/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.args.json b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.args.json new file mode 100644 index 0000000000..d8d3390ad9 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.args.json @@ -0,0 +1,19 @@ +{ + "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." + ], + "mode": { + "arkts2": "" + } +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json new file mode 100644 index 0000000000..25c25de79c --- /dev/null +++ b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json @@ -0,0 +1,88 @@ +{ + "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": 16, + "column": 27, + "endLine": 16, + "endColumn": 66, + "problem": "GenericCallNoTypeArgs", + "suggest": "", + "rule": "Type inference in case of generic function calls is limited (arkts-no-inferred-generic-params)", + "severity": "ERROR" + }, + { + "line": 17, + "column": 27, + "endLine": 17, + "endColumn": 63, + "problem": "GenericCallNoTypeArgs", + "suggest": "", + "rule": "Type inference in case of generic function calls is limited (arkts-no-inferred-generic-params)", + "severity": "ERROR" + }, + { + "line": 17, + "column": 60, + "endLine": 17, + "endColumn": 61, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 19, + "column": 13, + "endLine": 19, + "endColumn": 47, + "problem": "NotSupportTupleGenericValidation", + "suggest": "", + "rule": "Tuple type cannot be used in generic type parameters of Promise static methods (arkts-not-support-tuple-generic-validation)", + "severity": "ERROR" + }, + { + "line": 20, + "column": 13, + "endLine": 20, + "endColumn": 47, + "problem": "NotSupportTupleGenericValidation", + "suggest": "", + "rule": "Tuple type cannot be used in generic type parameters of Promise static methods (arkts-not-support-tuple-generic-validation)", + "severity": "ERROR" + }, + { + "line": 21, + "column": 14, + "endLine": 21, + "endColumn": 48, + "problem": "NotSupportTupleGenericValidation", + "suggest": "", + "rule": "Tuple type cannot be used in generic type parameters of Promise static methods (arkts-not-support-tuple-generic-validation)", + "severity": "ERROR" + }, + { + "line": 22, + "column": 20, + "endLine": 22, + "endColumn": 54, + "problem": "NotSupportTupleGenericValidation", + "suggest": "", + "rule": "Tuple type cannot be used in generic type parameters of Promise static methods (arkts-not-support-tuple-generic-validation)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.json b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.json new file mode 100644 index 0000000000..895325b061 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.json @@ -0,0 +1,18 @@ +{ + "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": [ + ] +} \ No newline at end of file -- Gitee From 470c4e5a032c8af7a878f741ed7160f5855daea5 Mon Sep 17 00:00:00 2001 From: Raif Mirza Erten Date: Mon, 4 Aug 2025 08:50:24 +0300 Subject: [PATCH 3/5] arkts-distinct-infinity-bitwise-inversion Issue: #ICQ4MZ Description: arkts-distinct-infinity-bitwise-inversion rule implementation Signed-off-by: Raif Mirza Erten --- ets2panda/linter/rule-config.json | 1 + ets2panda/linter/src/lib/CookBookMsg.ts | 3 +- ets2panda/linter/src/lib/FaultAttrs.ts | 1 + ets2panda/linter/src/lib/FaultDesc.ts | 1 + ets2panda/linter/src/lib/Problems.ts | 1 + ets2panda/linter/src/lib/TypeScriptLinter.ts | 301 ++++++++++-------- ets2panda/linter/src/lib/utils/TsUtils.ts | 20 +- .../src/lib/utils/consts/StringLiteral.ts | 1 + ...ts-distinct-infinity-bitwise-inversion.ets | 19 ++ ...t-infinity-bitwise-inversion.ets.args.json | 19 ++ ...infinity-bitwise-inversion.ets.arkts2.json | 28 ++ ...stinct-infinity-bitwise-inversion.ets.json | 17 + .../test/main/index_negative.ets.arkts2.json | 0 .../main/numeric_semantics.ets.arkts2.json | 2 +- .../main/numeric_semantics.ets.autofix.json | 2 +- .../main/numeric_semantics.ets.migrate.json | 2 +- .../test/main/swicth_expr.ets.arkts2.json | 2 +- 17 files changed, 265 insertions(+), 155 deletions(-) create mode 100644 ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets create mode 100644 ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json create mode 100644 ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json create mode 100644 ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json mode change 100755 => 100644 ets2panda/linter/test/main/index_negative.ets.arkts2.json mode change 100755 => 100644 ets2panda/linter/test/main/swicth_expr.ets.arkts2.json diff --git a/ets2panda/linter/rule-config.json b/ets2panda/linter/rule-config.json index ba9a6ee7ea..4eb374948c 100644 --- a/ets2panda/linter/rule-config.json +++ b/ets2panda/linter/rule-config.json @@ -24,6 +24,7 @@ "arkts-numeric-semantic", "arkts-incompatible-function-types", "arkts-limited-void-type", + "arkts-distinct-infinity-bitwise-inversion", "arkts-no-void-operator", "arkts-no-local-class", "arkts-no-ts-overload", diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index 96815f211e..55a46b8d68 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -88,7 +88,8 @@ cookBookTag[57] = ''; cookBookTag[58] = ''; cookBookTag[59] = '"delete" operator is not supported (arkts-no-delete)'; cookBookTag[60] = '"typeof" operator is allowed only in expression contexts (arkts-no-type-query)'; -cookBookTag[61] = ''; +cookBookTag[61] = + 'The bitwise inversion gives different result for "Infinity" (arkts-distinct-infinity-bitwise-inversion)'; cookBookTag[62] = ''; cookBookTag[63] = ''; cookBookTag[64] = ''; diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 14a34b34f3..818f79e0c9 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -59,6 +59,7 @@ faultsAttrs[FaultID.JsxElement] = new FaultAttributes(54); faultsAttrs[FaultID.UnaryArithmNotNumber] = new FaultAttributes(55); faultsAttrs[FaultID.DeleteOperator] = new FaultAttributes(59); faultsAttrs[FaultID.TypeQuery] = new FaultAttributes(60); +faultsAttrs[FaultID.PrefixUnaryInfinity] = new FaultAttributes(61); faultsAttrs[FaultID.InstanceofUnsupported] = new FaultAttributes(65); faultsAttrs[FaultID.InOperator] = new FaultAttributes(66); faultsAttrs[FaultID.DestructuringAssignment] = new FaultAttributes(69); diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index cfe14cd28e..fa035e1595 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -82,6 +82,7 @@ faultDesc[FaultID.StructuralIdentity] = 'Use of type structural identity'; faultDesc[FaultID.ExportAssignment] = 'Export assignments (export = ..)'; faultDesc[FaultID.ImportAssignment] = 'Import assignments (import = ..)'; faultDesc[FaultID.GenericCallNoTypeArgs] = 'Generic calls without type arguments'; +faultDesc[FaultID.PrefixUnaryInfinity] = 'Prefix unary infinity'; faultDesc[FaultID.ParameterProperties] = 'Parameter properties in constructor'; faultDesc[FaultID.InstanceofUnsupported] = 'Left-hand side of "instanceof" is wrong'; faultDesc[FaultID.TemplateStringType] = 'Template string type'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index 3d58b31926..86086f6993 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -103,6 +103,7 @@ export enum FaultID { LimitedStdLibApi, LimitedStdLibNoASON, NoNeedStdLibSendableContainer, + PrefixUnaryInfinity, ErrorSuppression, StrictDiagnostic, ImportAfterStatement, diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index c3b30d9890..0b4e850499 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -38,7 +38,8 @@ import { STRINGLITERAL_CHAR, STRINGLITERAL_LONG, STRINGLITERAL_FROM, - STRINGLITERAL_ARRAY + STRINGLITERAL_ARRAY, + STRINGLITERAL_INFINITY } from './utils/consts/StringLiteral'; import { NON_INITIALIZABLE_PROPERTY_CLASS_DECORATORS, @@ -257,6 +258,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private initEtsHandlers(): void { + /* * some syntax elements are ArkTs-specific and are only implemented inside patched * compiler, so we initialize those handlers if corresponding properties do exist @@ -445,7 +447,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { [ts.SyntaxKind.TypeOfExpression, this.handleInterOpImportJsOnTypeOfNode], [ts.SyntaxKind.AwaitExpression, this.handleAwaitExpression], [ts.SyntaxKind.PostfixUnaryExpression, this.handlePostfixUnaryExpression], - [ts.SyntaxKind.BigIntLiteral, this.handleBigIntLiteral], + [ts.SyntaxKind.BigIntLiteral, this.handleBigIntLiteral] ]); lint(): void { @@ -474,6 +476,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } else { const handler = this.handlersMap.get(node.kind); if (handler !== undefined) { + /* * possibly requested cancellation will be checked in a limited number of handlers * checked nodes are selected as construct nodes, similar to how TSC does @@ -581,7 +584,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * X.prototype.prototype.prototype = ... */ const baseExprTypeNode = this.tsTypeChecker.typeToTypeNode(baseExprType, undefined, ts.NodeBuilderFlags.None); - return (baseExprTypeNode && ts.isFunctionTypeNode(baseExprTypeNode)) || TsUtils.isAnyType(baseExprType); + return baseExprTypeNode && ts.isFunctionTypeNode(baseExprTypeNode) || TsUtils.isAnyType(baseExprType); } private interfaceInheritanceLint(node: ts.Node, heritageClauses: ts.NodeArray): void { @@ -655,8 +658,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ): boolean { return ( ts.isPropertyAssignment(prop) || - (ts.isShorthandPropertyAssignment(prop) && - (ts.isCallExpression(objLitExpr.parent) || ts.isNewExpression(objLitExpr.parent))) + ts.isShorthandPropertyAssignment(prop) && + (ts.isCallExpression(objLitExpr.parent) || ts.isNewExpression(objLitExpr.parent)) ); } @@ -718,6 +721,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private handleArrayLiteralExpression(node: ts.Node): void { + /* * If array literal is a part of destructuring assignment, then * don't process it further. @@ -914,6 +918,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const iSymbol = this.tsUtils.trueSymbolAtLocation(interfaceNode.name); const iDecls = iSymbol ? iSymbol.getDeclarations() : null; if (iDecls) { + /* * Since type checker merges all declarations with the same name * into one symbol, we need to check that there's more than one @@ -1197,7 +1202,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleImportModule(importDeclNode); if (this.options.arkts2) { const importClause = importDeclNode.importClause; - if (!importClause || (!importClause.name && !importClause.namedBindings)) { + if (!importClause || !importClause.name && !importClause.namedBindings) { const autofix = this.autofixer?.fixSideEffectImport(importDeclNode); this.incrementCounters(node, FaultID.NoSideEffectImport, autofix); } else { @@ -1275,6 +1280,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const modulePath = importDeclNode.moduleSpecifier.getText().slice(1, -1); if (modulePath.startsWith('./') || modulePath.startsWith('../')) { + /* * Reason for this method to check the oh module imports, * We do not use relative paths when importing from OhModules, @@ -1446,9 +1452,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isBinaryExpression(propertyAccessNode.parent)) { const isAssignment = propertyAccessNode.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken; - const autofix = isAssignment - ? this.autofixer?.fixInteropBinaryExpression(propertyAccessNode.parent) - : this.autofixer?.fixInteropPropertyAccessExpression(propertyAccessNode); + const autofix = isAssignment ? + this.autofixer?.fixInteropBinaryExpression(propertyAccessNode.parent) : + this.autofixer?.fixInteropPropertyAccessExpression(propertyAccessNode); this.incrementCounters( isAssignment ? propertyAccessNode.parent : propertyAccessNode, @@ -1507,9 +1513,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if ( - (baseExprSym && TsUtils.isFunctionSymbol(baseExprSym)) || + baseExprSym && TsUtils.isFunctionSymbol(baseExprSym) || this.tsUtils.isStdFunctionType(baseExprType) || - (TsUtils.isFunctionalType(baseExprType) && TsUtils.isAnonymousType(baseExprType)) + TsUtils.isFunctionalType(baseExprType) && TsUtils.isAnonymousType(baseExprType) ) { this.incrementCounters(node.expression, FaultID.PropertyDeclOnFunction); } @@ -1544,7 +1550,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return false; } if ( - (ts.isTypeAliasDeclaration(decl) && this.checkSpecialTypeNode(decl.type, true)) || + ts.isTypeAliasDeclaration(decl) && this.checkSpecialTypeNode(decl.type, true) || this.checkSpecialTypeNode(decl, true) ) { return true; @@ -1707,7 +1713,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private static extractKeyofFromString(typeString: string): boolean { - return /\bkeyof\b/.test(typeString); + return (/\bkeyof\b/).test(typeString); } checkUnionTypes(propertyAccessNode: ts.PropertyAccessExpression): void { @@ -1773,7 +1779,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private handleLiteralAsPropertyName(node: ts.PropertyDeclaration | ts.PropertySignature): void { const propName = node.name; - if (!!propName && (ts.isNumericLiteral(propName) || (this.options.arkts2 && ts.isStringLiteral(propName)))) { + if (!!propName && (ts.isNumericLiteral(propName) || this.options.arkts2 && ts.isStringLiteral(propName))) { const autofix = this.autofixer?.fixLiteralAsPropertyNamePropertyName(propName); this.incrementCounters(node.name, FaultID.LiteralAsPropertyName, autofix); } @@ -1840,7 +1846,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleQuotedHyphenPropsDeprecated(node); this.handleNoDeprecatedApi(node); const propName = node.name; - if (!propName || !(ts.isNumericLiteral(propName) || (this.options.arkts2 && ts.isStringLiteral(propName)))) { + if (!propName || !(ts.isNumericLiteral(propName) || this.options.arkts2 && ts.isStringLiteral(propName))) { return; } @@ -2192,8 +2198,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const tsRetType = this.tsTypeChecker.getReturnTypeOfSignature(tsSignature); if ( !tsRetType || - (!this.options.arkts2 && TsUtils.isUnsupportedType(tsRetType)) || - (this.options.arkts2 && this.tsUtils.isUnsupportedTypeArkts2(tsRetType)) + !this.options.arkts2 && TsUtils.isUnsupportedType(tsRetType) || + this.options.arkts2 && this.tsUtils.isUnsupportedTypeArkts2(tsRetType) ) { hasLimitedRetTypeInference = true; } else if (hasLimitedRetTypeInference) { @@ -2306,6 +2312,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (this.useStatic && this.options.arkts2) { const tsUnaryArithm = node as ts.PrefixUnaryExpression; this.handleInteropOperand(tsUnaryArithm); + this.handleInfinityIdentifier(tsUnaryArithm); } const tsUnaryOp = tsUnaryArithm.operator; const tsUnaryOperand = tsUnaryArithm.operand; @@ -2330,6 +2337,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } + private handleInfinityIdentifier(node: ts.PrefixUnaryExpression): void { + const identifier = node.operand; + if (identifier.getText() === STRINGLITERAL_INFINITY && node.operator === ts.SyntaxKind.TildeToken) { + this.incrementCounters(node, FaultID.PrefixUnaryInfinity); + } + } + private handleBinaryExpression(node: ts.Node): void { const tsBinaryExpr = node as ts.BinaryExpression; const tsLhsExpr = tsBinaryExpr.left; @@ -2374,7 +2388,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleArkTSPropertyAccess(tsBinaryExpr); this.handleObjectLiteralAssignmentToClass(tsBinaryExpr); this.handleAssignmentNotsLikeSmartType(tsBinaryExpr); - this.checkNumericSemanticsForBinaryExpression(tsBinaryExpr) + this.checkNumericSemanticsForBinaryExpression(tsBinaryExpr); } private checkInterOpImportJsDataCompare(expr: ts.BinaryExpression): void { @@ -2516,7 +2530,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } - private static isNumericInitializer(node: ts.Node): boolean { if (ts.isNumericLiteral(node)) { return true; @@ -2640,7 +2653,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleVariableDeclarationForProp(tsVarDecl); if ( !this.options.useRtLogic || - (ts.isVariableDeclarationList(tsVarDecl.parent) && ts.isVariableStatement(tsVarDecl.parent.parent)) + ts.isVariableDeclarationList(tsVarDecl.parent) && ts.isVariableStatement(tsVarDecl.parent.parent) ) { this.handleDeclarationDestructuring(tsVarDecl); } @@ -2719,8 +2732,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - if (this.tsUtils.isPossiblyImportedFromJS(node.left) || - this.tsUtils.isPossiblyImportedFromJS(node.right)) { + if (this.tsUtils.isPossiblyImportedFromJS(node.left) || this.tsUtils.isPossiblyImportedFromJS(node.right)) { return; } @@ -2736,15 +2748,19 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return true; } - if (ts.isBinaryExpression(node.parent) && + if ( + ts.isBinaryExpression(node.parent) && node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && - ts.isElementAccessExpression(node.parent.left)) { + ts.isElementAccessExpression(node.parent.left) + ) { return true; } - if (ts.isBinaryExpression(node.parent) && + if ( + ts.isBinaryExpression(node.parent) && node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && - this.tsUtils.isNumberArrayType(this.tsTypeChecker.getTypeAtLocation(node.parent.left))) { + this.tsUtils.isNumberArrayType(this.tsTypeChecker.getTypeAtLocation(node.parent.left)) + ) { return true; } @@ -2793,15 +2809,12 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isNumericLiteral(element) && !element.text.includes('.')) { const autofix = this.autofixer?.fixNumericLiteralToFloat(element); this.incrementCounters(element, FaultID.NumericSemantics, autofix); - } - else if (ts.isBinaryExpression(element) && - element.operatorToken.kind === ts.SyntaxKind.SlashToken) { + } else if (ts.isBinaryExpression(element) && element.operatorToken.kind === ts.SyntaxKind.SlashToken) { this.checkNumericSemanticsForDivisionOperation(element); } } } - private checkNumericSemanticsForVariable(node: ts.VariableDeclaration): void { if (!this.options.arkts2 || !node.initializer) { return; @@ -2812,8 +2825,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - if (ts.isBinaryExpression(node.initializer) && - node.initializer.operatorToken.kind === ts.SyntaxKind.BarBarToken) { + if (ts.isBinaryExpression(node.initializer) && node.initializer.operatorToken.kind === ts.SyntaxKind.BarBarToken) { this.checkNumericSemanticsForNullishCoalescing(node.initializer); } else if (ts.isConditionalExpression(node.initializer)) { this.checkNumericSemanticsForTernaryOperator(node.initializer); @@ -2852,9 +2864,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private handleDeclarationDestructuring(decl: ts.VariableDeclaration | ts.ParameterDeclaration): void { const faultId = ts.isVariableDeclaration(decl) ? FaultID.DestructuringDeclaration : FaultID.DestructuringParameter; if (ts.isObjectBindingPattern(decl.name)) { - const autofix = ts.isVariableDeclaration(decl) - ? this.autofixer?.fixObjectBindingPatternDeclarations(decl) - : undefined; + const autofix = ts.isVariableDeclaration(decl) ? + this.autofixer?.fixObjectBindingPatternDeclarations(decl) : + undefined; this.incrementCounters(decl, faultId, autofix); } else if (ts.isArrayBindingPattern(decl.name)) { // Array destructuring is allowed only for Arrays/Tuples and without spread operator. @@ -2871,9 +2883,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { hasNestedObjectDestructuring || TsUtils.destructuringDeclarationHasSpreadOperator(decl.name) ) { - const autofix = ts.isVariableDeclaration(decl) - ? this.autofixer?.fixArrayBindingPatternDeclarations(decl, isArrayOrTuple) - : undefined; + const autofix = ts.isVariableDeclaration(decl) ? + this.autofixer?.fixArrayBindingPatternDeclarations(decl, isArrayOrTuple) : + undefined; this.incrementCounters(decl, faultId, autofix); } } @@ -3343,6 +3355,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * Handle comment directive '@ts-nocheck' */ while ((currentNode as any).expression) { + /* * CC-OFFNXT(no_explicit_any) std lib * Handle comment directive '@ts-nocheck' @@ -3358,9 +3371,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { methodName?: string ): boolean { return heritageClause.types.some((type) => { - const parentName = ts.isPropertyAccessExpression(type.expression) - ? type.expression.name.text - : type.expression.getText(); + const parentName = ts.isPropertyAccessExpression(type.expression) ? + type.expression.name.text : + type.expression.getText(); const fullTypeName = TypeScriptLinter.findFinalExpression(type).getText(); const sdkInfos = this.interfaceMap.get(fullTypeName); if (!sdkInfos || sdkInfos.size === 0) { @@ -3545,6 +3558,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private checkClassDeclarationHeritageClause(hClause: ts.HeritageClause, isSendableClass: boolean): void { for (const tsTypeExpr of hClause.types) { + /* * Always resolve type from 'tsTypeExpr' node, not from 'tsTypeExpr.expression' node, * as for the latter, type checker will return incorrect type result for classes in @@ -3675,10 +3689,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const names = new Set(); if ( - (ts.isFunctionDeclaration(statement) && statement.name && statement.body) || - (ts.isClassDeclaration(statement) && statement.name) || - (ts.isInterfaceDeclaration(statement) && statement.name) || - (ts.isEnumDeclaration(statement) && statement.name) + ts.isFunctionDeclaration(statement) && statement.name && statement.body || + ts.isClassDeclaration(statement) && statement.name || + ts.isInterfaceDeclaration(statement) && statement.name || + ts.isEnumDeclaration(statement) && statement.name ) { names.add(statement.name.text); return names; @@ -4337,7 +4351,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ]; for (const [wrapper, primitive] of typePairs) { - if ((typeStr === wrapper && typeSet.has(primitive)) || (typeStr === primitive && typeSet.has(wrapper))) { + if (typeStr === wrapper && typeSet.has(primitive) || typeStr === primitive && typeSet.has(wrapper)) { return true; } } @@ -4688,6 +4702,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private isStdlibClassVarDecl(ident: ts.Identifier, sym: ts.Symbol): boolean { + /* * Most standard JS classes are defined in TS stdlib as ambient global * variables with interface constructor type and require special check @@ -4738,7 +4753,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if ( - ((tsIdentSym.flags & illegalValues) === 0 && !this.isStdlibClassVarDecl(tsIdentifier, tsIdentSym)) || + (tsIdentSym.flags & illegalValues) === 0 && !this.isStdlibClassVarDecl(tsIdentifier, tsIdentSym) || isStruct(tsIdentSym) || !identiferUseInValueContext(tsIdentifier, tsIdentSym) ) { @@ -4810,8 +4825,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.tsUtils.isOrDerivedFrom(type, TsUtils.isTuple) || this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStdRecordType) || this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStringType) || - (!this.options.arkts2 && - (this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStdMapType) || TsUtils.isIntrinsicObjectType(type))) || + !this.options.arkts2 && + (this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStdMapType) || TsUtils.isIntrinsicObjectType(type)) || TsUtils.isEnumType(type) || // we allow EsObject here beacuse it is reported later using FaultId.EsObjectType TsUtils.isEsValueType(typeNode) @@ -4864,8 +4879,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.tsUtils.isLibrarySymbol(tsElementAccessExprSymbol) || ts.isArrayLiteralExpression(tsElementAccessExpr.expression) || this.isElementAcessAllowed(tsElemAccessBaseExprType, tsElemAccessArgType) || - (this.options.arkts2 && isGetIndexable) || - (this.options.arkts2 && isSetIndexable) + this.options.arkts2 && isGetIndexable || + this.options.arkts2 && isSetIndexable ) { return; } @@ -5555,6 +5570,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { callLikeExpr: ts.CallExpression | ts.NewExpression | ts.ExpressionWithTypeArguments, callSignature?: ts.Signature ): void { + /* * Note: The PR!716 has led to a significant performance degradation. * Since initial problem was fixed in a more general way, this change @@ -5585,9 +5601,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isNewExpression(callLikeExpr) && this.isNonGenericClass(callLikeExpr)) { return; } - const tsSyntaxKind = ts.isNewExpression(callLikeExpr) - ? ts.SyntaxKind.Constructor - : ts.SyntaxKind.FunctionDeclaration; + const tsSyntaxKind = ts.isNewExpression(callLikeExpr) ? + ts.SyntaxKind.Constructor : + ts.SyntaxKind.FunctionDeclaration; const signFlags = ts.NodeBuilderFlags.WriteTypeArgumentsOfSignature | ts.NodeBuilderFlags.IgnoreErrors; const signDecl = this.tsTypeChecker.signatureToSignatureDeclaration( callSignature, @@ -5605,7 +5621,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const shouldCheck = this.shouldCheckGenericCallExpression(callLikeExpr as ts.CallExpression); if ( this.options.arkts2 && - (ts.isNewExpression(callLikeExpr) || (ts.isCallExpression(callLikeExpr) && shouldCheck)) + (ts.isNewExpression(callLikeExpr) || ts.isCallExpression(callLikeExpr) && shouldCheck) ) { shouldReportError = this.shouldReportGenericTypeArgsError( callLikeExpr, @@ -5702,9 +5718,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * in ArkTS and already have separate check for it. */ if (typeNode.kind === ts.SyntaxKind.UnknownKeyword) { - const autofix = ts.isCallExpression(callLikeExpr) - ? this.autofixer?.fixGenericCallNoTypeArgsForUnknown(callLikeExpr) - : undefined; + const autofix = ts.isCallExpression(callLikeExpr) ? + this.autofixer?.fixGenericCallNoTypeArgsForUnknown(callLikeExpr) : + undefined; this.incrementCounters(callLikeExpr, FaultID.GenericCallNoTypeArgs, autofix); break; } @@ -6004,6 +6020,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { expr, this.tsUtils.isLibraryType(this.tsTypeChecker.getTypeAtLocation(expr.expression)), (diagnostic, errorType) => { + /* * When a diagnostic meets the filter criteria, If it happens in an ets file in the 'oh_modules' directory. * the diagnostic is downgraded to warning. For other files, downgraded to nothing. @@ -6203,8 +6220,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const exprType = this.tsTypeChecker.getTypeAtLocation(tsAsExpr.expression).getNonNullableType(); // check for rule#65: 'number as Number' and 'boolean as Boolean' are disabled if ( - (this.tsUtils.isNumberLikeType(exprType) && this.tsUtils.isStdNumberType(targetType)) || - (TsUtils.isBooleanLikeType(exprType) && this.tsUtils.isStdBooleanType(targetType)) + this.tsUtils.isNumberLikeType(exprType) && this.tsUtils.isStdNumberType(targetType) || + TsUtils.isBooleanLikeType(exprType) && this.tsUtils.isStdBooleanType(targetType) ) { this.incrementCounters(node, FaultID.TypeAssertion); } @@ -6296,7 +6313,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const isRestrictedPrimitive = restrictedPrimitiveTypes.includes(type.kind); const isRestrictedArrayType = type.kind === ts.SyntaxKind.ArrayType || - (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName) && type.typeName.text === 'Array'); + ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName) && type.typeName.text === 'Array'; if (!isRestrictedPrimitive && !isRestrictedArrayType) { return; @@ -6323,7 +6340,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const type = tsAsExpr.type; const isNullAssertion = type.kind === ts.SyntaxKind.NullKeyword || - (ts.isLiteralTypeNode(type) && type.literal.kind === ts.SyntaxKind.NullKeyword) || + ts.isLiteralTypeNode(type) && type.literal.kind === ts.SyntaxKind.NullKeyword || type.getText() === 'null'; if (isNullAssertion) { this.incrementCounters(tsAsExpr, FaultID.InterOpConvertImport); @@ -6556,6 +6573,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private handleSpreadOp(node: ts.Node): void { + /* * spread assignment is disabled * spread element is allowed only for arrays as rest parameter @@ -6650,7 +6668,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { decl: ts.VariableDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration ): boolean | undefined { if ( - ((ts.isVariableDeclaration(decl) && ts.isVariableStatement(decl.parent.parent)) || + (ts.isVariableDeclaration(decl) && ts.isVariableStatement(decl.parent.parent) || ts.isPropertyDeclaration(decl)) && !decl.initializer ) { @@ -6773,6 +6791,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private handleCommentDirectives(sourceFile: ts.SourceFile): void { + /* * We use a dirty hack to retrieve list of parsed comment directives by accessing * internal properties of SourceFile node. @@ -6783,6 +6802,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (pragmas && pragmas instanceof Map) { const noCheckPragma = pragmas.get('ts-nocheck'); if (noCheckPragma) { + /* * The value is either a single entry or an array of entries. * Wrap up single entry with array to simplify processing. @@ -6806,9 +6826,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const range = directive.range as ts.TextRange; const kind: ts.SyntaxKind = - sourceFile.text.slice(range.pos, range.pos + 2) === '/*' - ? ts.SyntaxKind.MultiLineCommentTrivia - : ts.SyntaxKind.SingleLineCommentTrivia; + sourceFile.text.slice(range.pos, range.pos + 2) === '/*' ? + ts.SyntaxKind.MultiLineCommentTrivia : + ts.SyntaxKind.SingleLineCommentTrivia; const commentRange: ts.CommentRange = { pos: range.pos, end: range.end, @@ -6957,7 +6977,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const declPosition = decl.getStart(); if ( decl.getSourceFile().fileName !== node.getSourceFile().fileName || - (declPosition !== undefined && declPosition >= scope.getStart() && declPosition < scope.getEnd()) + declPosition !== undefined && declPosition >= scope.getStart() && declPosition < scope.getEnd() ) { return; } @@ -7154,6 +7174,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { rhsType: ts.Type, rhsExpr: ts.Expression ): boolean { + /* * When resolving the contextual type for return expression in async function, the TS compiler * infers 'PromiseLike' type instead of standard 'Promise' (see following link: @@ -7236,8 +7257,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private isSendableDecoratorValid(decl: ts.FunctionDeclaration | ts.TypeAliasDeclaration): boolean { if ( this.compatibleSdkVersion > SENDBALE_FUNCTION_START_VERSION || - (this.compatibleSdkVersion === SENDBALE_FUNCTION_START_VERSION && - !SENDABLE_FUNCTION_UNSUPPORTED_STAGES_IN_API12.includes(this.compatibleSdkVersionStage)) + this.compatibleSdkVersion === SENDBALE_FUNCTION_START_VERSION && + !SENDABLE_FUNCTION_UNSUPPORTED_STAGES_IN_API12.includes(this.compatibleSdkVersionStage) ) { return true; } @@ -7298,7 +7319,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ts.isExpressionStatement(node.parent) || ts.isVoidExpression(node.parent) || ts.isArrowFunction(node.parent) || - (ts.isConditionalExpression(node.parent) && ts.isExpressionStatement(node.parent.parent)) + ts.isConditionalExpression(node.parent) && ts.isExpressionStatement(node.parent.parent) ) { return; } @@ -7407,7 +7428,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return ts.isFunctionDeclaration(name) || ts.isMethodDeclaration(name); }); const isInternalFunction = decl.name && ts.isIdentifier(decl.name) && interanlFunction.includes(decl.name.text); - if ((isInternalFunction && filterDecl.length > 2) || (!isInternalFunction && filterDecl.length > 1)) { + if (isInternalFunction && filterDecl.length > 2 || !isInternalFunction && filterDecl.length > 1) { this.incrementCounters(decl, FaultID.TsOverload); } } else if (ts.isConstructorDeclaration(decl) && decl.getText()) { @@ -7453,8 +7474,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { t.flags & ts.TypeFlags.StringLike || typeText === 'String' || typeText === 'number' || - (t.flags & ts.TypeFlags.NumberLike && /^\d+$/.test(typeText)) || - (isLiteralInitialized && !hasExplicitTypeAnnotation) || + t.flags & ts.TypeFlags.NumberLike && (/^\d+$/).test(typeText) || + isLiteralInitialized && !hasExplicitTypeAnnotation || t.flags & ts.TypeFlags.EnumLike ); }; @@ -7587,7 +7608,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private evaluateNumericValueFromPrefixUnaryExpression(node: ts.PrefixUnaryExpression): number | null { if (node.operator === ts.SyntaxKind.MinusToken) { - if (ts.isNumericLiteral(node.operand) || (ts.isIdentifier(node.operand) && node.operand.text === 'Infinity')) { + if (ts.isNumericLiteral(node.operand) || ts.isIdentifier(node.operand) && node.operand.text === 'Infinity') { return node.operand.text === 'Infinity' ? Number.NEGATIVE_INFINITY : -Number(node.operand.text); } const operandValue = this.evaluateNumericValue(node.operand); @@ -7602,7 +7623,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const typeNode = node.type; if ( typeNode.kind === ts.SyntaxKind.NumberKeyword || - (ts.isTypeReferenceNode(typeNode) && typeNode.typeName.getText() === 'Number') + ts.isTypeReferenceNode(typeNode) && typeNode.typeName.getText() === 'Number' ) { return this.evaluateNumericValue(node.expression); } @@ -7715,10 +7736,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } if ( - (this.tsUtils.isOrDerivedFrom(lhsType, this.tsUtils.isArray) && - this.tsUtils.isOrDerivedFrom(rhsType, TsUtils.isTuple)) || - (this.tsUtils.isOrDerivedFrom(rhsType, this.tsUtils.isArray) && - this.tsUtils.isOrDerivedFrom(lhsType, TsUtils.isTuple)) + this.tsUtils.isOrDerivedFrom(lhsType, this.tsUtils.isArray) && + this.tsUtils.isOrDerivedFrom(rhsType, TsUtils.isTuple) || + this.tsUtils.isOrDerivedFrom(rhsType, this.tsUtils.isArray) && + this.tsUtils.isOrDerivedFrom(lhsType, TsUtils.isTuple) ) { this.incrementCounters(node, FaultID.NoTuplesArrays); } @@ -7947,7 +7968,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } const text = node.initializer.getText(); - if (!/^\$.+$/.test(text)) { + if (!(/^\$.+$/).test(text)) { return; } @@ -9162,7 +9183,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private shouldWarn(symbol: ts.Symbol): boolean { const parentApiName = this.getLocalApiListItemByKey(SdkNameInfo.ParentApiName); - return (symbol && this.isHeritageClauseisThirdPartyBySymbol(symbol)) || symbol.name === parentApiName; + return symbol && this.isHeritageClauseisThirdPartyBySymbol(symbol) || symbol.name === parentApiName; } private getFinalSymOnQuotedHyphenPropsDeprecated(node: ts.Node): ts.Symbol | undefined { @@ -9210,9 +9231,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private getTypeOfVariable(variable: ts.VariableDeclaration): ts.Symbol | undefined { if (variable.type) { - return ts.isArrayTypeNode(variable.type) - ? this.resolveTypeNodeSymbol(variable.type.elementType) - : this.resolveTypeNodeSymbol(variable.type); + return ts.isArrayTypeNode(variable.type) ? + this.resolveTypeNodeSymbol(variable.type.elementType) : + this.resolveTypeNodeSymbol(variable.type); } return variable.initializer ? this.tsTypeChecker.getTypeAtLocation(variable.initializer).getSymbol() : undefined; } @@ -9655,7 +9676,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return false; } - const propertyName = (ts.isIdentifier(decl.expression.name) && decl.expression.name.text) || ''; + const propertyName = ts.isIdentifier(decl.expression.name) && decl.expression.name.text || ''; if (propertyName !== 'self') { return false; } @@ -9669,13 +9690,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - const importApiName = (ts.isIdentifier(decl.expression.expression) && decl.expression.expression.text) || ''; + const importApiName = ts.isIdentifier(decl.expression.expression) && decl.expression.expression.text || ''; const sdkInfos = importApiName && this.interfaceMap.get(importApiName); if (!sdkInfos) { return; } - const apiName = (ts.isIdentifier(decl.name) && decl.name.text) || ''; + const apiName = ts.isIdentifier(decl.name) && decl.name.text || ''; const matchedApi = [...sdkInfos].find((sdkInfo) => { return sdkInfo.api_name === apiName; }); @@ -9888,7 +9909,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if ( decl && (ts.isFunctionDeclaration(decl) || - (ts.isVariableDeclaration(decl) && decl.initializer && ts.isArrowFunction(decl.initializer))) + ts.isVariableDeclaration(decl) && decl.initializer && ts.isArrowFunction(decl.initializer)) ) { this.incrementCounters(arg, FaultID.InteropJsObjectCallStaticFunc); } @@ -9950,16 +9971,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!TypeScriptLinter.isInForLoopBody(elementAccessExpr)) { return; } - const variableDeclaration = ts.isIdentifier(elementAccessExpr.expression) - ? this.tsUtils.findVariableDeclaration(elementAccessExpr.expression) - : undefined; + const variableDeclaration = ts.isIdentifier(elementAccessExpr.expression) ? + this.tsUtils.findVariableDeclaration(elementAccessExpr.expression) : + undefined; if (!variableDeclaration?.initializer) { return; } - const identifier = ts.isPropertyAccessExpression(variableDeclaration.initializer) - ? (variableDeclaration.initializer.expression as ts.Identifier) - : undefined; + const identifier = ts.isPropertyAccessExpression(variableDeclaration.initializer) ? + (variableDeclaration.initializer.expression as ts.Identifier) : + undefined; if (!identifier) { return; } @@ -9988,9 +10009,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!this.options.arkts2 || !this.useStatic) { return; } - const objectExpr = ts.isNewExpression(propertyAccess.expression) - ? propertyAccess.expression.expression - : propertyAccess.expression; + const objectExpr = ts.isNewExpression(propertyAccess.expression) ? + propertyAccess.expression.expression : + propertyAccess.expression; // Step 1: Must be either setCloneList or setTransferList if (!TypeScriptLinter.isDeprecatedTaskPoolMethodCall(propertyAccess)) { return; @@ -10009,9 +10030,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } const faultId = - propertyAccess.name.text === DEPRECATED_TASKPOOL_METHOD_SETCLONELIST - ? FaultID.SetCloneListDeprecated - : FaultID.SetTransferListDeprecated; + propertyAccess.name.text === DEPRECATED_TASKPOOL_METHOD_SETCLONELIST ? + FaultID.SetCloneListDeprecated : + FaultID.SetTransferListDeprecated; this.incrementCounters(propertyAccess.name, faultId); } @@ -10026,7 +10047,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private isTaskPoolTaskCreation(taskpoolExpr: ts.Expression): boolean { if ( ts.isIdentifier(taskpoolExpr) || - (ts.isPropertyAccessExpression(taskpoolExpr) && taskpoolExpr.name.text === STDLIB_TASK_CLASS_NAME) + ts.isPropertyAccessExpression(taskpoolExpr) && taskpoolExpr.name.text === STDLIB_TASK_CLASS_NAME ) { const objectExpr = ts.isIdentifier(taskpoolExpr) ? taskpoolExpr : taskpoolExpr.expression; return this.isTaskPoolReferenceisTaskPoolImportForTaskPoolDeprecatedUsages(objectExpr); @@ -10305,16 +10326,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { */ private isFieldTypeMatchingBetweenDerivedAndBaseClass(derivedType: ts.Type, baseType: ts.Type): boolean { // Split union type strings into trimmed member names - const derivedNames = this.tsTypeChecker - .typeToString(derivedType) - .split('|') - .map((s) => { + const derivedNames = this.tsTypeChecker. + typeToString(derivedType). + split('|'). + map((s) => { return s.trim(); }); - const baseNames = this.tsTypeChecker - .typeToString(baseType) - .split('|') - .map((s) => { + const baseNames = this.tsTypeChecker. + typeToString(baseType). + split('|'). + map((s) => { return s.trim(); }); @@ -10500,7 +10521,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { symbol?.declarations?.some((decl) => { return ( ts.isEnumDeclaration(decl) || - (ts.isVariableDeclaration(decl) && decl.initializer && ts.isEnumDeclaration(decl.initializer)) + ts.isVariableDeclaration(decl) && decl.initializer && ts.isEnumDeclaration(decl.initializer) ); }) ?? false ); @@ -10540,6 +10561,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if (superCall.arguments.length > 1) { + /* * STD Error Type have two constructors * either empty constructor which is just "Error" message @@ -11076,9 +11098,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - const parentType = node.type - ? this.tsTypeChecker.getTypeAtLocation(node.type) - : this.tsTypeChecker.getTypeAtLocation(node.initializer); + const parentType = node.type ? + this.tsTypeChecker.getTypeAtLocation(node.type) : + this.tsTypeChecker.getTypeAtLocation(node.initializer); this.processNestedObjectLiterals(node.initializer, parentType); } @@ -11773,7 +11795,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { }; const isBigIntAndNumberOperand = - (isNumber(leftType) && isBigInt(rightType)) || (isBigInt(leftType) && isNumber(rightType)); + isNumber(leftType) && isBigInt(rightType) || isBigInt(leftType) && isNumber(rightType); if (isBigIntAndNumberOperand) { this.incrementCounters(node, FaultID.NumericBigintCompare); } @@ -11785,7 +11807,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } const literalText = node.getText(); - if (/^0[box]/i.test(literalText)) { + if ((/^0[box]/i).test(literalText)) { this.incrementCounters(node, FaultID.NondecimalBigint); } } @@ -11864,7 +11886,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return binaryOperators.includes(kind); } - private checkArrayUsageWithoutBound(accessExpr: ts.ElementAccessExpression): void { if (this.shouldSkipArrayBoundCheck(accessExpr)) { return; @@ -12041,13 +12062,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName: string, arraySym: ts.Symbol ): { isValidBoundCheck: boolean; isVarModifiedBeforeAccess: boolean } { - const isValidBoundCheck = forNode.condition - ? this.checkBoundCondition(forNode.condition, loopVarName, arraySym) - : false; + const isValidBoundCheck = forNode.condition ? + this.checkBoundCondition(forNode.condition, loopVarName, arraySym) : + false; - const isVarModifiedBeforeAccess = forNode.statement - ? TypeScriptLinter.checkVarModifiedBeforeNode(forNode.statement, accessExpr, loopVarName) - : false; + const isVarModifiedBeforeAccess = forNode.statement ? + TypeScriptLinter.checkVarModifiedBeforeNode(forNode.statement, accessExpr, loopVarName) : + false; return { isValidBoundCheck, isVarModifiedBeforeAccess }; } @@ -12058,13 +12079,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName: string, arraySym: ts.Symbol ): { isValidBoundCheck: boolean; isVarModifiedBeforeAccess: boolean } { - const isValidBoundCheck = whileNode.expression - ? this.checkBoundCondition(whileNode.expression, loopVarName, arraySym) - : false; + const isValidBoundCheck = whileNode.expression ? + this.checkBoundCondition(whileNode.expression, loopVarName, arraySym) : + false; - const isVarModifiedBeforeAccess = whileNode.statement - ? TypeScriptLinter.checkVarModifiedBeforeNode(whileNode.statement, accessExpr, loopVarName) - : false; + const isVarModifiedBeforeAccess = whileNode.statement ? + TypeScriptLinter.checkVarModifiedBeforeNode(whileNode.statement, accessExpr, loopVarName) : + false; return { isValidBoundCheck, isVarModifiedBeforeAccess }; } @@ -12075,9 +12096,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName: string, arraySym: ts.Symbol ): { isValidBoundCheck: boolean; isVarModifiedBeforeAccess: boolean } { - const isValidBoundCheck = ifNode.expression - ? this.checkBoundCondition(ifNode.expression, loopVarName, arraySym) - : false; + const isValidBoundCheck = ifNode.expression ? + this.checkBoundCondition(ifNode.expression, loopVarName, arraySym) : + false; let isVarModifiedBeforeAccess = false; const statementBlock = ts.isBlock(ifNode.thenStatement) ? ifNode.thenStatement : undefined; @@ -12125,16 +12146,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isIdentifier(left) && left.text === varName && ts.isNumericLiteral(right)) { const value = parseFloat(right.text); return ( - (operatorToken.kind === ts.SyntaxKind.GreaterThanEqualsToken && value <= 0) || - (operatorToken.kind === ts.SyntaxKind.GreaterThanToken && value < 0) + operatorToken.kind === ts.SyntaxKind.GreaterThanEqualsToken && value <= 0 || + operatorToken.kind === ts.SyntaxKind.GreaterThanToken && value < 0 ); } if (ts.isPropertyAccessExpression(left) && left.name.text === LENGTH_IDENTIFIER && ts.isNumericLiteral(right)) { const constantValue = parseInt(right.text); return ( - (operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0) || - (operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0) + operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0 || + operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0 ); } @@ -12342,10 +12363,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const argType = this.tsTypeChecker.getTypeAtLocation(node); return ( (argType.flags & ts.TypeFlags.NumberLike) !== 0 || - (argType.isUnionOrIntersection() && + argType.isUnionOrIntersection() && argType.types.some((t) => { return t.flags & ts.TypeFlags.NumberLike; - })) + }) ); } @@ -12502,8 +12523,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const constantValue = parseInt(right.text); return ( - (operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0) || - (operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0) + operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0 || + operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0 ); } @@ -12582,7 +12603,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { accessExpr.parent.operatorToken.kind === ts.SyntaxKind.BarBarToken ) { const defaultValue = accessExpr.parent.right; - return ts.isNumericLiteral(defaultValue) || (ts.isIdentifier(defaultValue) && defaultValue.text === 'undefined'); + return ts.isNumericLiteral(defaultValue) || ts.isIdentifier(defaultValue) && defaultValue.text === 'undefined'; } return false; } diff --git a/ets2panda/linter/src/lib/utils/TsUtils.ts b/ets2panda/linter/src/lib/utils/TsUtils.ts index fb3a664f71..84bac15260 100644 --- a/ets2panda/linter/src/lib/utils/TsUtils.ts +++ b/ets2panda/linter/src/lib/utils/TsUtils.ts @@ -3862,16 +3862,16 @@ export class TsUtils { } } - isNumberArrayType(type: ts.Type): boolean { - if (!type.symbol || !this.isGenericArrayType(type)) { - return false; - } - - const typeArguments = this.tsTypeChecker.getTypeArguments(type as ts.TypeReference); - if (!typeArguments || typeArguments.length === 0) { - return false; - } + isNumberArrayType(type: ts.Type): boolean { + if (!type.symbol || !this.isGenericArrayType(type)) { + return false; + } - return (typeArguments[0].flags & ts.TypeFlags.Number) !== 0; + const typeArguments = this.tsTypeChecker.getTypeArguments(type); + if (!typeArguments || typeArguments.length === 0) { + return false; } + + return (typeArguments[0].flags & ts.TypeFlags.Number) !== 0; + } } diff --git a/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts b/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts index 67bafa00b4..a694f58fa0 100644 --- a/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts +++ b/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts @@ -25,3 +25,4 @@ export const STRINGLITERAL_ANY = 'ANY'; export const STRINGLITERAL_ENUM = 'enum'; export const STRINGLITERAL_FROM = 'from'; export const STRINGLITERAL_ARRAY = 'Array'; +export const STRINGLITERAL_INFINITY = 'Infinity'; diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets new file mode 100644 index 0000000000..7d07822085 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets @@ -0,0 +1,19 @@ +/* + * 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. + */ + +-Infinity !== -1 ; ++Infinity !== -1 ; +Infinity !== -1 ; +~Infinity !== -1 ; diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json new file mode 100644 index 0000000000..948b846fe0 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json @@ -0,0 +1,19 @@ +{ + "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." + ], + "mode": { + "arkts2": "" + } +} diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json new file mode 100644 index 0000000000..1a7e31f801 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json @@ -0,0 +1,28 @@ +{ + "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": 19, + "column": 1, + "endLine": 19, + "endColumn": 10, + "problem": "PrefixUnaryInfinity", + "suggest": "", + "rule": "The bitwise inversion gives different result for \"Infinity\" (arkts-distinct-infinity-bitwise-inversion)", + "severity": "ERROR" + } + ] +} diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json new file mode 100644 index 0000000000..9f305c86d7 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json @@ -0,0 +1,17 @@ +{ + "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": [] +} diff --git a/ets2panda/linter/test/main/index_negative.ets.arkts2.json b/ets2panda/linter/test/main/index_negative.ets.arkts2.json old mode 100755 new mode 100644 diff --git a/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json b/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json index fc7c0bef22..f7d3a8c29c 100644 --- a/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json +++ b/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json @@ -505,4 +505,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json b/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json index 132354c1a5..da7ce528c0 100644 --- a/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json +++ b/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json @@ -868,4 +868,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json b/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json index 8248685e05..713d6b80a9 100644 --- a/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json +++ b/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json @@ -255,4 +255,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json b/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json old mode 100755 new mode 100644 index 469e417b34..2d6e11c515 --- a/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json +++ b/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json @@ -1,6 +1,6 @@ { "copyright": [ - "Copyright (c) 2023-2025 Huawei Device Co., Ltd.", + "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", -- Gitee From e953e8121d5e268ff99a4196a01101cba5d4eaf7 Mon Sep 17 00:00:00 2001 From: beratagaca_9a91 Date: Thu, 31 Jul 2025 11:07:50 +0300 Subject: [PATCH 4/5] rule arkts-class-no-signature-distinct Description: rule impl and test cases added Issue: #ICPCSK Signed-off-by: beratagaca_9a91 --- ets2panda/linter/rule-config.json | 1 + ets2panda/linter/src/lib/CookBookMsg.ts | 2 + ets2panda/linter/src/lib/FaultAttrs.ts | 1 + ets2panda/linter/src/lib/FaultDesc.ts | 2 + ets2panda/linter/src/lib/Problems.ts | 1 + ets2panda/linter/src/lib/TypeScriptLinter.ts | 28 +++ .../src/lib/utils/consts/LimitedStdAPI.ts | 9 + ...rkts_class_no_signature_public_obj_api.ets | 106 ++++++++ ..._no_signature_public_obj_api.ets.args.json | 19 ++ ...o_signature_public_obj_api.ets.arkts2.json | 238 ++++++++++++++++++ ...class_no_signature_public_obj_api.ets.json | 28 +++ .../main/method_inheritance.ets.arkts2.json | 10 + 12 files changed, 445 insertions(+) create mode 100644 ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets create mode 100644 ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.args.json create mode 100644 ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json create mode 100644 ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.json diff --git a/ets2panda/linter/rule-config.json b/ets2panda/linter/rule-config.json index 4eb374948c..6400c2084a 100644 --- a/ets2panda/linter/rule-config.json +++ b/ets2panda/linter/rule-config.json @@ -60,6 +60,7 @@ "arkts-limited-stdlib-no-setTransferList", "arkts-builtin-object-getOwnPropertyNames", "arkts-no-class-omit-interface-optional-prop", + "arkts-class-no-signature-distinct-with-object-public-api", "arkts-no-sparse-array", "arkts-no-enum-prop-as-type", "arkts-no-ts-like-smart-type", diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index 55a46b8d68..7e8669926b 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -258,6 +258,8 @@ cookBookTag[212] = 'The index expression must be zero or positive value.(arkts-a cookBookTag[213] = 'Class cannot have static codeblocks. (arkts-class-lazy-import)'; cookBookTag[214] = 'Objects have no constructor property in ArkTS1.2 (arkts-obj-no-constructor)'; cookBookTag[215] = 'Array bound not checked. (arkts-runtime-array-check)'; +cookBookTag[216] = + 'The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)'; cookBookTag[222] = 'Import for side-effect only is prohibited.(arkts-no-side-effect-import)'; cookBookTag[232] = 'Lazy import is not supported(arkts-no-lazy-import)'; cookBookTag[233] = 'Dynamic import is not supported(arkts-no-dynamic-import)'; diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 818f79e0c9..5cbd4165d9 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -171,6 +171,7 @@ faultsAttrs[FaultID.IndexNegative] = new FaultAttributes(212); faultsAttrs[FaultID.NoStaticOnClass] = new FaultAttributes(213); faultsAttrs[FaultID.NoConstructorOnClass] = new FaultAttributes(214); faultsAttrs[FaultID.RuntimeArrayCheck] = new FaultAttributes(215); +faultsAttrs[FaultID.NoSignatureDistinctWithObjectPublicApi] = new FaultAttributes(216); faultsAttrs[FaultID.NoSideEffectImport] = new FaultAttributes(222); faultsAttrs[FaultID.ImportLazyIdentifier] = new FaultAttributes(232); faultsAttrs[FaultID.DynamicImport] = new FaultAttributes(233); diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index fa035e1595..6a57334c7f 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -71,6 +71,8 @@ faultDesc[FaultID.PropertyAccessByIndex] = 'property access by index'; faultDesc[FaultID.NoStaticOnClass] = 'No static blocks on classes'; faultDesc[FaultID.NoConstructorOnClass] = 'No constructor field on object'; faultDesc[FaultID.RuntimeArrayCheck] = 'Array bound not checked'; +faultDesc[FaultID.NoSignatureDistinctWithObjectPublicApi] = + 'Method’s signature in a class/interface must match the public interface of the object.'; faultDesc[FaultID.JsxElement] = 'JSX Elements'; faultDesc[FaultID.EnumMemberNonConstInit] = 'Enum members with non-constant initializer'; faultDesc[FaultID.ImplementsClass] = 'Class type mentioned in "implements" clause'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index 86086f6993..d29b7c987b 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -71,6 +71,7 @@ export enum FaultID { NoStaticOnClass, NoConstructorOnClass, RuntimeArrayCheck, + NoSignatureDistinctWithObjectPublicApi, MethodReassignment, MultipleStaticBlocks, ThisType, diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 0b4e850499..f05bfe360a 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -78,6 +78,7 @@ import { MODULE_IMPORTS, ARKTSUTILS_MODULES, ARKTSUTILS_LOCKS_MEMBER, + OBJECT_PUBLIC_API_METHOD_SIGNATURES, ARKTSUTILS_PROCESS_MEMBER, PROCESS_DEPRECATED_INTERFACES } from './utils/consts/LimitedStdAPI'; @@ -940,6 +941,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } this.countDeclarationsWithDuplicateName(interfaceNode.name, interfaceNode); this.handleLocalDeclarationOfClassAndIface(interfaceNode); + this.checkObjectPublicApiMethods(interfaceNode); } private handleTryStatement(node: ts.TryStatement): void { @@ -3345,6 +3347,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleSdkMethod(tsClassDecl); this.handleNotsLikeSmartType(tsClassDecl); this.handleLocalDeclarationOfClassAndIface(tsClassDecl); + this.checkObjectPublicApiMethods(tsClassDecl); } private static findFinalExpression(typeNode: ts.TypeNode): ts.Node { @@ -3851,6 +3854,31 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleNoDeprecatedApi(tsMethodDecl); } + private checkObjectPublicApiMethods(node: ts.ClassDeclaration | ts.InterfaceDeclaration): void { + if (!this.options.arkts2) { + return; + } + for (const member of node.members) { + if (!((ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) && ts.isIdentifier(member.name))) { + continue; + } + const methodName = member.name.text; + const expectedSignature = OBJECT_PUBLIC_API_METHOD_SIGNATURES.get(methodName); + if (!expectedSignature) { + continue; + } + const methodType = this.tsTypeChecker.getTypeAtLocation(member); + const signature = TsUtils.getFunctionalTypeSignature(methodType); + if (!signature) { + continue; + } + const actualSignature = this.tsTypeChecker.signatureToString(signature); + if (actualSignature !== expectedSignature) { + this.incrementCounters(member, FaultID.NoSignatureDistinctWithObjectPublicApi); + } + } + } + private handleLimitedVoidFunction(node: ts.FunctionLikeDeclaration): void { const typeNode = node.type; if (!typeNode || !ts.isUnionTypeNode(typeNode)) { diff --git a/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts b/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts index 5051185d47..5865c5a450 100644 --- a/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts +++ b/ets2panda/linter/src/lib/utils/consts/LimitedStdAPI.ts @@ -162,6 +162,15 @@ export const MODULE_IMPORTS: Record = { export const ARKTSUTILS_MODULES = ['@arkts.utils', '@ohos.process', '@kit.ArkTS']; export const ARKTSUTILS_LOCKS_MEMBER = 'locks'; + +export const OBJECT_PUBLIC_API_METHOD_SIGNATURES = new Map([ + ['toString', '(): string'], + ['toLocaleString', '(): string'], + ['valueOf', '(): Object'], + ['hasOwnProperty', '(v: PropertyKey): boolean'], + ['isPrototypeOf', '(v: Object): boolean'], + ['propertyIsEnumerable', '(v: PropertyKey): boolean'] +]); export const ARKTSUTILS_PROCESS_MEMBER = 'process'; export const PROCESS_DEPRECATED_INTERFACES = [ diff --git a/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets new file mode 100644 index 0000000000..b02afc3dcc --- /dev/null +++ b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets @@ -0,0 +1,106 @@ +/* + * 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. + */ + +class A1 { + toString(): string { // valid + return "ok"; + } + + toLocaleString(): string { // valid + return "ok"; + } + + valueOf(): number { // error + return 789; + } + + hasOwnProperty(): boolean { // error + return false; + } + + isPrototypeOf(v: Object): boolean { // valid + return true; + } + + propertyIsEnumerable(v: PropertyKey): boolean { // valid + return false; + } +} + +class A2 { + customFunc(): void {} // valid + + toString(): number {return 123;} // error + + toLocaleString(): number { // error + return 456; + } + + valueOf(): Object { // valid + return {}; + } + + hasOwnProperty(v: PropertyKey): boolean { // valid + return true; + } + + isPrototypeOf(v: string): boolean { // error + return false; + } + + propertyIsEnumerable(v: PropertyKey): string { // error + return "not boolean"; + } +} + +class A3 { + toString(): string { return "ok"; } // valid + valueOf(): number { return 123; } // error +} + +class A4 { + customFunc(): void {} // valid + valueOf(): number { return 123; } // error + toString(): string { return "ok"; } // valid +} + +interface I1 { + toString(): string; // valid + toLocaleString(): number; // error + valueOf(): number; // error + customFunc(): boolean; // valid + hasOwnProperty(v: PropertyKey): boolean; // valid + isPrototypeOf(v: Object): boolean; // valid + propertyIsEnumerable(v: PropertyKey): boolean; // valid +} + +interface I2 { + toString(): boolean; // error + toLocaleString(): string; // valid + valueOf(): Object; // valid + hasOwnProperty(): boolean; // error + isPrototypeOf(v: string): boolean; // error + propertyIsEnumerable(v: PropertyKey): string; // error +} + +interface I3 { + toString(): string; // valid + valueOf(): number; // error +} + +interface I4 { + valueOf(): number; // error + toString(): string; // valid +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.args.json b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.args.json new file mode 100644 index 0000000000..1b80aa9e73 --- /dev/null +++ b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.args.json @@ -0,0 +1,19 @@ +{ + "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." + ], + "mode": { + "arkts2": "" + } + } \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json new file mode 100644 index 0000000000..e8e7a47f64 --- /dev/null +++ b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json @@ -0,0 +1,238 @@ +{ + "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": 25, + "column": 3, + "endLine": 27, + "endColumn": 4, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 29, + "column": 3, + "endLine": 31, + "endColumn": 4, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 26, + "column": 12, + "endLine": 26, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 45, + "column": 3, + "endLine": 45, + "endColumn": 35, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 47, + "column": 3, + "endLine": 49, + "endColumn": 4, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 59, + "column": 3, + "endLine": 61, + "endColumn": 4, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 63, + "column": 3, + "endLine": 65, + "endColumn": 4, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 45, + "column": 30, + "endLine": 45, + "endColumn": 33, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 48, + "column": 12, + "endLine": 48, + "endColumn": 15, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 52, + "column": 12, + "endLine": 52, + "endColumn": 13, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + }, + { + "line": 70, + "column": 3, + "endLine": 70, + "endColumn": 36, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 70, + "column": 30, + "endLine": 70, + "endColumn": 33, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 75, + "column": 3, + "endLine": 75, + "endColumn": 36, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 75, + "column": 30, + "endLine": 75, + "endColumn": 33, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 81, + "column": 3, + "endLine": 81, + "endColumn": 28, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 82, + "column": 3, + "endLine": 82, + "endColumn": 21, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 90, + "column": 3, + "endLine": 90, + "endColumn": 23, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 93, + "column": 3, + "endLine": 93, + "endColumn": 29, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 94, + "column": 3, + "endLine": 94, + "endColumn": 37, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 95, + "column": 3, + "endLine": 95, + "endColumn": 48, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 100, + "column": 3, + "endLine": 100, + "endColumn": 21, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, + { + "line": 104, + "column": 3, + "endLine": 104, + "endColumn": 21, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.json b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.json new file mode 100644 index 0000000000..84b96b7788 --- /dev/null +++ b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.json @@ -0,0 +1,28 @@ +{ + "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": 52, + "column": 12, + "endLine": 52, + "endColumn": 13, + "problem": "ObjectLiteralNoContextType", + "suggest": "", + "rule": "Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals)", + "severity": "ERROR" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/method_inheritance.ets.arkts2.json b/ets2panda/linter/test/main/method_inheritance.ets.arkts2.json index 7a9d5b7dab..54216cf950 100644 --- a/ets2panda/linter/test/main/method_inheritance.ets.arkts2.json +++ b/ets2panda/linter/test/main/method_inheritance.ets.arkts2.json @@ -224,6 +224,16 @@ "rule": "Overridden method parameters and return types must respect type inheritance principles (arkts-method-inherit-rule)", "severity": "ERROR" }, + { + "line": 224, + "column": 3, + "endLine": 226, + "endColumn": 4, + "problem": "NoSignatureDistinctWithObjectPublicApi", + "suggest": "", + "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", + "severity": "ERROR" + }, { "line": 266, "column": 9, -- Gitee From 4ca5b494e321700f7845930b4748439033f33c35 Mon Sep 17 00:00:00 2001 From: Raif Mirza Erten Date: Mon, 4 Aug 2025 10:33:22 +0300 Subject: [PATCH 5/5] arkts-use-long-for-large-numeric-literal Issue: #ICPJER Description: arkts-use-long-for-large-numeric-literal rule implementation Signed-off-by: Raif Mirza Erten --- ets2panda/linter/rule-config.json | 1 + ets2panda/linter/src/lib/CookBookMsg.ts | 3 +- ets2panda/linter/src/lib/FaultAttrs.ts | 1 + ets2panda/linter/src/lib/FaultDesc.ts | 1 + ets2panda/linter/src/lib/Problems.ts | 1 + ets2panda/linter/src/lib/TypeScriptLinter.ts | 26 +++++++++- ets2panda/linter/src/lib/utils/TsUtils.ts | 17 +++++++ .../lib/utils/consts/NumericalConstants.ts | 17 +++++++ ...nt_process_deprecated_apis.ets.arkts2.json | 10 ++++ ..._sharedarraybuffer1_arkts2.ets.arkts2.json | 2 +- ...sharedarraybuffer1_arkts2.ets.autofix.json | 2 +- ..._sharedarraybuffer1_arkts2.ets.migrate.ets | 0 ...t-tuple-generic-validation.ets.arkts2.json | 10 ---- ...arkts-obj-literal-key-type.ets.arkts2.json | 2 +- ...rkts-require-func-arg-type.ets.arkts2.json | 2 +- ...kts-use-long-for-large-numeric-literal.ets | 23 +++++++++ ...ng-for-large-numeric-literal.ets.args.json | 19 +++++++ ...-for-large-numeric-literal.ets.arkts2.json | 48 ++++++++++++++++++ ...se-long-for-large-numeric-literal.ets.json | 17 +++++++ ...o_signature_public_obj_api.ets.arkts2.json | 50 ------------------- .../test/main/comment_test.ets.arkts2.json | 2 +- .../main/invalid_identifier.ets.arkts2.json | 2 +- .../no_import_concurrency.ets.arkts2.json | 2 +- 23 files changed, 189 insertions(+), 69 deletions(-) create mode 100644 ets2panda/linter/src/lib/utils/consts/NumericalConstants.ts mode change 100755 => 100644 ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.migrate.ets create mode 100644 ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets create mode 100644 ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.args.json create mode 100644 ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.arkts2.json create mode 100644 ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.json diff --git a/ets2panda/linter/rule-config.json b/ets2panda/linter/rule-config.json index 6400c2084a..b4a9e330ed 100644 --- a/ets2panda/linter/rule-config.json +++ b/ets2panda/linter/rule-config.json @@ -21,6 +21,7 @@ "arkts-no-template-string-type", "arkts-obj-literal-key-type", "arkts-optional-methods", + "arkts-use-long-for-large-numeric-literal", "arkts-numeric-semantic", "arkts-incompatible-function-types", "arkts-limited-void-type", diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index 7e8669926b..3aafa7ae52 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -106,7 +106,8 @@ cookBookTag[74] = 'Destructuring variable declarations are not supported (arkts- cookBookTag[75] = 'Use string-literal keys with Record (arkts-obj-literal-key-type)'; cookBookTag[76] = 'Type of parameter must be defined explicitly (arkts-require-func-arg-type)'; cookBookTag[77] = 'Template string type is not supported (arkts-no-template-string-type)'; -cookBookTag[78] = ''; +cookBookTag[78] = + 'Numeric value literals outside of integer range require long representation (arkts-use-long-for-large-numeric-literal)'; cookBookTag[79] = 'Type annotation in catch clause is not supported (arkts-no-types-in-catch)'; cookBookTag[80] = '"for .. in" is not supported (arkts-no-for-in)'; cookBookTag[81] = ''; diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 5cbd4165d9..85ce65627c 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -65,6 +65,7 @@ faultsAttrs[FaultID.InOperator] = new FaultAttributes(66); faultsAttrs[FaultID.DestructuringAssignment] = new FaultAttributes(69); faultsAttrs[FaultID.CommaOperator] = new FaultAttributes(71); faultsAttrs[FaultID.DestructuringDeclaration] = new FaultAttributes(74); +faultsAttrs[FaultID.LongNumeric] = new FaultAttributes(78); faultsAttrs[FaultID.ObjectLiteralKeyType] = new FaultAttributes(75); faultsAttrs[FaultID.ParameterType] = new FaultAttributes(76); faultsAttrs[FaultID.TemplateStringType] = new FaultAttributes(77); diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index 6a57334c7f..5f0de591dd 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -89,6 +89,7 @@ faultDesc[FaultID.ParameterProperties] = 'Parameter properties in constructor'; faultDesc[FaultID.InstanceofUnsupported] = 'Left-hand side of "instanceof" is wrong'; faultDesc[FaultID.TemplateStringType] = 'Template string type'; faultDesc[FaultID.ShorthandAmbientModuleDecl] = 'Shorthand ambient module declaration'; +faultDesc[FaultID.LongNumeric] = 'Use long for big numbers'; faultDesc[FaultID.WildcardsInModuleName] = 'Wildcards in module name'; faultDesc[FaultID.UMDModuleDefinition] = 'UMD module definition'; faultDesc[FaultID.NewTarget] = '"new.target" meta-property'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index d29b7c987b..891835e1cb 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -181,6 +181,7 @@ export enum FaultID { NoImportNamespaceStarAsVar, ExtendsExpression, NumericSemantics, + LongNumeric, AnimatableExtendDecoratorTransform, NoDuplicateFunctionName, OhmUrlFullPath, diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index f05bfe360a..3f2e5be9d6 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -448,7 +448,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { [ts.SyntaxKind.TypeOfExpression, this.handleInterOpImportJsOnTypeOfNode], [ts.SyntaxKind.AwaitExpression, this.handleAwaitExpression], [ts.SyntaxKind.PostfixUnaryExpression, this.handlePostfixUnaryExpression], - [ts.SyntaxKind.BigIntLiteral, this.handleBigIntLiteral] + [ts.SyntaxKind.BigIntLiteral, this.handleBigIntLiteral], + [ts.SyntaxKind.NumericLiteral, this.handleNumericLiteral] ]); lint(): void { @@ -11914,6 +11915,29 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return binaryOperators.includes(kind); } + private handleNumericLiteral(node: ts.Node): void { + if (!this.options.arkts2 || !ts.isNumericLiteral(node)) { + return; + } + this.handleLargeNumericLiteral(node); + } + + private handleLargeNumericLiteral(node: ts.NumericLiteral): void { + const parent = node.parent; + const isPrefix = ts.isPrefixUnaryExpression(parent) && parent.operator === ts.SyntaxKind.MinusToken; + + const type = isPrefix ? this.tsTypeChecker.getContextualType(parent) : this.tsTypeChecker.getContextualType(node); + const isLarge = TsUtils.ifLargerThanInt(node, isPrefix); + if (!isLarge) { + return; + } + const isLong = this.tsUtils.isStdLongType(type); + if (isLong) { + return; + } + this.incrementCounters(node, FaultID.LongNumeric); + } + private checkArrayUsageWithoutBound(accessExpr: ts.ElementAccessExpression): void { if (this.shouldSkipArrayBoundCheck(accessExpr)) { return; diff --git a/ets2panda/linter/src/lib/utils/TsUtils.ts b/ets2panda/linter/src/lib/utils/TsUtils.ts index 84bac15260..6eafedeaf4 100644 --- a/ets2panda/linter/src/lib/utils/TsUtils.ts +++ b/ets2panda/linter/src/lib/utils/TsUtils.ts @@ -47,6 +47,7 @@ import { STRINGLITERAL_NUMBER, STRINGLITERAL_NUMBER_ARRAY } from './consts/Strin import { ETS_MODULE, PATH_SEPARATOR, VALID_OHM_COMPONENTS_MODULE_PATH } from './consts/OhmUrl'; import { EXTNAME_ETS, EXTNAME_JS, EXTNAME_D_ETS } from './consts/ExtensionName'; import { CONCAT_ARRAY, STRING_ERROR_LITERAL } from './consts/Literals'; +import { INT_MIN, INT_MAX } from './consts/NumericalConstants'; export const PROMISE_METHODS = new Set(['all', 'race', 'any', 'resolve', 'allSettled']); export const PROMISE_METHODS_WITH_NO_TUPLE_SUPPORT = new Set(['all', 'race', 'any', 'allSettled']); @@ -55,6 +56,7 @@ export const SYMBOL_CONSTRUCTOR = 'SymbolConstructor'; const ITERATOR = 'iterator'; export type CheckType = (this: TsUtils, t: ts.Type) => boolean; + export class TsUtils { constructor( private readonly tsTypeChecker: ts.TypeChecker, @@ -1670,6 +1672,21 @@ export class TsUtils { return false; } + isStdLongType(type: ts.Type | undefined): boolean { + if (!type) { + return false; + } + const sym = type.aliasSymbol; + return !!sym && sym.getName() === 'long' && this.isGlobalSymbol(sym); + } + + static ifLargerThanInt(node: ts.NumericLiteral, isPrefix: boolean): boolean { + const raw = node.getText(); + const value = isPrefix ? Number(raw) * -1 : Number(raw); + + return value < INT_MIN || value > INT_MAX; + } + isStdErrorType(type: ts.Type): boolean { const symbol = type.symbol; if (!symbol) { diff --git a/ets2panda/linter/src/lib/utils/consts/NumericalConstants.ts b/ets2panda/linter/src/lib/utils/consts/NumericalConstants.ts new file mode 100644 index 0000000000..f15e7fc233 --- /dev/null +++ b/ets2panda/linter/src/lib/utils/consts/NumericalConstants.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export const INT_MIN = -2147483648; +export const INT_MAX = 2147483647; diff --git a/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json index 56cdb58228..2001c8e9d6 100644 --- a/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json +++ b/ets2panda/linter/test/concurrent/concurrent_process_deprecated_apis.ets.arkts2.json @@ -14,6 +14,16 @@ "limitations under the License." ], "result": [ + { + "line": 16, + "column": 10, + "endLine": 16, + "endColumn": 17, + "problem": "LimitedStdLibNoImportConcurrency", + "suggest": "", + "rule": "Import Concurrency is not required (arkts-limited-stdlib-no-import-concurrency)", + "severity": "ERROR" + }, { "line": 19, "column": 1, diff --git a/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.arkts2.json b/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.arkts2.json index f5a7495916..1f7540062c 100755 --- a/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.arkts2.json +++ b/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.arkts2.json @@ -45,4 +45,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.autofix.json b/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.autofix.json index f5a7495916..1f7540062c 100755 --- a/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.autofix.json +++ b/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.autofix.json @@ -45,4 +45,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.migrate.ets b/ets2panda/linter/test/concurrent/concurrent_sharedarraybuffer1_arkts2.ets.migrate.ets old mode 100755 new mode 100644 diff --git a/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json index 25c25de79c..52c316a716 100644 --- a/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json +++ b/ets2panda/linter/test/main/arkts-not-support-tuple-generic-validation.ets.arkts2.json @@ -34,16 +34,6 @@ "rule": "Type inference in case of generic function calls is limited (arkts-no-inferred-generic-params)", "severity": "ERROR" }, - { - "line": 17, - "column": 60, - "endLine": 17, - "endColumn": 61, - "problem": "NumericSemantics", - "suggest": "", - "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", - "severity": "ERROR" - }, { "line": 19, "column": 13, diff --git a/ets2panda/linter/test/main/arkts-obj-literal-key-type.ets.arkts2.json b/ets2panda/linter/test/main/arkts-obj-literal-key-type.ets.arkts2.json index 74e12d3c6c..dbdffd0677 100644 --- a/ets2panda/linter/test/main/arkts-obj-literal-key-type.ets.arkts2.json +++ b/ets2panda/linter/test/main/arkts-obj-literal-key-type.ets.arkts2.json @@ -95,4 +95,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/arkts-require-func-arg-type.ets.arkts2.json b/ets2panda/linter/test/main/arkts-require-func-arg-type.ets.arkts2.json index a7d0a1a9ba..ebc344bf04 100644 --- a/ets2panda/linter/test/main/arkts-require-func-arg-type.ets.arkts2.json +++ b/ets2panda/linter/test/main/arkts-require-func-arg-type.ets.arkts2.json @@ -115,4 +115,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets new file mode 100644 index 0000000000..c8771f9e4e --- /dev/null +++ b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets @@ -0,0 +1,23 @@ +/* + * 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. + */ + +console.log(0xcafebabe) +const a : long = 3405691582; +const b = 3405691582; +const c : long = 2342343; +const d = 123; +const e = -2147483649; +const f : long = -2147483649; +const g = 0x0b101010; diff --git a/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.args.json b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.args.json new file mode 100644 index 0000000000..66fb88f859 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.args.json @@ -0,0 +1,19 @@ +{ + "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." + ], + "mode": { + "arkts2": "" + } +} diff --git a/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.arkts2.json b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.arkts2.json new file mode 100644 index 0000000000..b6ac079e4b --- /dev/null +++ b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.arkts2.json @@ -0,0 +1,48 @@ +{ + "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": 16, + "column": 13, + "endLine": 16, + "endColumn": 23, + "problem": "LongNumeric", + "suggest": "", + "rule": "Numeric value literals outside of integer range require long representation (arkts-use-long-for-large-numeric-literal)", + "severity": "ERROR" + }, + { + "line": 18, + "column": 11, + "endLine": 18, + "endColumn": 21, + "problem": "LongNumeric", + "suggest": "", + "rule": "Numeric value literals outside of integer range require long representation (arkts-use-long-for-large-numeric-literal)", + "severity": "ERROR" + }, + { + "line": 21, + "column": 12, + "endLine": 21, + "endColumn": 22, + "problem": "LongNumeric", + "suggest": "", + "rule": "Numeric value literals outside of integer range require long representation (arkts-use-long-for-large-numeric-literal)", + "severity": "ERROR" + } + ] +} diff --git a/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.json b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.json new file mode 100644 index 0000000000..9f305c86d7 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-use-long-for-large-numeric-literal.ets.json @@ -0,0 +1,17 @@ +{ + "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": [] +} diff --git a/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json index e8e7a47f64..0352c42e8b 100644 --- a/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json +++ b/ets2panda/linter/test/main/arkts_class_no_signature_public_obj_api.ets.arkts2.json @@ -34,16 +34,6 @@ "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", "severity": "ERROR" }, - { - "line": 26, - "column": 12, - "endLine": 26, - "endColumn": 15, - "problem": "NumericSemantics", - "suggest": "", - "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", - "severity": "ERROR" - }, { "line": 45, "column": 3, @@ -84,26 +74,6 @@ "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", "severity": "ERROR" }, - { - "line": 45, - "column": 30, - "endLine": 45, - "endColumn": 33, - "problem": "NumericSemantics", - "suggest": "", - "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", - "severity": "ERROR" - }, - { - "line": 48, - "column": 12, - "endLine": 48, - "endColumn": 15, - "problem": "NumericSemantics", - "suggest": "", - "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", - "severity": "ERROR" - }, { "line": 52, "column": 12, @@ -124,16 +94,6 @@ "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", "severity": "ERROR" }, - { - "line": 70, - "column": 30, - "endLine": 70, - "endColumn": 33, - "problem": "NumericSemantics", - "suggest": "", - "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", - "severity": "ERROR" - }, { "line": 75, "column": 3, @@ -144,16 +104,6 @@ "rule": "The signature of a method in a class/interface cannot be different from the public interface in an object. (arkts-class-no-signature-distinct-with-object-public-api)", "severity": "ERROR" }, - { - "line": 75, - "column": 30, - "endLine": 75, - "endColumn": 33, - "problem": "NumericSemantics", - "suggest": "", - "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", - "severity": "ERROR" - }, { "line": 81, "column": 3, diff --git a/ets2panda/linter/test/main/comment_test.ets.arkts2.json b/ets2panda/linter/test/main/comment_test.ets.arkts2.json index ca88f857e9..9f305c86d7 100644 --- a/ets2panda/linter/test/main/comment_test.ets.arkts2.json +++ b/ets2panda/linter/test/main/comment_test.ets.arkts2.json @@ -14,4 +14,4 @@ "limitations under the License." ], "result": [] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/invalid_identifier.ets.arkts2.json b/ets2panda/linter/test/main/invalid_identifier.ets.arkts2.json index a2e462d71d..9a3582fd08 100644 --- a/ets2panda/linter/test/main/invalid_identifier.ets.arkts2.json +++ b/ets2panda/linter/test/main/invalid_identifier.ets.arkts2.json @@ -925,4 +925,4 @@ "severity": "ERROR" } ] -} +} \ No newline at end of file diff --git a/ets2panda/linter/test/main/no_import_concurrency.ets.arkts2.json b/ets2panda/linter/test/main/no_import_concurrency.ets.arkts2.json index e5e0606299..596eceebd8 100644 --- a/ets2panda/linter/test/main/no_import_concurrency.ets.arkts2.json +++ b/ets2panda/linter/test/main/no_import_concurrency.ets.arkts2.json @@ -185,4 +185,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} -- Gitee