• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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