diff --git a/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts b/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts index 4a15f6af6a981db97dcc499e167d5a5bcce39434..140b4e81e349c9258aa046ba8f27d1e58e1d3788 100644 --- a/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts +++ b/ets2panda/linter/homecheck/src/checker/migration/InteropAssignCheck.ts @@ -29,6 +29,10 @@ import { ArkNamespace, PrimitiveType, UnclearReferenceType, + AnyType, + UnionType, + NullType, + UndefinedType, } from 'arkanalyzer/lib'; import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; import { BaseChecker, BaseMetaData } from '../BaseChecker'; @@ -93,7 +97,7 @@ export class InteropAssignCheck implements BaseChecker { } } - private checkPassToFunction(target: ArkMethod, scene: Scene) { + private checkPassToFunction(target: ArkMethod, scene: Scene): void { const callsites = this.cg.getInvokeStmtByMethod(target.getSignature()); callsites .filter(cs => cs.getCfg().getDeclaringMethod().getLanguage() === Language.ARKTS1_1) @@ -101,11 +105,15 @@ export class InteropAssignCheck implements BaseChecker { let hasTargetArg = false; const invoke = cs.getInvokeExpr()!; const csMethod = cs.getCfg().getDeclaringMethod(); - invoke.getArgs().forEach(arg => { + invoke.getArgs().forEach((arg, argIdx) => { const argTy = arg.getType(); if (argTy instanceof PrimitiveType || this.isBoxedType(argTy)) { return; } + const paramTy = invoke.getMethodSignature().getMethodSubSignature().getParameterTypes()[argIdx]; + if (this.isAnyType(paramTy) || this.isESObjectType(paramTy)) { + return; + } const argTyLang = this.getTypeDefinedLang(argTy, scene) ?? csMethod?.getLanguage() ?? Language.UNKNOWN; if (argTyLang === Language.ARKTS1_1) { hasTargetArg = true; @@ -126,13 +134,35 @@ export class InteropAssignCheck implements BaseChecker { }); } + private isAnyType(ty: Type): boolean { + return ty instanceof AnyType || (ty instanceof UnclearReferenceType && ty.getName() === 'Any'); + } + + private isESObjectType(ty: Type): boolean { + if (!(ty instanceof UnionType)) { + return false; + } + const types = ty.getTypes(); + if (types.length !== 3) { + return false; + } + const isObjectTy = (type: Type): boolean => { + return type instanceof ClassType && type.getClassSignature().getClassName() === 'Object'; + }; + return ( + types.find(ty => ty instanceof NullType) !== undefined && + types.find(ty => ty instanceof UndefinedType) !== undefined && + types.find(ty => isObjectTy(ty)) !== undefined + ); + } + private isBoxedType(checkType: Type): boolean { const unclear = checkType instanceof UnclearReferenceType && BOXED_SET.has(checkType.getName()); const cls = checkType instanceof ClassType && BOXED_SET.has(checkType.getClassSignature().getClassName()); return unclear || cls; } - private checkAssignToField(target: ArkMethod, scene: Scene) { + private checkAssignToField(target: ArkMethod, scene: Scene): void { const assigns: Stmt[] = this.collectAssignToObjectField(target, scene); if (assigns.length > 0) { DVFGHelper.buildSingleDVFG(target, scene);