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 */ 15 16import { ArkInstanceInvokeExpr } from '../../core/base/Expr'; 17import { Local } from '../../core/base/Local'; 18import { Stmt, ArkInvokeStmt } from '../../core/base/Stmt'; 19import { ArkMethod } from '../../core/model/ArkMethod'; 20import { ClassSignature } from '../../core/model/ArkSignature'; 21import { Scene } from '../../Scene'; 22import { COMPONENT_LIFECYCLE_METHOD_NAME } from '../../utils/entryMethodUtils'; 23import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; 24 25const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'Dummy Call'); 26 27/** 28 * TODO: constructor pointer and cid 29 */ 30export class DummyCallCreator { 31 private scene: Scene; 32 private pageMap; 33 // TODO: classSig -> str ? 34 private componentMap: Map<ClassSignature, Set<Stmt>>; 35 36 constructor(scene: Scene) { 37 this.scene = scene; 38 this.componentMap = new Map(); 39 this.pageMap = new Map(); 40 } 41 42 public getDummyCallByPage(classSig: ClassSignature, basePage: Local): Set<Stmt> { 43 let dummyCallStmts = this.pageMap.get(classSig); 44 if (dummyCallStmts) { 45 return dummyCallStmts; 46 } 47 48 dummyCallStmts = this.buildDummyCallBody(classSig, basePage); 49 50 this.pageMap.set(classSig, dummyCallStmts); 51 return dummyCallStmts; 52 } 53 54 public getDummyCallByComponent(classSig: ClassSignature, baseComponent: Local): Set<Stmt> { 55 let dummyCallStmts = this.componentMap.get(classSig); 56 if (dummyCallStmts) { 57 return dummyCallStmts; 58 } 59 60 dummyCallStmts = this.buildDummyCallBody(classSig, baseComponent); 61 62 this.componentMap.set(classSig, dummyCallStmts); 63 return dummyCallStmts; 64 } 65 66 /** 67 * build dummy call edge with class signature, including a class new expr and call back function invokes 68 * @param classSig class signature 69 * @returns dummy call edges 70 */ 71 private buildDummyCallBody(classSig: ClassSignature, baseComponent: Local): Set<Stmt> { 72 let dummyCallStmts: Set<Stmt> = new Set(); 73 74 this.getComponentCallStmts(classSig, baseComponent).forEach(stmt => dummyCallStmts.add(stmt)); 75 76 return dummyCallStmts; 77 } 78 79 private getComponentCallStmts(classSig: ClassSignature, base: Local): Stmt[] { 80 let componentClass = this.scene.getClass(classSig); 81 if (!componentClass) { 82 logger.error(`can not find class ${classSig.toString()}`); 83 return []; 84 } 85 86 let callStmts: Stmt[] = []; 87 // filter callback method 88 componentClass 89 .getMethods() 90 .filter(method => COMPONENT_LIFECYCLE_METHOD_NAME.includes(method.getName())) 91 .forEach((method: ArkMethod) => { 92 // TODO: args pointer ? 93 if (method.getParameters().length === 0) { 94 callStmts.push(new ArkInvokeStmt(new ArkInstanceInvokeExpr(base, method.getSignature(), []))); 95 } else { 96 logger.warn(`parameters in callback function hasn't been processed: ${method.getSignature().toString()}`); 97 } 98 }); 99 100 return callStmts; 101 } 102} 103