1/* 2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15import { ArkMethod } from '../model/ArkMethod'; 16import { 17 AliasType, 18 AnnotationNamespaceType, 19 AnyType, 20 ArrayType, 21 ClassType, 22 FunctionType, 23 GenericType, 24 LexicalEnvType, 25 NullType, 26 Type, 27 UnclearReferenceType, 28 UndefinedType, 29 UnionType, 30 UnknownType, 31} from '../base/Type'; 32import { Local } from '../base/Local'; 33import { TypeInference } from './TypeInference'; 34import { 35 AbstractExpr, 36 AbstractInvokeExpr, 37 AliasTypeExpr, 38 ArkInstanceInvokeExpr, 39 ArkPtrInvokeExpr, 40 ArkStaticInvokeExpr 41} from '../base/Expr'; 42import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; 43import { Scene } from '../../Scene'; 44import { ArkClass } from '../model/ArkClass'; 45import { findArkExport, ModelUtils } from './ModelUtils'; 46import { ArkField, FieldCategory } from '../model/ArkField'; 47import { CALL_BACK } from './EtsConst'; 48import { 49 AliasClassSignature, 50 BaseSignature, 51 ClassSignature, 52 FieldSignature, FileSignature, 53 MethodSignature, 54 MethodSubSignature 55} from '../model/ArkSignature'; 56import { CONSTRUCTOR_NAME, FUNCTION, IMPORT, SUPER_NAME, THIS_NAME } from './TSConst'; 57import { Builtin } from './Builtin'; 58import { ArkBody } from '../model/ArkBody'; 59import { ArkAssignStmt, ArkInvokeStmt } from '../base/Stmt'; 60import { 61 AbstractFieldRef, 62 AbstractRef, 63 ArkArrayRef, 64 ArkInstanceFieldRef, 65 ArkParameterRef, 66 ArkStaticFieldRef 67} from '../base/Ref'; 68import { Value } from '../base/Value'; 69import { Constant } from '../base/Constant'; 70import { 71 ANONYMOUS_CLASS_PREFIX, 72 CALL_SIGNATURE_NAME, 73 DEFAULT_ARK_CLASS_NAME, LEXICAL_ENV_NAME_PREFIX, 74 NAME_DELIMITER, 75 NAME_PREFIX, 76 UNKNOWN_CLASS_NAME 77} from './Const'; 78import { ValueUtil } from './ValueUtil'; 79import { ArkFile } from '../model/ArkFile'; 80import { AbstractTypeExpr, KeyofTypeExpr, TypeQueryExpr } from '../base/TypeExpr'; 81import { ArkBaseModel } from '../model/ArkBaseModel'; 82 83const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'IRInference'); 84 85export class IRInference { 86 private static inferExportInfos(file: ArkFile): void { 87 file.getExportInfos().forEach(exportInfo => { 88 if (exportInfo.getArkExport() === undefined) { 89 let arkExport = findArkExport(exportInfo); 90 exportInfo.setArkExport(arkExport); 91 if (arkExport) { 92 exportInfo.setExportClauseType(arkExport.getExportType()); 93 } 94 } 95 }); 96 file.getNamespaces().forEach(namespace => { 97 namespace.getExportInfos().forEach(exportInfo => { 98 if (exportInfo.getArkExport() === undefined) { 99 let arkExport = findArkExport(exportInfo); 100 exportInfo.setArkExport(arkExport); 101 arkExport !== null ? exportInfo.setExportClauseType(arkExport.getExportType()) : true; 102 } 103 }); 104 }); 105 } 106 107 private static inferImportInfos(file: ArkFile): void { 108 file.getImportInfos().forEach(importInfo => { 109 importInfo.getLazyExportInfo(); 110 }); 111 } 112 113 public static inferFile(file: ArkFile): void { 114 this.inferImportInfos(file); 115 ModelUtils.getAllClassesInFile(file).forEach(arkClass => { 116 TypeInference.inferGenericType(arkClass.getGenericsTypes(), arkClass); 117 const defaultArkMethod = arkClass.getDefaultArkMethod(); 118 if (defaultArkMethod) { 119 TypeInference.inferTypeInMethod(defaultArkMethod); 120 } 121 arkClass.getFields().forEach(arkField => TypeInference.inferTypeInArkField(arkField)); 122 const methods = arkClass.getMethods().sort((a, b) => { 123 const name = a.getName().split(NAME_DELIMITER).reverse().join(); 124 const anotherName = b.getName().split(NAME_DELIMITER).reverse().join(); 125 if (name.startsWith(anotherName)) { 126 return 1; 127 } else if (anotherName.startsWith(name)) { 128 return -1; 129 } 130 return 0; 131 }); 132 arkClass.getAllHeritageClasses(); 133 methods.forEach(arkMethod => TypeInference.inferTypeInMethod(arkMethod)); 134 }); 135 this.inferExportInfos(file); 136 } 137 138 public static inferStaticInvokeExpr(expr: ArkStaticInvokeExpr, arkMethod: ArkMethod): AbstractInvokeExpr { 139 const fileSignature = expr.getMethodSignature().getDeclaringClassSignature().getDeclaringFileSignature(); 140 if (fileSignature !== FileSignature.DEFAULT && fileSignature !== Builtin.BUILT_IN_CLASSES_FILE_SIGNATURE) { 141 return expr; 142 } 143 const arkClass = arkMethod.getDeclaringArkClass(); 144 const methodName = expr.getMethodSignature().getMethodSubSignature().getMethodName(); 145 expr.getArgs().forEach(arg => TypeInference.inferValueType(arg, arkMethod)); 146 if (methodName === IMPORT) { 147 const arg = expr.getArg(0); 148 let type; 149 if (arg instanceof Constant) { 150 type = TypeInference.inferDynamicImportType(arg.getValue(), arkClass); 151 } 152 if (type) { 153 expr.getMethodSignature().getMethodSubSignature().setReturnType(type); 154 } 155 return expr; 156 } else if (methodName === SUPER_NAME) { 157 const superClass = arkClass.getSuperClass(); 158 if (superClass !== null) { 159 const newMethodSignature = new MethodSignature(superClass.getSignature(), expr.getMethodSignature().getMethodSubSignature()); 160 expr.setMethodSignature(newMethodSignature); 161 } 162 return expr; 163 } 164 const className = expr.getMethodSignature().getDeclaringClassSignature().getClassName(); 165 if (className && className !== UNKNOWN_CLASS_NAME) { 166 const baseType = TypeInference.inferBaseType(className, arkClass); 167 if (baseType) { 168 let result = this.inferInvokeExpr(expr, baseType, methodName, arkClass.getDeclaringArkFile().getScene()); 169 if (result) { 170 this.inferArgs(result, arkMethod); 171 return result; 172 } 173 } 174 return expr; 175 } 176 return this.inferStaticInvokeExprByMethodName(methodName, arkMethod, expr); 177 } 178 179 private static inferStaticInvokeExprByMethodName(methodName: string, arkMethod: ArkMethod, expr: AbstractInvokeExpr): AbstractInvokeExpr { 180 const arkClass = arkMethod.getDeclaringArkClass(); 181 const arkExport = 182 ModelUtils.getStaticMethodWithName(methodName, arkClass) ?? 183 arkMethod.getFunctionLocal(methodName) ?? 184 ModelUtils.findDeclaredLocal(new Local(methodName), arkMethod) ?? 185 ModelUtils.getArkExportInImportInfoWithName(methodName, arkClass.getDeclaringArkFile()) ?? 186 arkClass.getDeclaringArkFile().getScene().getSdkGlobal(methodName); 187 let method; 188 let signature; 189 if (arkExport instanceof ArkMethod) { 190 method = arkExport; 191 } else if (arkExport instanceof ArkClass) { 192 method = arkExport.getMethodWithName(CONSTRUCTOR_NAME); 193 } else if (arkExport instanceof Local) { 194 const type = TypeInference.replaceAliasType(arkExport.getType()); 195 if (type instanceof ClassType) { 196 const cls = arkClass.getDeclaringArkFile().getScene().getClass(type.getClassSignature()); 197 method = cls?.getMethodWithName(CONSTRUCTOR_NAME) ?? cls?.getMethodWithName(CALL_SIGNATURE_NAME); 198 } else if (type instanceof FunctionType) { 199 signature = type.getMethodSignature(); 200 } 201 } else if (arkExport instanceof AliasType && arkExport.getOriginalType() instanceof FunctionType) { 202 signature = (arkExport.getOriginalType() as FunctionType).getMethodSignature(); 203 } 204 if (method) { 205 signature = method.matchMethodSignature(expr.getArgs()); 206 TypeInference.inferSignatureReturnType(signature, method); 207 } 208 if (signature) { 209 if (arkExport instanceof Local) { 210 expr = new ArkPtrInvokeExpr(signature, arkExport, expr.getArgs(), expr.getRealGenericTypes()); 211 } else { 212 expr.setMethodSignature(signature); 213 } 214 this.inferArgs(expr, arkMethod); 215 } 216 return expr; 217 } 218 219 public static inferInstanceInvokeExpr(expr: ArkInstanceInvokeExpr, arkMethod: ArkMethod): AbstractInvokeExpr { 220 const arkClass = arkMethod.getDeclaringArkClass(); 221 TypeInference.inferRealGenericTypes(expr.getRealGenericTypes(), arkClass); 222 this.inferBase(expr, arkMethod); 223 224 const baseType: Type = TypeInference.replaceAliasType(expr.getBase().getType()); 225 let methodName = expr.getMethodSignature().getMethodSubSignature().getMethodName(); 226 if (methodName.startsWith(NAME_PREFIX)) { 227 const declaringStmt = arkMethod.getBody()?.getLocals().get(methodName)?.getDeclaringStmt(); 228 if (declaringStmt instanceof ArkAssignStmt && declaringStmt.getRightOp() instanceof ArkInstanceFieldRef) { 229 const rightOp = declaringStmt.getRightOp() as ArkInstanceFieldRef; 230 methodName = rightOp.getBase().getName() + '.' + rightOp.getFieldName(); 231 } 232 } 233 const scene = arkClass.getDeclaringArkFile().getScene(); 234 if (methodName === 'forEach' && baseType instanceof ArrayType) { 235 this.processForEach(expr.getArg(0), baseType, scene); 236 return expr; 237 } 238 expr.getArgs().forEach(arg => TypeInference.inferValueType(arg, arkMethod)); 239 let result = this.inferInvokeExpr(expr, baseType, methodName, scene) ?? this.processExtendFunc(expr, arkMethod, methodName); 240 if (result) { 241 this.inferArgs(result, arkMethod); 242 return result; 243 } 244 logger.warn('invoke ArkInstanceInvokeExpr MethodSignature type fail: ', expr.toString()); 245 return expr; 246 } 247 248 /** 249 * process arkUI function with Annotation @Extend @Styles @AnimatableExtend 250 * @param expr 251 * @param arkMethod 252 * @param methodName 253 */ 254 private static processExtendFunc(expr: AbstractInvokeExpr, arkMethod: ArkMethod, methodName: string): AbstractInvokeExpr | null { 255 const type = TypeInference.inferBaseType(methodName, arkMethod.getDeclaringArkClass()); 256 if (type instanceof FunctionType) { 257 const methodSignature = type.getMethodSignature(); 258 // because of last stmt is ArkReturnVoidStmt, the ArkInvokeStmt at -2 before ArkReturnVoidStmt. 259 const stmts = arkMethod.getDeclaringArkFile().getScene().getMethod(methodSignature)?.getCfg()?.getStmts(); 260 if (stmts) { 261 const endStmt = stmts[stmts.length - 2]; 262 if (endStmt instanceof ArkInvokeStmt) { 263 methodSignature.getMethodSubSignature().setReturnType(endStmt.getInvokeExpr().getType()); 264 } 265 } 266 expr.setMethodSignature(methodSignature); 267 return expr; 268 } 269 return null; 270 } 271 272 public static inferFieldRef(ref: ArkInstanceFieldRef, arkMethod: ArkMethod): AbstractRef { 273 this.inferBase(ref, arkMethod); 274 const baseType: Type = TypeInference.replaceAliasType(ref.getBase().getType()); 275 if (baseType instanceof ArrayType && ref.getFieldName() !== 'length') { 276 return new ArkArrayRef(ref.getBase(), ValueUtil.createConst(ref.getFieldName())); 277 } 278 279 let newFieldSignature = this.generateNewFieldSignature(ref, arkMethod.getDeclaringArkClass(), baseType); 280 if (newFieldSignature) { 281 if (newFieldSignature.isStatic()) { 282 return new ArkStaticFieldRef(newFieldSignature); 283 } 284 ref.setFieldSignature(newFieldSignature); 285 } 286 return ref; 287 } 288 289 private static inferBase(instance: ArkInstanceFieldRef | ArkInstanceInvokeExpr, arkMethod: ArkMethod): void { 290 const base = instance.getBase(); 291 if (base.getName() === THIS_NAME) { 292 const name = instance instanceof ArkInstanceFieldRef ? instance.getFieldName() : 293 instance.getMethodSignature().getMethodSubSignature().getMethodName(); 294 if (name.includes('.')) { 295 return; 296 } 297 const declaringArkClass = arkMethod.getDeclaringArkClass(); 298 if (declaringArkClass.isAnonymousClass()) { 299 let newBase = this.inferThisLocal(arkMethod); 300 if (newBase) { 301 instance.setBase(newBase); 302 } 303 } else if (base.getType() instanceof UnknownType) { 304 base.setType(new ClassType(declaringArkClass.getSignature(), declaringArkClass.getRealTypes())); 305 } 306 } else { 307 this.inferLocal(instance.getBase(), arkMethod); 308 } 309 } 310 311 public static inferThisLocal(arkMethod: ArkMethod): Local | null { 312 const arkClass = arkMethod.getDeclaringArkClass(); 313 if (!arkClass.isAnonymousClass()) { 314 return null; 315 } 316 317 const value = arkMethod.getBody()?.getUsedGlobals()?.get(THIS_NAME); 318 if (value instanceof Local) { 319 return value; 320 } else { 321 const thisType = TypeInference.inferBaseType(arkClass.getSignature().getDeclaringClassName(), arkClass); 322 if (thisType instanceof ClassType) { 323 const newBase = new Local(THIS_NAME, thisType); 324 let usedGlobals = arkMethod.getBody()?.getUsedGlobals(); 325 if (!usedGlobals) { 326 usedGlobals = new Map(); 327 arkMethod.getBody()?.setUsedGlobals(usedGlobals); 328 } 329 usedGlobals.set(THIS_NAME, newBase); 330 return newBase; 331 } 332 } 333 return null; 334 } 335 336 private static inferArgs(expr: AbstractInvokeExpr, arkMethod: ArkMethod): void { 337 const scene = arkMethod.getDeclaringArkFile().getScene(); 338 const parameters = expr.getMethodSignature().getMethodSubSignature().getParameters(); 339 let realTypes: Type[] = []; 340 const len = expr.getArgs().length; 341 for (let index = 0; index < len; index++) { 342 const arg = expr.getArg(index); 343 if (index >= parameters.length) { 344 break; 345 } 346 const argType = arg.getType(); 347 const paramType = parameters[index].getType(); 348 this.inferArg(expr, argType, paramType, scene, realTypes); 349 } 350 if (realTypes.length > 0 && !expr.getRealGenericTypes()) { 351 expr.setRealGenericTypes(realTypes); 352 } 353 } 354 355 private static inferArg(expr: AbstractInvokeExpr, argType: Type, paramType: Type, scene: Scene, realTypes: Type[]): void { 356 if (paramType instanceof UnionType) { 357 paramType.getTypes().forEach(t => this.inferArg(expr, argType, t, scene, realTypes)); 358 } else if (paramType instanceof AliasType) { 359 this.inferArg(expr, argType, paramType.getOriginalType(), scene, realTypes); 360 } else if (paramType instanceof ArrayType && argType instanceof ArrayType) { 361 this.inferArg(expr, argType.getBaseType(), paramType.getBaseType(), scene, realTypes); 362 } else if (expr instanceof ArkInstanceInvokeExpr && expr.getBase().getType() instanceof ArrayType) { 363 if (paramType instanceof ArrayType && paramType.getBaseType() instanceof GenericType) { 364 this.inferArg(expr, argType, (expr.getBase().getType() as ArrayType).getBaseType(), scene, realTypes); 365 } 366 } 367 368 if (paramType instanceof ClassType && scene.getProjectSdkMap().has(paramType.getClassSignature().getDeclaringFileSignature().getProjectName())) { 369 this.inferArgTypeWithSdk(paramType, scene, argType); 370 } else if (paramType instanceof GenericType || paramType instanceof AnyType) { 371 realTypes.push(argType); 372 } else if (paramType instanceof FunctionType && argType instanceof FunctionType) { 373 if (paramType.getMethodSignature().getParamLength() > 0 && paramType.getMethodSignature().getType() instanceof GenericType) { 374 const paramMethod = scene.getMethod(expr.getMethodSignature()); 375 const argMethod = scene.getMethod(argType.getMethodSignature()); 376 if (paramMethod && paramMethod.getGenericTypes() && argMethod) { 377 TypeInference.inferTypeInMethod(argMethod); 378 } 379 } 380 const realTypes = expr.getRealGenericTypes(); 381 TypeInference.inferFunctionType(argType, paramType.getMethodSignature().getMethodSubSignature(), realTypes); 382 } 383 } 384 385 public static inferRightWithSdkType(leftType: Type, rightType: Type, ackClass: ArkClass): void { 386 if (leftType instanceof AliasType) { 387 this.inferRightWithSdkType(TypeInference.replaceAliasType(leftType), rightType, ackClass); 388 } else if (leftType instanceof UnionType) { 389 leftType.getTypes().forEach(t => this.inferRightWithSdkType(t, rightType, ackClass)); 390 } else if (leftType instanceof ClassType) { 391 IRInference.inferArgTypeWithSdk(leftType, ackClass.getDeclaringArkFile().getScene(), rightType); 392 } else if (rightType instanceof ArrayType && leftType instanceof ArrayType) { 393 const baseType = TypeInference.replaceAliasType(leftType.getBaseType()); 394 if (baseType instanceof ClassType) { 395 IRInference.inferArgTypeWithSdk(baseType, ackClass.getDeclaringArkFile().getScene(), rightType.getBaseType()); 396 } 397 } 398 } 399 400 public static inferArgTypeWithSdk(sdkType: ClassType, scene: Scene, argType: Type): void { 401 if (!scene.getProjectSdkMap().has(sdkType.getClassSignature().getDeclaringFileSignature().getProjectName())) { 402 return; 403 } 404 if (argType instanceof UnionType) { 405 argType.getTypes().forEach(t => this.inferArgTypeWithSdk(sdkType, scene, t)); 406 } else if (argType instanceof ClassType && argType.getClassSignature().getClassName().startsWith(ANONYMOUS_CLASS_PREFIX)) { 407 this.inferAnonymousClass(scene.getClass(argType.getClassSignature()), sdkType.getClassSignature()); 408 } else if (argType instanceof FunctionType) { 409 const param = scene.getClass(sdkType.getClassSignature())?.getMethodWithName(CALL_SIGNATURE_NAME)?.getSignature().getMethodSubSignature(); 410 const realTypes = sdkType.getRealGenericTypes(); 411 TypeInference.inferFunctionType(argType, param, realTypes); 412 } 413 } 414 415 private static inferInvokeExpr(expr: AbstractInvokeExpr, baseType: Type, methodName: string, scene: Scene): AbstractInvokeExpr | null { 416 if (baseType instanceof AliasType) { 417 return this.inferInvokeExpr(expr, baseType.getOriginalType(), methodName, scene); 418 } else if (baseType instanceof UnionType) { 419 for (let type of baseType.flatType()) { 420 if (type instanceof UndefinedType || type instanceof NullType) { 421 continue; 422 } 423 let result = this.inferInvokeExpr(expr, type, methodName, scene); 424 if (result) { 425 return result; 426 } 427 } 428 } 429 if (baseType instanceof ClassType) { 430 return this.inferInvokeExprWithDeclaredClass(expr, baseType, methodName, scene); 431 } else if (baseType instanceof AnnotationNamespaceType) { 432 const namespace = scene.getNamespace(baseType.getNamespaceSignature()); 433 if (namespace) { 434 const foundMethod = ModelUtils.findPropertyInNamespace(methodName, namespace); 435 if (foundMethod instanceof ArkMethod) { 436 let signature = foundMethod.matchMethodSignature(expr.getArgs()); 437 TypeInference.inferSignatureReturnType(signature, foundMethod); 438 expr.setMethodSignature(signature); 439 return expr instanceof ArkInstanceInvokeExpr ? new ArkStaticInvokeExpr(signature, expr.getArgs(), expr.getRealGenericTypes()) : expr; 440 } 441 } 442 } else if (baseType instanceof FunctionType) { 443 return IRInference.inferInvokeExprWithFunction(methodName, expr, baseType, scene); 444 } else if (baseType instanceof ArrayType) { 445 return IRInference.inferInvokeExprWithArray(methodName, expr, baseType, scene); 446 } 447 return null; 448 } 449 450 private static inferInvokeExprWithArray(methodName: string, expr: AbstractInvokeExpr, baseType: ArrayType, scene: Scene): AbstractInvokeExpr | null { 451 const arrayInterface = scene.getSdkGlobal(Builtin.ARRAY); 452 if (arrayInterface instanceof ArkClass) { 453 return this.inferInvokeExpr(expr, new ClassType(arrayInterface.getSignature(), [baseType.getBaseType()]), methodName, scene); 454 } else if (methodName === Builtin.ITERATOR_FUNCTION) { 455 expr.getMethodSignature().getMethodSubSignature().setReturnType(Builtin.ITERATOR_CLASS_TYPE); 456 expr.setRealGenericTypes([baseType.getBaseType()]); 457 return expr; 458 } 459 return null; 460 } 461 462 private static inferInvokeExprWithFunction(methodName: string, expr: AbstractInvokeExpr, baseType: FunctionType, scene: Scene): AbstractInvokeExpr | null { 463 if (methodName === CALL_SIGNATURE_NAME) { 464 expr.setMethodSignature(baseType.getMethodSignature()); 465 return expr; 466 } 467 const funcInterface = scene.getSdkGlobal(FUNCTION); 468 if (funcInterface instanceof ArkClass) { 469 const method = ModelUtils.findPropertyInClass(methodName, funcInterface); 470 if (method instanceof ArkMethod) { 471 expr.setRealGenericTypes([baseType]); 472 expr.setMethodSignature(method.getSignature()); 473 return expr; 474 } 475 } 476 return null; 477 } 478 479 private static inferInvokeExprWithDeclaredClass( 480 expr: AbstractInvokeExpr, 481 baseType: ClassType, 482 methodName: string, 483 scene: Scene 484 ): AbstractInvokeExpr | null { 485 if (Builtin.isBuiltinClass(baseType.getClassSignature().getClassName())) { 486 expr.setMethodSignature(new MethodSignature(baseType.getClassSignature(), expr.getMethodSignature().getMethodSubSignature())); 487 } 488 let declaredClass = scene.getClass(baseType.getClassSignature()); 489 if (!declaredClass) { 490 const globalClass = scene.getSdkGlobal(baseType.getClassSignature().getClassName()); 491 if (globalClass instanceof ArkClass) { 492 declaredClass = globalClass; 493 } 494 } 495 const method = declaredClass ? ModelUtils.findPropertyInClass(methodName, declaredClass) : null; 496 if (method instanceof ArkMethod) { 497 const methodSignature = method.matchMethodSignature(expr.getArgs()); 498 TypeInference.inferSignatureReturnType(methodSignature, method); 499 expr.setMethodSignature(this.replaceMethodSignature(expr.getMethodSignature(), methodSignature)); 500 expr.setRealGenericTypes(IRInference.getRealTypes(expr, declaredClass, baseType, method)); 501 if (method.isStatic() && expr instanceof ArkInstanceInvokeExpr) { 502 return new ArkStaticInvokeExpr(methodSignature, expr.getArgs(), expr.getRealGenericTypes()); 503 } 504 return expr; 505 } else if (method instanceof ArkField) { 506 const type = method.getType(); 507 let methodSignature; 508 if (type instanceof FunctionType) { 509 methodSignature = type.getMethodSignature(); 510 } else if (type instanceof ClassType && type.getClassSignature().getClassName().endsWith(CALL_BACK)) { 511 const callback = scene.getClass(type.getClassSignature())?.getMethodWithName(CALL_SIGNATURE_NAME); 512 if (callback) { 513 methodSignature = callback.getSignature(); 514 } 515 } 516 if (methodSignature) { 517 const ptr = 518 expr instanceof ArkInstanceInvokeExpr 519 ? new ArkInstanceFieldRef(expr.getBase(), method.getSignature()) 520 : new ArkStaticFieldRef(method.getSignature()); 521 expr = new ArkPtrInvokeExpr(methodSignature, ptr, expr.getArgs(), expr.getRealGenericTypes()); 522 } 523 return expr; 524 } else if (methodName === CONSTRUCTOR_NAME) { 525 //sdk隐式构造 526 const subSignature = new MethodSubSignature(methodName, [], new ClassType(baseType.getClassSignature())); 527 expr.setMethodSignature(new MethodSignature(baseType.getClassSignature(), subSignature)); 528 return expr; 529 } else if (methodName === Builtin.ITERATOR_NEXT && 530 baseType.getClassSignature().getDeclaringFileSignature().getProjectName() === Builtin.DUMMY_PROJECT_NAME) { 531 expr.getMethodSignature().getMethodSubSignature().setReturnType(Builtin.ITERATOR_RESULT_CLASS_TYPE); 532 expr.setRealGenericTypes(baseType.getRealGenericTypes()); 533 return expr; 534 } 535 return null; 536 } 537 538 private static getRealTypes(expr: AbstractInvokeExpr, declaredClass: ArkClass | null, baseType: ClassType, method: ArkMethod): Type[] | undefined { 539 let realTypes; 540 const tmp: Type[] = []; 541 if (method.getGenericTypes()) { 542 expr.getMethodSignature().getMethodSubSignature().getParameters() 543 .filter(p => !p.getName().startsWith(LEXICAL_ENV_NAME_PREFIX)) 544 .forEach((p, i) => { 545 if (TypeInference.checkType(p.getType(), t => t instanceof GenericType)) { 546 tmp.push(expr.getArg(i).getType()); 547 } 548 }); 549 } 550 if (tmp.length > 0) { 551 realTypes = tmp; 552 } else if (declaredClass?.hasComponentDecorator()) { 553 realTypes = [new ClassType(declaredClass?.getSignature())]; 554 } else { 555 realTypes = baseType.getRealGenericTypes() ?? declaredClass?.getRealTypes(); 556 } 557 return realTypes; 558 } 559 560 public static replaceMethodSignature(init: MethodSignature, declared: MethodSignature): MethodSignature { 561 const className = init.getDeclaringClassSignature().getClassName(); 562 let classSignature; 563 if (declared.getDeclaringClassSignature().getClassName().endsWith('Interface')) { 564 classSignature = new AliasClassSignature(className, declared.getDeclaringClassSignature()); 565 } 566 let newSubSignature; 567 if (classSignature || newSubSignature) { 568 return new MethodSignature(classSignature ?? declared.getDeclaringClassSignature(), newSubSignature ?? declared.getMethodSubSignature()); 569 } 570 return declared; 571 } 572 573 private static processForEach(arg: Value, baseType: ArrayType, scene: Scene): void { 574 const argType = arg.getType(); 575 if (argType instanceof FunctionType) { 576 const argMethodSignature = argType.getMethodSignature(); 577 const argMethod = scene.getMethod(argMethodSignature); 578 if (argMethod != null && argMethod.getBody()) { 579 const body = argMethod.getBody() as ArkBody; 580 const firstStmt = body.getCfg().getStartingStmt(); 581 if (firstStmt instanceof ArkAssignStmt && firstStmt.getRightOp() instanceof ArkParameterRef) { 582 const parameterRef = firstStmt.getRightOp() as ArkParameterRef; 583 parameterRef.setType(baseType.getBaseType()); 584 const argMethodParams = argMethod.getSignature().getMethodSubSignature().getParameters(); 585 const actualParam = argMethodParams[argMethodParams.length - 1]; 586 actualParam.setType(baseType.getBaseType()); 587 } 588 TypeInference.inferTypeInMethod(argMethod); 589 } 590 } else { 591 logger.warn(`arg of forEach must be callable`); 592 } 593 } 594 595 public static inferLocal(base: Local, arkMethod: ArkMethod): void { 596 const arkClass = arkMethod.getDeclaringArkClass(); 597 let baseType: Type | null | undefined = base.getType(); 598 if (baseType instanceof UnclearReferenceType) { 599 baseType = TypeInference.inferUnclearRefName(baseType.getName(), arkClass); 600 } else if (TypeInference.isUnclearType(baseType)) { 601 const declaringStmt = base.getDeclaringStmt(); 602 if (!declaringStmt || !declaringStmt.getOriginalText() || declaringStmt.getOriginalText()?.startsWith(base.getName())) { 603 baseType = ModelUtils.findDeclaredLocal(base, arkMethod)?.getType() ?? TypeInference.inferBaseType(base.getName(), arkClass); 604 } 605 } 606 if (baseType instanceof UnionType || (baseType && !TypeInference.isUnclearType(baseType))) { 607 base.setType(baseType); 608 } 609 } 610 611 private static generateNewFieldSignature(ref: AbstractFieldRef, arkClass: ArkClass, baseType: Type): FieldSignature | null { 612 if (baseType instanceof UnionType) { 613 for (let type of baseType.flatType()) { 614 if (type instanceof UndefinedType || type instanceof NullType) { 615 continue; 616 } 617 let newFieldSignature = this.generateNewFieldSignature(ref, arkClass, type); 618 if (!TypeInference.isUnclearType(newFieldSignature?.getType())) { 619 return newFieldSignature; 620 } 621 } 622 return null; 623 } else if (baseType instanceof AliasType) { 624 return this.generateNewFieldSignature(ref, arkClass, baseType.getOriginalType()); 625 } 626 const fieldName = ref.getFieldName().replace(/[\"|\']/g, ''); 627 const propertyAndType = TypeInference.inferFieldType(baseType, fieldName, arkClass); 628 let propertyType = IRInference.repairType(propertyAndType?.[1], fieldName, arkClass); 629 let staticFlag: boolean; 630 let signature: BaseSignature; 631 if (baseType instanceof ClassType) { 632 const property = propertyAndType?.[0]; 633 if (property instanceof ArkField && property.getCategory() !== FieldCategory.ENUM_MEMBER && 634 !(property.getType() instanceof GenericType)) { 635 return property.getSignature(); 636 } 637 staticFlag = 638 baseType.getClassSignature().getClassName() === DEFAULT_ARK_CLASS_NAME || 639 ((property instanceof ArkField || property instanceof ArkMethod) && property.isStatic()); 640 signature = property instanceof ArkMethod ? property.getSignature().getDeclaringClassSignature() : baseType.getClassSignature(); 641 } else if (baseType instanceof AnnotationNamespaceType) { 642 staticFlag = true; 643 signature = baseType.getNamespaceSignature(); 644 } else { 645 return null; 646 } 647 return new FieldSignature(fieldName, signature, propertyType ?? ref.getType(), staticFlag); 648 } 649 650 private static repairType(propertyType: Type | undefined, fieldName: string, arkClass: ArkClass): Type | undefined { 651 if (!propertyType || propertyType instanceof UnknownType) { 652 const newType = TypeInference.inferBaseType(fieldName, arkClass); 653 if (newType) { 654 propertyType = newType; 655 } 656 } else if (TypeInference.isUnclearType(propertyType)) { 657 const newType = TypeInference.inferUnclearedType(propertyType, arkClass); 658 if (newType) { 659 propertyType = newType; 660 } 661 } 662 return propertyType; 663 } 664 665 public static inferAnonymousClass(anon: ArkClass | null, declaredSignature: ClassSignature, set: Set<string> = new Set()): void { 666 if (!anon) { 667 return; 668 } 669 const key = anon.getSignature().toString(); 670 if (set.has(key)) { 671 return; 672 } else { 673 set.add(key); 674 } 675 const scene = anon.getDeclaringArkFile().getScene(); 676 const declaredClass = scene.getClass(declaredSignature); 677 if (!declaredClass) { 678 return; 679 } 680 for (const anonField of anon.getFields()) { 681 const property = ModelUtils.findPropertyInClass(anonField.getName(), declaredClass); 682 if (property instanceof ArkField) { 683 this.assignAnonField(property, anonField, scene, set); 684 } else if (property instanceof ArkMethod) { 685 const type = anonField.getType(); 686 if (type instanceof FunctionType) { 687 this.assignAnonMethod(scene.getMethod(type.getMethodSignature()), property); 688 } 689 anonField.setSignature( 690 new FieldSignature(anonField.getName(), property.getDeclaringArkClass().getSignature(), new FunctionType(property.getSignature())) 691 ); 692 } 693 } 694 for (const anonMethod of anon.getMethods()) { 695 this.assignAnonMethod(anonMethod, declaredClass.getMethodWithName(anonMethod.getName())); 696 } 697 } 698 699 private static assignAnonMethod(anonMethod: ArkMethod | null, declaredMethod: ArkMethod | null): void { 700 if (declaredMethod && anonMethod) { 701 anonMethod.setDeclareSignatures(declaredMethod.matchMethodSignature(anonMethod.getSubSignature().getParameters())); 702 } 703 } 704 705 private static assignAnonField(property: ArkField, anonField: ArkField, scene: Scene, set: Set<string>): void { 706 function deepInfer(anonType: Type, declaredSignature: ClassSignature): void { 707 if (anonType instanceof ClassType && anonType.getClassSignature().getClassName().startsWith(ANONYMOUS_CLASS_PREFIX)) { 708 IRInference.inferAnonymousClass(scene.getClass(anonType.getClassSignature()), declaredSignature, set); 709 } 710 } 711 712 const type = property.getSignature().getType(); 713 const fieldInitializer = anonField.getInitializer(); 714 const lastStmt = fieldInitializer[fieldInitializer.length - 1]; 715 if (lastStmt instanceof ArkAssignStmt) { 716 const rightType = lastStmt.getRightOp().getType(); 717 if (type instanceof ClassType) { 718 deepInfer(rightType, type.getClassSignature()); 719 } else if (type instanceof ArrayType && type.getBaseType() instanceof ClassType && rightType instanceof ArrayType) { 720 const baseType = rightType.getBaseType(); 721 const classSignature = (type.getBaseType() as ClassType).getClassSignature(); 722 if (baseType instanceof UnionType) { 723 baseType.getTypes().forEach(t => deepInfer(t, classSignature)); 724 } else { 725 deepInfer(rightType.getBaseType(), classSignature); 726 } 727 } else if (type instanceof FunctionType && rightType instanceof FunctionType) { 728 TypeInference.inferFunctionType(rightType, type.getMethodSignature().getMethodSubSignature(), type.getRealGenericTypes()); 729 } 730 const leftOp = lastStmt.getLeftOp(); 731 if (leftOp instanceof AbstractFieldRef) { 732 leftOp.setFieldSignature(property.getSignature()); 733 } 734 } 735 anonField.setSignature(property.getSignature()); 736 } 737 738 public static inferAliasTypeExpr(expr: AliasTypeExpr, arkMethod: ArkMethod): AbstractExpr { 739 const originalObject = expr.getOriginalObject(); 740 let model; 741 if (originalObject instanceof Local) { 742 model = ModelUtils.findArkModelByRefName(originalObject.getName(), arkMethod.getDeclaringArkClass()); 743 } else if (originalObject instanceof AbstractTypeExpr) { 744 originalObject.inferType(arkMethod); 745 model = originalObject; 746 } else if (originalObject instanceof Type) { 747 const type = TypeInference.inferUnclearedType(originalObject, arkMethod.getDeclaringArkClass()); 748 749 // If original Object is ClassType, AliasType or UnclearReferenceType with real generic types, 750 // the type after infer should be revert back to the object itself. 751 if (type instanceof ClassType) { 752 const scene = arkMethod.getDeclaringArkFile().getScene(); 753 model = ModelUtils.findArkModelBySignature(type.getClassSignature(), scene); 754 } else if (type instanceof AliasType) { 755 const scene = arkMethod.getDeclaringArkFile().getScene(); 756 model = ModelUtils.findArkModelBySignature(type.getSignature(), scene); 757 } else if (type) { 758 model = type; 759 } 760 if (expr.getRealGenericTypes() !== undefined && originalObject instanceof UnclearReferenceType) { 761 expr.setRealGenericTypes(originalObject.getGenericTypes()); 762 } 763 } 764 765 if (AliasTypeExpr.isAliasTypeOriginalModel(model)) { 766 expr.setOriginalObject(model); 767 } 768 return expr; 769 } 770 771 public static inferTypeQueryExpr(expr: TypeQueryExpr, arkMethod: ArkMethod): void { 772 let gTypes = expr.getGenerateTypes(); 773 if (gTypes) { 774 for (let i = 0; i < gTypes.length; i++) { 775 const newType = TypeInference.inferUnclearedType(gTypes[i], arkMethod.getDeclaringArkClass()); 776 if (newType) { 777 gTypes[i] = newType; 778 } 779 } 780 } 781 782 const opValue = expr.getOpValue(); 783 let opValueType; 784 if (opValue instanceof ArkBaseModel) { 785 opValueType = ModelUtils.parseArkBaseModel2Type(opValue) ?? UnknownType.getInstance(); 786 } else { 787 opValueType = opValue.getType(); 788 } 789 790 if (!TypeInference.isUnclearType(opValueType)) { 791 return; 792 } 793 if (opValue instanceof Local) { 794 const newOpValueType = TypeInference.inferBaseType(opValue.getName(), arkMethod.getDeclaringArkClass()); 795 const scene = arkMethod.getDeclaringArkFile().getScene(); 796 if (newOpValueType instanceof ClassType) { 797 const newOpValue = ModelUtils.findArkModelBySignature(newOpValueType.getClassSignature(), scene); 798 if (newOpValue instanceof ArkBaseModel) { 799 expr.setOpValue(newOpValue); 800 } 801 } else if (newOpValueType instanceof FunctionType) { 802 const newOpValue = ModelUtils.findArkModelBySignature(newOpValueType.getMethodSignature(), scene); 803 if (newOpValue instanceof ArkBaseModel) { 804 expr.setOpValue(newOpValue); 805 } 806 } else { 807 this.inferLocal(opValue, arkMethod); 808 } 809 } else if (opValue instanceof AbstractRef || opValue instanceof AbstractExpr) { 810 expr.setOpValue(opValue.inferType(arkMethod)); 811 } 812 } 813 814 public static inferKeyofTypeExpr(expr: KeyofTypeExpr, arkMethod: ArkMethod): void { 815 const opType = expr.getOpType(); 816 if (TypeInference.isUnclearType(opType)) { 817 if (opType instanceof TypeQueryExpr) { 818 this.inferTypeQueryExpr(opType, arkMethod); 819 } else { 820 const type = TypeInference.inferUnclearedType(opType, arkMethod.getDeclaringArkClass()); 821 if (type) { 822 expr.setOpType(type); 823 } 824 } 825 } 826 } 827 828 public static inferParameterRef(ref: ArkParameterRef, arkMethod: ArkMethod): AbstractRef { 829 const paramType = ref.getType(); 830 if (paramType instanceof UnknownType || paramType instanceof UnclearReferenceType) { 831 const signature = arkMethod.getDeclareSignatures()?.[0] ?? arkMethod.getSignature(); 832 const type1 = signature.getMethodSubSignature().getParameters()[ref.getIndex()]?.getType(); 833 if (!TypeInference.isUnclearType(type1)) { 834 ref.setType(type1); 835 return ref; 836 } 837 } else if (paramType instanceof LexicalEnvType) { 838 paramType 839 .getClosures() 840 .filter(c => TypeInference.isUnclearType(c.getType())) 841 .forEach(e => this.inferLocal(e, arkMethod)); 842 return ref; 843 } 844 let type = TypeInference.inferUnclearedType(paramType, arkMethod.getDeclaringArkClass()); 845 if (type) { 846 ref.setType(type); 847 } 848 return ref; 849 } 850} 851