diff --git a/ets2panda/linter/homecheck/package.json b/ets2panda/linter/homecheck/package.json index ae47a9e950e04f2fffdffb639519b65f7ac3138f..d6345b08fc34e4bd4c98f2502359099292656eab 100644 --- a/ets2panda/linter/homecheck/package.json +++ b/ets2panda/linter/homecheck/package.json @@ -1,6 +1,5 @@ { "scripts": { - "installArkAnalyzer": "bash ./scripts/install_arkanalyzer.sh", "compile": "tsc -p ./tsconfig.prod.json", "test": "vitest --no-color run", "coverage": "vitest run --coverage", diff --git a/ets2panda/linter/homecheck/scripts/install_arkanalyzer.sh b/ets2panda/linter/homecheck/scripts/install_arkanalyzer.sh deleted file mode 100644 index 282d190c670e4295438767188c996c864deea436..0000000000000000000000000000000000000000 --- a/ets2panda/linter/homecheck/scripts/install_arkanalyzer.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# 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. -# - -set -x - -# install and pack dependency arkanalyzer -cd ../arkanalyzer -npm install - -cp package.json package.json.bak - -sed -i '/postinstall/d' package.json -npm pack - -TAR_FILE=$(find . -maxdepth 1 -name "arkanalyzer-*.tgz" -print0) -cd ../homecheck -npm install ../arkanalyzer/$TAR_FILE - -# revert the project files -mv ../arkanalyzer/package.json.bak ../arkanalyzer/package.json -rm ../arkanalyzer/$TAR_FILE diff --git a/ets2panda/linter/homecheck/scripts/run_ci_ut.sh b/ets2panda/linter/homecheck/scripts/run_ci_ut.sh deleted file mode 100644 index 56f455f87bfec03844eb6ea991bb9669ff4b7d15..0000000000000000000000000000000000000000 --- a/ets2panda/linter/homecheck/scripts/run_ci_ut.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# Copyright (c) 2024 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. -# - -set -x - -if [ -z "${ROOT_DIR+x}" ]; then - export ROOT_DIR=$(pwd) - echo "ROOT_DIR was not set. Initialized to $ROOT_DIR" -else - echo "ROOT_DIR is already set to $ROOT_DIR" -fi - -NODE_VERSION=v22.3.0 -NODE_HOME=$ROOT_DIR/pre_scripts/node-$NODE_VERSION-linux-x64 -NODE_URL=https://gitee.com/muya318/pre_scripts/raw/master/node-v22.3.0-linux-x64.tar.gz -NODE_BIN=node-v22.3.0-linux-x64.tar.gz - -prepare_nodejs() { - echo "### preparing nodejs" - if [ ! -d "$NODE_HOME" ]; then - cd $ROOT_DIR/pre_scripts - tar -xf $NODE_BIN - chmod 777 $NODE_HOME/bin/* - cd - - export PATH=$NODE_HOME/bin:$PATH - fi - npm config set registry=https://repo.huaweicloud.com/repository/npm/ - npm config set strict-ssl false - echo "###nodejs env ready" -} - -git clone https://gitee.com/muya318/pre_scripts.git - -prepare_nodejs - -pwd -cd $ROOT_DIR - -node -v -npm -v - -npm install -npm run test - -if [ $? -ne 0 ]; then - echo "************* Unit test failed *************" - exit 1 -fi - -echo "************* Unit test success *************" - -npm pack -if [ $? -ne 0 ]; then - echo "************* Npm pack failed *************" - exit 1 -fi -echo "************* Npm pack success *************" - -exit 0 \ No newline at end of file diff --git a/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts index 59c04a84d8ba0ee9b07e916f30e9a6d23dfaa4c4..b492f1fcc66e5171900eb786c6bc49ba9f2d3216 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/ObservedDecoratorCheck.ts @@ -31,7 +31,7 @@ import { import { ClassCategory } from 'arkanalyzer/lib/core/model/ArkClass'; import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; import { BaseChecker, BaseMetaData } from '../BaseChecker'; -import { Rule, Defects, ClassMatcher, MatcherTypes, MatcherCallback } from '../../Index'; +import { ClassMatcher, Defects, MatcherCallback, MatcherTypes, Rule } from '../../Index'; import { IssueReport } from '../../model/Defects'; import { RuleFix } from '../../model/Fix'; import { FixUtils } from '../../utils/common/FixUtils'; @@ -85,8 +85,6 @@ export class ObservedDecoratorCheck implements BaseChecker { } // usedClasses用于记录field的初始化中涉及的所有class let usedClasses: Set = new Set(); - // issueClasses用于记录usedClasses以及他们的所有父类 - let issueClasses: Set = new Set(); // ArkAnalyzer此处有问题,若field的类型注解为unclear type,会用右边的替换左边的。 const fieldType = field.getType(); // 此处仅对field为class类型进行检查,包含class和interface,非class类型不在本规则检查范围之内 @@ -94,10 +92,20 @@ export class ObservedDecoratorCheck implements BaseChecker { continue; } const initializers = field.getInitializer(); - let canFindAllTargets = true; - let locals: Set = new Set(); + // field无初始化的场景,对field的类型进行检查 + if (initializers.length === 0) { + const fieldTypeClass = scene.getClass(fieldType.getClassSignature()); + if (fieldTypeClass === null || fieldTypeClass.getCategory() !== ClassCategory.CLASS) { + continue; + } + usedClasses.add(fieldTypeClass); + this.handleAllUsedClasses(field, usedClasses); + continue; + } + let canFindAllTargets = true; + let locals: Set = new Set(); // field的初始化语句的最后一句,一定是将右边的value赋值给field,此处仍然判断一次,排除其他场景或者初始化语句为空的场景 const lastStmt = initializers[initializers.length - 1]; if (!(lastStmt instanceof ArkAssignStmt)) { @@ -128,31 +136,14 @@ export class ObservedDecoratorCheck implements BaseChecker { // 此处需要区分field = new cls()和field = {}两种场景,查找完毕需继续遍历stmts以解析条件表达式造成的多赋值场景 canFindAllTargets = canFindAllTargets && this.handleNewExpr(scene, fieldType, rightOp, usedClasses, projectName); } else if (rightOp instanceof AbstractInvokeExpr) { - canFindAllTargets = - canFindAllTargets && this.handleInvokeExpr(scene, fieldType, rightOp, usedClasses, projectName); + canFindAllTargets = canFindAllTargets && this.handleInvokeExpr(scene, fieldType, rightOp, usedClasses, projectName); } else { // 对应场景为使用条件表达式cond ? 123 : 456赋值时 continue; } } - for (const cls of usedClasses) { - issueClasses.add(cls); - this.getAllSuperClasses( - cls, - superCls => superCls.getCategory() === ClassCategory.CLASS && issueClasses.add(superCls) - ); - } - - for (const target of issueClasses) { - if (target.hasDecorator('Observed')) { - continue; - } - const pos = this.getClassPos(target); - const description = this.generateIssueDescription(field, target); - const ruleFix = this.generateRuleFix(pos, target) ?? undefined; - this.addIssueReport(pos, description, ruleFix); - } + this.handleAllUsedClasses(field, usedClasses); if (!canFindAllTargets) { const pos = this.getFieldPos(field); @@ -162,6 +153,25 @@ export class ObservedDecoratorCheck implements BaseChecker { } }; + private handleAllUsedClasses(field: ArkField, usedClasses: Set): void { + // issueClasses用于记录usedClasses以及他们的所有父类 + let issueClasses: Set = new Set(); + for (const cls of usedClasses) { + issueClasses.add(cls); + this.getAllSuperClasses(cls, superCls => superCls.getCategory() === ClassCategory.CLASS && issueClasses.add(superCls)); + } + + for (const target of issueClasses) { + if (target.hasDecorator('Observed')) { + continue; + } + const pos = this.getClassPos(target); + const description = this.generateIssueDescription(field, target); + const ruleFix = this.generateRuleFix(pos, target) ?? undefined; + this.addIssueReport(pos, description, ruleFix); + } + } + // 此处需要区分field = new cls()和field = {}两种场景 // 对于field = new cls()场景,需要查找此右边class的所有父class // 对于field = {}场景,需要查找左边field类型为class时的所有父class @@ -170,6 +180,7 @@ export class ObservedDecoratorCheck implements BaseChecker { if (target === null) { return false; } + // class为非本项目的内容时,表示调用到三方库、SDK等内容,不再继续进行查找 if (target.getDeclaringArkFile().getProjectName() !== projectName) { return true; @@ -210,13 +221,7 @@ export class ObservedDecoratorCheck implements BaseChecker { // 此处需要区分返回值为class和object literal两种场景 // 对于返回值为class的场景,需要查找此class的所有父class // 对于存在返回值为object literal的场景,需要查找左边field类型为class时的所有父class - private handleInvokeExpr( - scene: Scene, - fieldType: Type, - invokeExpr: AbstractInvokeExpr, - targets: Set, - projectName: string - ): boolean { + private handleInvokeExpr(scene: Scene, fieldType: Type, invokeExpr: AbstractInvokeExpr, targets: Set, projectName: string): boolean { let canFindAllTargets = true; const callMethod = scene.getMethod(invokeExpr.getMethodSignature()); if (callMethod === null) { @@ -278,11 +283,7 @@ export class ObservedDecoratorCheck implements BaseChecker { } } - private generateIssueDescription( - field: ArkField, - issueClass: ArkClass | null, - canFindAllTargets: boolean = true - ): string { + private generateIssueDescription(field: ArkField, issueClass: ArkClass | null, canFindAllTargets: boolean = true): string { if (issueClass === null || !canFindAllTargets) { return `can not find all classes, please check this field manually (arkui-data-observation)`; }