1/* 2 * Copyright (c) 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 { 17 ArkAssignStmt, 18 ArkMethod, 19 CallGraph, 20 CallGraphBuilder, 21 Local, 22 LOG_MODULE_TYPE, 23 Logger, 24 Scene, 25 Stmt, 26 Value, 27} from 'arkanalyzer/lib'; 28import { WarnInfo } from '../../utils/common/Utils'; 29import { Language } from 'arkanalyzer/lib/core/model/ArkFile'; 30import { DVFG, DVFGNode } from 'arkanalyzer/lib/VFG/DVFG'; 31import { DVFGBuilder } from 'arkanalyzer/lib/VFG/builder/DVFGBuilder'; 32 33const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'Utils'); 34 35export const CALL_DEPTH_LIMIT = 2; 36export class CallGraphHelper { 37 private static cgInstance: CallGraph | null = null; 38 39 public static dispose(): void { 40 this.cgInstance = null; 41 } 42 43 public static getCGInstance(scene: Scene): CallGraph { 44 if (!this.cgInstance) { 45 this.cgInstance = new CallGraph(scene); 46 } 47 return this.cgInstance; 48 } 49} 50 51export class GlobalCallGraphHelper { 52 private static cgInstance: CallGraph | null = null; 53 54 public static dispose(): void { 55 this.cgInstance = null; 56 } 57 58 public static getCGInstance(scene: Scene): CallGraph { 59 if (!this.cgInstance) { 60 this.cgInstance = new CallGraph(scene); 61 let cgBuilder = new CallGraphBuilder(this.cgInstance, scene); 62 cgBuilder.buildCHA4WholeProject(true); 63 } 64 return this.cgInstance; 65 } 66} 67 68export class DVFGHelper { 69 private static dvfgInstance: DVFG; 70 private static dvfgBuilder: DVFGBuilder; 71 private static built: Set<ArkMethod> = new Set(); 72 73 public static dispose(): void { 74 // @ts-ignore 75 this.dvfgInstance = null; 76 // @ts-ignore 77 this.dvfgBuilder = null; 78 this.built.clear(); 79 } 80 81 private static createDVFGInstance(scene: Scene): void { 82 if (!this.dvfgInstance) { 83 this.dvfgInstance = new DVFG(GlobalCallGraphHelper.getCGInstance(scene)); 84 this.dvfgBuilder = new DVFGBuilder(this.dvfgInstance, scene); 85 } 86 } 87 88 public static buildSingleDVFG(method: ArkMethod, scene: Scene): void { 89 if (!this.dvfgInstance) { 90 this.createDVFGInstance(scene); 91 } 92 if (!this.built.has(method)) { 93 this.dvfgBuilder.buildForSingleMethod(method); 94 this.built.add(method); 95 } 96 } 97 98 public static getOrNewDVFGNode(stmt: Stmt, scene: Scene): DVFGNode { 99 if (!this.dvfgInstance) { 100 this.createDVFGInstance(scene); 101 } 102 return this.dvfgInstance!.getOrNewDVFGNode(stmt); 103 } 104} 105 106export const CALLBACK_METHOD_NAME: string[] = [ 107 'onClick', // 点击事件,当用户点击组件时触发 108 'onTouch', // 触摸事件,当手指在组件上按下、滑动、抬起时触发 109 'onAppear', // 组件挂载显示时触发 110 'onDisAppear', // 组件卸载消失时触发 111 'onDragStart', // 拖拽开始事件,当组件被长按后开始拖拽时触发 112 'onDragEnter', // 拖拽进入组件范围时触发 113 'onDragMove', // 拖拽在组件范围内移动时触发 114 'onDragLeave', // 拖拽离开组件范围内时触发 115 'onDrop', // 拖拽释放目标,当在本组件范围内停止拖拽行为时触发 116 'onKeyEvent', // 按键事件,当组件获焦后,按键动作触发 117 'onFocus', // 焦点事件,当组件获取焦点时触发 118 'onBlur', // 当组件失去焦点时触发的回调 119 'onHover', // 鼠标悬浮事件,鼠标进入或退出组件时触发 120 'onMouse', // 鼠标事件,当鼠标按键点击或在组件上移动时触发 121 'onAreaChange', // 组件区域变化事件,组件尺寸、位置变化时触发 122 'onVisibleAreaChange', // 组件可见区域变化事件,组件在屏幕中的显示区域面积变化时触发 123]; 124 125export function getLanguageStr(language: Language): string { 126 let targetLan: string = ''; 127 switch (language) { 128 case Language.JAVASCRIPT: 129 targetLan = 'javascript'; 130 break; 131 case Language.TYPESCRIPT: 132 targetLan = 'typescript'; 133 break; 134 case Language.ARKTS1_1: 135 targetLan = 'arkts1.1'; 136 break; 137 case Language.ARKTS1_2: 138 targetLan = 'arkts1.2'; 139 break; 140 default: 141 break; 142 } 143 return targetLan; 144} 145 146export function getLineAndColumn(stmt: Stmt, operand: Value): WarnInfo { 147 const arkFile = stmt.getCfg().getDeclaringMethod().getDeclaringArkFile(); 148 const originPosition = stmt.getOperandOriginalPosition(operand); 149 if (arkFile && originPosition) { 150 const originPath = arkFile.getFilePath(); 151 const line = originPosition.getFirstLine(); 152 const startCol = originPosition.getFirstCol(); 153 const endCol = startCol; 154 return { line, startCol, endCol, filePath: originPath }; 155 } else { 156 logger.debug('ArkFile or operand position is null.'); 157 } 158 return { line: -1, startCol: -1, endCol: -1, filePath: '' }; 159} 160 161export function getGlobalsDefineInDefaultMethod(defaultMethod: ArkMethod): Map<string, Stmt[]> { 162 const globalVarMap: Map<string, Stmt[]> = new Map(); 163 const stmts = defaultMethod.getBody()?.getCfg().getStmts() ?? []; 164 for (const stmt of stmts) { 165 if (!(stmt instanceof ArkAssignStmt)) { 166 continue; 167 } 168 const leftOp = stmt.getLeftOp(); 169 if (!(leftOp instanceof Local)) { 170 continue; 171 } 172 const name = leftOp.getName(); 173 if (name.startsWith('%') || name === 'this') { 174 continue; 175 } 176 globalVarMap.set(name, [...(globalVarMap.get(name) ?? []), stmt]); 177 } 178 return globalVarMap; 179} 180