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 { CallGraph, CallGraphNode, CallGraphNodeKind, Method } from '../CallGraph'; 17import { Scene } from '../../../Scene'; 18import { AbstractInvokeExpr, ArkInstanceInvokeExpr, ArkStaticInvokeExpr } from '../../../core/base/Expr'; 19import { NodeID } from '../../../core/graph/BaseExplicitGraph'; 20import { ClassHierarchyAnalysis } from '../../algorithm/ClassHierarchyAnalysis'; 21import { RapidTypeAnalysis } from '../../algorithm/RapidTypeAnalysis'; 22import { ArkMethod } from '../../../core/model/ArkMethod'; 23 24export class CallGraphBuilder { 25 private cg: CallGraph; 26 private scene: Scene; 27 28 constructor(c: CallGraph, s: Scene) { 29 this.cg = c; 30 this.scene = s; 31 } 32 33 public buildDirectCallGraphForScene(): void { 34 const methods = this.scene.getMethods(); 35 this.buildDirectCallGraph(methods); 36 37 // set entries at end 38 this.setEntries(); 39 } 40 41 /* 42 * Create CG Node for ArkMethods 43 */ 44 public buildCGNodes(methods: ArkMethod[]): void { 45 for (const method of methods) { 46 let m = method.getSignature(); 47 let kind = CallGraphNodeKind.real; 48 if (method.isGenerated()) { 49 kind = CallGraphNodeKind.intrinsic; 50 } else if (method.getBody() === undefined || method.getCfg() === undefined) { 51 kind = CallGraphNodeKind.blank; 52 } else if (method.getName() === 'constructor') { 53 kind = CallGraphNodeKind.constructor; 54 } 55 56 this.cg.addCallGraphNode(m, kind); 57 } 58 } 59 60 public buildDirectCallGraph(methods: ArkMethod[]): void { 61 this.buildCGNodes(methods); 62 63 for (const method of methods) { 64 let cfg = method.getCfg(); 65 if (cfg === undefined) { 66 // abstract method cfg is undefined 67 continue; 68 } 69 let stmts = cfg.getStmts(); 70 for (const stmt of stmts) { 71 let invokeExpr = stmt.getInvokeExpr(); 72 if (invokeExpr === undefined) { 73 continue; 74 } 75 76 let callee: Method | undefined = this.getDCCallee(invokeExpr); 77 // abstract method will also be added into direct cg 78 if (callee && invokeExpr instanceof ArkStaticInvokeExpr) { 79 this.cg.addDirectOrSpecialCallEdge(method.getSignature(), callee, stmt); 80 } else if ( 81 callee && invokeExpr instanceof ArkInstanceInvokeExpr && 82 (this.isConstructor(callee) || this.scene.getMethod(callee)?.isGenerated()) 83 ) { 84 this.cg.addDirectOrSpecialCallEdge(method.getSignature(), callee, stmt, false); 85 } else { 86 this.cg.addDynamicCallInfo(stmt, method.getSignature(), callee); 87 } 88 } 89 } 90 } 91 92 public buildClassHierarchyCallGraph(entries: Method[], displayGeneratedMethod: boolean = false): void { 93 let cgEntries: NodeID[] = []; 94 entries.forEach((entry: Method) => { 95 cgEntries.push(this.cg.getCallGraphNodeByMethod(entry).getID()); 96 }); 97 this.cg.setEntries(cgEntries); 98 99 let classHierarchyAnalysis: ClassHierarchyAnalysis = new ClassHierarchyAnalysis(this.scene, this.cg, this); 100 classHierarchyAnalysis.start(displayGeneratedMethod); 101 } 102 103 public buildCHA4WholeProject(displayGeneratedMethod: boolean = false): void { 104 let classHierarchyAnalysis: ClassHierarchyAnalysis = new ClassHierarchyAnalysis(this.scene, this.cg, this); 105 classHierarchyAnalysis.projectStart(displayGeneratedMethod); 106 } 107 108 public buildRapidTypeCallGraph(entries: Method[], displayGeneratedMethod: boolean = false): void { 109 let cgEntries: NodeID[] = []; 110 entries.forEach((entry: Method) => { 111 cgEntries.push(this.cg.getCallGraphNodeByMethod(entry).getID()); 112 }); 113 this.cg.setEntries(cgEntries); 114 115 let rapidTypeAnalysis: RapidTypeAnalysis = new RapidTypeAnalysis(this.scene, this.cg); 116 rapidTypeAnalysis.start(displayGeneratedMethod); 117 } 118 119 /// Get direct call callee 120 private getDCCallee(invokeExpr: AbstractInvokeExpr): Method | undefined { 121 return invokeExpr.getMethodSignature(); 122 } 123 124 private isConstructor(m: Method): boolean { 125 return m.getMethodSubSignature().getMethodName() === 'constructor'; 126 } 127 128 public setEntries(): void { 129 let nodesIter = this.cg.getNodesIter(); 130 let entries = Array.from(nodesIter) 131 .filter(node => !node.hasIncomingEdges() && node.getKind() === CallGraphNodeKind.real && !(node as CallGraphNode).isBlankMethod) 132 .map(node => node.getID()); 133 this.cg.setEntries(entries); 134 } 135} 136