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 { Constant } from '../../core/base/Constant'; 17import { ArkInstanceInvokeExpr, ArkNormalBinopExpr, ArkStaticInvokeExpr, NormalBinaryOperator } from '../../core/base/Expr'; 18import { Local } from '../../core/base/Local'; 19import { ArkAssignStmt, Stmt } from '../../core/base/Stmt'; 20import { 21 COMPONENT_BRANCH_FUNCTION, 22 COMPONENT_CREATE_FUNCTION, 23 COMPONENT_IF, 24 COMPONENT_POP_FUNCTION, 25 isEtsSystemComponent, 26 SPECIAL_CONTAINER_COMPONENT, 27} from '../../core/common/EtsConst'; 28import { ArkClass, ClassCategory } from '../../core/model/ArkClass'; 29import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; 30import { ANONYMOUS_CLASS_PREFIX, ANONYMOUS_METHOD_PREFIX, DEFAULT_ARK_CLASS_NAME } from '../../core/common/Const'; 31import { ClassSignature } from '../../core/model/ArkSignature'; 32import { ArkNamespace } from '../../core/model/ArkNamespace'; 33import ts from 'ohos-typescript'; 34import { TEMP_LOCAL_PREFIX } from '../../core/common/Const'; 35 36const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'PrinterUtils'); 37 38export const CLASS_CATEGORY_COMPONENT = 100; 39 40export class PrinterUtils { 41 public static classOriginTypeToString = new Map<number, string>([ 42 [ClassCategory.CLASS, 'class'], 43 [ClassCategory.STRUCT, 'struct'], 44 [ClassCategory.INTERFACE, 'interface'], 45 [ClassCategory.ENUM, 'enum'], 46 [ClassCategory.TYPE_LITERAL, 'typeliteral'], 47 [ClassCategory.OBJECT, 'object'], 48 [CLASS_CATEGORY_COMPONENT, 'component'], 49 ]); 50 51 public static isAnonymousClass(name: string): boolean { 52 return name.startsWith(ANONYMOUS_CLASS_PREFIX); 53 } 54 55 public static isDefaultClass(name: string): boolean { 56 return name === DEFAULT_ARK_CLASS_NAME; 57 } 58 59 public static isAnonymousMethod(name: string): boolean { 60 return name.startsWith(ANONYMOUS_METHOD_PREFIX); 61 } 62 63 public static isConstructorMethod(name: string): boolean { 64 return name === 'constructor'; 65 } 66 67 public static isDeIncrementStmt(stmt: Stmt | null, op: NormalBinaryOperator): boolean { 68 if (!(stmt instanceof ArkAssignStmt)) { 69 return false; 70 } 71 72 let leftOp = stmt.getLeftOp(); 73 let rightOp = stmt.getRightOp(); 74 if (!(leftOp instanceof Local) || !(rightOp instanceof ArkNormalBinopExpr)) { 75 return false; 76 } 77 78 let op1 = rightOp.getOp1(); 79 let op2 = rightOp.getOp2(); 80 let operator = rightOp.getOperator(); 81 if (!(op1 instanceof Local) || !(op2 instanceof Constant)) { 82 return false; 83 } 84 85 return leftOp.getName() === op1.getName() && operator === op && op2.getValue() === '1'; 86 } 87 88 public static isTemp(name: string): boolean { 89 return name.startsWith(TEMP_LOCAL_PREFIX); 90 } 91 92 public static getOriginType(cls: ArkClass): number { 93 if (cls.hasComponentDecorator()) { 94 return CLASS_CATEGORY_COMPONENT; 95 } 96 return cls.getCategory(); 97 } 98 99 public static isComponentPop(invokeExpr: ArkStaticInvokeExpr): boolean { 100 let className = invokeExpr.getMethodSignature().getDeclaringClassSignature().getClassName(); 101 let methodName = invokeExpr.getMethodSignature().getMethodSubSignature().getMethodName(); 102 103 if (methodName === COMPONENT_POP_FUNCTION && (isEtsSystemComponent(className) || SPECIAL_CONTAINER_COMPONENT.has(className))) { 104 return true; 105 } 106 107 return false; 108 } 109 110 public static isComponentCreate(invokeExpr: ArkStaticInvokeExpr): boolean { 111 let className = invokeExpr.getMethodSignature().getDeclaringClassSignature().getClassName(); 112 let methodName = invokeExpr.getMethodSignature().getMethodSubSignature().getMethodName(); 113 114 if (methodName === COMPONENT_CREATE_FUNCTION && (isEtsSystemComponent(className) || SPECIAL_CONTAINER_COMPONENT.has(className))) { 115 return true; 116 } 117 118 return false; 119 } 120 121 public static isComponentAttributeInvoke(invokeExpr: ArkInstanceInvokeExpr, visitor: Set<ArkInstanceInvokeExpr> = new Set()): boolean { 122 if (visitor.has(invokeExpr)) { 123 return false; 124 } 125 visitor.add(invokeExpr); 126 let base = invokeExpr.getBase(); 127 if (!(base instanceof Local)) { 128 logger.error(`PrinterUtils->isComponentAttributeInvoke illegal invoke expr ${invokeExpr}`); 129 return false; 130 } 131 let stmt = base.getDeclaringStmt(); 132 if (!stmt || !(stmt instanceof ArkAssignStmt)) { 133 return false; 134 } 135 136 let rightOp = stmt.getRightOp(); 137 if (rightOp instanceof ArkInstanceInvokeExpr) { 138 return PrinterUtils.isComponentAttributeInvoke(rightOp, visitor); 139 } 140 141 if (rightOp instanceof ArkStaticInvokeExpr) { 142 return PrinterUtils.isComponentCreate(rightOp); 143 } 144 145 return false; 146 } 147 148 public static isComponentIfBranchInvoke(invokeExpr: ArkStaticInvokeExpr): boolean { 149 let className = invokeExpr.getMethodSignature().getDeclaringClassSignature().getClassName(); 150 let methodName = invokeExpr.getMethodSignature().getMethodSubSignature().getMethodName(); 151 152 if (className === COMPONENT_IF && methodName === COMPONENT_BRANCH_FUNCTION) { 153 return true; 154 } 155 return false; 156 } 157 158 public static isComponentIfElseInvoke(invokeExpr: ArkStaticInvokeExpr): boolean { 159 let className = invokeExpr.getMethodSignature().getDeclaringClassSignature().getClassName(); 160 let methodName = invokeExpr.getMethodSignature().getMethodSubSignature().getMethodName(); 161 162 if (className === COMPONENT_IF && methodName === COMPONENT_BRANCH_FUNCTION) { 163 let arg0 = invokeExpr.getArg(0) as Constant; 164 if (arg0.getValue() === '1') { 165 return true; 166 } 167 } 168 return false; 169 } 170 171 public static getStaticInvokeClassFullName(classSignature: ClassSignature, namespace?: ArkNamespace): string { 172 let code: string[] = []; 173 let declareNamespace = classSignature.getDeclaringNamespaceSignature(); 174 while (declareNamespace !== null) { 175 let namespaceName = declareNamespace.getNamespaceName(); 176 if (namespaceName.length > 0 && namespaceName !== namespace?.getName()) { 177 code.unshift(namespaceName); 178 declareNamespace = declareNamespace.getDeclaringNamespaceSignature(); 179 } else { 180 break; 181 } 182 } 183 184 let className = classSignature.getClassName(); 185 if (className && className.length > 0 && !PrinterUtils.isDefaultClass(className)) { 186 code.push(className); 187 } 188 return code.join('.'); 189 } 190 191 public static isIdentifierText(text: string): boolean { 192 let ch = text.charCodeAt(0); 193 if (!ts.isIdentifierStart(ch, ts.ScriptTarget.Latest)) { 194 return false; 195 } 196 197 for (let i = 1; i < text.length; i++) { 198 if (!ts.isIdentifierPart(text.charCodeAt(i), ts.ScriptTarget.Latest)) { 199 return false; 200 } 201 } 202 203 return true; 204 } 205 206 public static escape(text: string): string { 207 return text 208 .replace(/\\/g, '\\\\') 209 .replace(/\f/g, `\\f`) 210 .replace(/\n/g, `\\n`) 211 .replace(/\r/g, '\\r') 212 .replace(/\t/g, '\\t') 213 .replace(/\v/g, '\\v') 214 .replace(/\?/g, '\\?') 215 .replace(/\'/g, "\\'") 216 .replace(/\"/g, '\\"'); 217 } 218} 219