• 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 {
17    AbstractInvokeExpr,
18    AliasTypeExpr,
19    ArkCastExpr,
20    ArkConditionExpr,
21    ArkInstanceInvokeExpr,
22    ArkStaticInvokeExpr,
23    BinaryOperator,
24    NormalBinaryOperator,
25    RelationalBinaryOperator,
26    UnaryOperator,
27} from '../base/Expr';
28import { ArkCaughtExceptionRef, ArkInstanceFieldRef, ArkParameterRef, ArkThisRef, GlobalRef } from '../base/Ref';
29import { Value } from '../base/Value';
30import * as ts from 'ohos-typescript';
31import { Local } from '../base/Local';
32import { ArkAliasTypeDefineStmt, ArkAssignStmt, ArkIfStmt, ArkInvokeStmt, ArkReturnStmt, ArkReturnVoidStmt, ArkThrowStmt, Stmt } from '../base/Stmt';
33import { AliasType, BooleanType, ClassType, Type, UnclearReferenceType, UnknownType, VoidType } from '../base/Type';
34import { ValueUtil } from './ValueUtil';
35import { AliasTypeSignature, ClassSignature, FieldSignature, MethodSignature, MethodSubSignature } from '../model/ArkSignature';
36
37import { IRUtils } from './IRUtils';
38import { ArkMethod } from '../model/ArkMethod';
39import { buildArkMethodFromArkClass } from '../model/builder/ArkMethodBuilder';
40import { ArkSignatureBuilder } from '../model/builder/ArkSignatureBuilder';
41import { COMPONENT_BRANCH_FUNCTION, COMPONENT_CREATE_FUNCTION, COMPONENT_IF, COMPONENT_POP_FUNCTION, COMPONENT_REPEAT } from './EtsConst';
42import { FullPosition, LineColPosition } from '../base/Position';
43import { ModelUtils } from './ModelUtils';
44import { Builtin } from './Builtin';
45import { DEFAULT, PROMISE } from './TSConst';
46import { buildGenericType, buildModifiers, buildTypeParameters } from '../model/builder/builderUtils';
47import { ArkValueTransformer } from './ArkValueTransformer';
48import { ImportInfo } from '../model/ArkImport';
49import { AbstractTypeExpr } from '../base/TypeExpr';
50import { buildNormalArkClassFromArkMethod } from '../model/builder/ArkClassBuilder';
51import { ArkClass } from '../model/ArkClass';
52import { ModifierType } from '../model/ArkBaseModel';
53
54export type ValueAndStmts = {
55    value: Value;
56    valueOriginalPositions: FullPosition[]; // original positions of value and its uses
57    stmts: Stmt[];
58};
59
60export class DummyStmt extends Stmt {
61    constructor(text: string) {
62        super();
63        this.text = text;
64    }
65
66    public toString(): string {
67        return this.text!;
68    }
69}
70
71export class ArkIRTransformer {
72    public static readonly DUMMY_LOOP_INITIALIZER_STMT = 'LoopInitializer';
73    public static readonly DUMMY_CONDITIONAL_OPERATOR = 'ConditionalOperator';
74    public static readonly DUMMY_CONDITIONAL_OPERATOR_IF_TRUE_STMT = ArkIRTransformer.DUMMY_CONDITIONAL_OPERATOR + 'IfTrue';
75    public static readonly DUMMY_CONDITIONAL_OPERATOR_IF_FALSE_STMT = ArkIRTransformer.DUMMY_CONDITIONAL_OPERATOR + 'IfFalse';
76    public static readonly DUMMY_CONDITIONAL_OPERATOR_END_STMT = ArkIRTransformer.DUMMY_CONDITIONAL_OPERATOR + 'End';
77
78    private sourceFile: ts.SourceFile;
79    private declaringMethod: ArkMethod;
80    private inBuilderMethod = false;
81    private builderMethodContextFlag = false;
82    private stmtsHaveOriginalText: Set<Stmt> = new Set();
83    private arkValueTransformer: ArkValueTransformer;
84
85    constructor(sourceFile: ts.SourceFile, declaringMethod: ArkMethod) {
86        this.sourceFile = sourceFile;
87        this.declaringMethod = declaringMethod;
88        this.inBuilderMethod = ModelUtils.isArkUIBuilderMethod(declaringMethod);
89        this.arkValueTransformer = new ArkValueTransformer(this, sourceFile, this.declaringMethod);
90    }
91
92    public getLocals(): Set<Local> {
93        return this.arkValueTransformer.getLocals();
94    }
95
96    public getGlobals(): Map<string, GlobalRef> | null {
97        return this.arkValueTransformer.getGlobals();
98    }
99
100    public getThisLocal(): Local {
101        return this.arkValueTransformer.getThisLocal();
102    }
103
104    public getAliasTypeMap(): Map<string, [AliasType, ArkAliasTypeDefineStmt]> {
105        return this.arkValueTransformer.getAliasTypeMap();
106    }
107
108    public prebuildStmts(): Stmt[] {
109        const stmts: Stmt[] = [];
110        let index = 0;
111        for (const methodParameter of this.declaringMethod.getParameters()) {
112            const parameterRef = new ArkParameterRef(index, methodParameter.getType());
113            stmts.push(new ArkAssignStmt(this.arkValueTransformer.addNewLocal(methodParameter.getName(), parameterRef.getType()), parameterRef));
114            index++;
115        }
116
117        const thisRef = new ArkThisRef(this.arkValueTransformer.getThisLocal().getType() as ClassType);
118        stmts.push(new ArkAssignStmt(this.arkValueTransformer.getThisLocal(), thisRef));
119        return stmts;
120    }
121
122    public tsNodeToStmts(node: ts.Node): Stmt[] {
123        let stmts: Stmt[] = [];
124        if (ts.isExpressionStatement(node)) {
125            stmts = this.expressionStatementToStmts(node);
126        } else if (ts.isTypeAliasDeclaration(node)) {
127            stmts = this.typeAliasDeclarationToStmts(node);
128        } else if (ts.isBlock(node)) {
129            stmts = this.blockToStmts(node);
130        } else if (ts.isForStatement(node)) {
131            stmts = this.forStatementToStmts(node);
132        } else if (ts.isForInStatement(node) || ts.isForOfStatement(node)) {
133            stmts = this.rangeForStatementToStmts(node);
134        } else if (ts.isWhileStatement(node)) {
135            stmts = this.whileStatementToStmts(node);
136        } else if (ts.isDoStatement(node)) {
137            stmts = this.doStatementToStmts(node);
138        } else if (ts.isVariableStatement(node)) {
139            stmts = this.variableStatementToStmts(node);
140        } else if (ts.isVariableDeclarationList(node)) {
141            stmts = this.variableDeclarationListToStmts(node);
142        } else if (ts.isIfStatement(node)) {
143            stmts = this.ifStatementToStmts(node);
144        } else if (ts.isBreakStatement(node) || ts.isContinueStatement(node)) {
145            stmts = this.gotoStatementToStmts(node);
146        } else if (ts.isThrowStatement(node)) {
147            stmts = this.throwStatementToStmts(node);
148        } else if (ts.isCatchClause(node)) {
149            stmts = this.catchClauseToStmts(node);
150        } else if (ts.isReturnStatement(node)) {
151            stmts = this.returnStatementToStmts(node);
152        } else if (ts.isFunctionDeclaration(node)) {
153            stmts = this.functionDeclarationToStmts(node);
154        } else if (ts.isExportAssignment(node)) {
155            stmts = this.expressionInExportToStmts(node.expression);
156        } else if (ts.isClassDeclaration(node)) {
157            stmts = this.classDeclarationToStmts(node);
158        } else if (ts.isParameter(node)) {
159            stmts = this.parameterPropertyToStmts(node);
160        }
161
162        this.mapStmtsToTsStmt(stmts, node);
163        if (stmts.length > 0) {
164            IRUtils.setComments(stmts[0], node, this.sourceFile, this.declaringMethod.getDeclaringArkFile().getScene().getOptions());
165        }
166        return stmts;
167    }
168
169    public tsNodeToValueAndStmts(node: ts.Node): ValueAndStmts {
170        return this.arkValueTransformer.tsNodeToValueAndStmts(node);
171    }
172
173    private functionDeclarationToStmts(functionDeclarationNode: ts.FunctionDeclaration): Stmt[] {
174        const declaringClass = this.declaringMethod.getDeclaringArkClass();
175        const arkMethod = new ArkMethod();
176        if (this.builderMethodContextFlag) {
177            ModelUtils.implicitArkUIBuilderMethods.add(arkMethod);
178        }
179        buildArkMethodFromArkClass(functionDeclarationNode, declaringClass, arkMethod, this.sourceFile, this.declaringMethod);
180        return [];
181    }
182
183    private classDeclarationToStmts(node: ts.ClassDeclaration): Stmt[] {
184        const cls = new ArkClass();
185        const declaringArkNamespace = this.declaringMethod.getDeclaringArkClass().getDeclaringArkNamespace();
186        if (declaringArkNamespace) {
187            cls.setDeclaringArkNamespace(declaringArkNamespace);
188        }
189        cls.setDeclaringArkFile(this.declaringMethod.getDeclaringArkFile());
190        buildNormalArkClassFromArkMethod(node, cls, this.sourceFile, this.declaringMethod);
191        return [];
192    }
193
194    // This is only used to add class property assign stmts into constructor when it is with parameter property.
195    private parameterPropertyToStmts(paramNode: ts.ParameterDeclaration): Stmt[] {
196        if (paramNode.modifiers === undefined || !ts.isIdentifier(paramNode.name)) {
197            return [];
198        }
199        const fieldName = paramNode.name.text;
200        const arkClass = this.declaringMethod.getDeclaringArkClass();
201        const fieldSignature = arkClass.getFieldWithName(fieldName)?.getSignature();
202        const paramLocal = Array.from(this.getLocals()).find(local => local.getName() === fieldName);
203        if (fieldSignature === undefined || paramLocal === undefined) {
204            return [];
205        }
206        const leftOp = new ArkInstanceFieldRef(this.getThisLocal(), fieldSignature);
207        const fieldAssignStmt = new ArkAssignStmt(leftOp, paramLocal);
208        fieldAssignStmt.setOperandOriginalPositions([FullPosition.DEFAULT, FullPosition.DEFAULT, FullPosition.DEFAULT]);
209
210        // If the parameter has initializer, the related stmts should be added into class instance init method.
211        const instInitMethodCfg = arkClass.getInstanceInitMethod().getBody()?.getCfg();
212        const instInitStmts = instInitMethodCfg?.getStartingBlock()?.getStmts();
213        if (paramNode.initializer && instInitStmts && instInitMethodCfg) {
214            const {
215                value: instanceInitValue,
216                valueOriginalPositions: instanceInitPositions,
217                stmts: instanceInitStmts,
218            } = this.tsNodeToValueAndStmts(paramNode.initializer);
219            const instanceAssignStmt = new ArkAssignStmt(leftOp, instanceInitValue);
220            instanceAssignStmt.setOperandOriginalPositions([FullPosition.DEFAULT, FullPosition.DEFAULT, ...instanceInitPositions]);
221            const newInstanceInitStmts = [...instanceInitStmts, instanceAssignStmt];
222
223            // All these stmts will be added into instance init method, while that method has completed the building. So all new stmts should set cfg here.
224            newInstanceInitStmts.forEach(stmt => stmt.setCfg(instInitMethodCfg));
225
226            // The last stmt of instance init method is return stmt, so all the initializer stmts should be added before return stmt.
227            instInitStmts.splice(instInitStmts.length - 1, 0, ...newInstanceInitStmts);
228        }
229        return [fieldAssignStmt];
230    }
231
232    private returnStatementToStmts(returnStatement: ts.ReturnStatement): Stmt[] {
233        const stmts: Stmt[] = [];
234        if (returnStatement.expression) {
235            let { value: exprValue, valueOriginalPositions: exprPositions, stmts: exprStmts } = this.tsNodeToValueAndStmts(returnStatement.expression);
236            exprStmts.forEach(stmt => stmts.push(stmt));
237            if (IRUtils.moreThanOneAddress(exprValue)) {
238                ({ value: exprValue, valueOriginalPositions: exprPositions, stmts: exprStmts } = this.generateAssignStmtForValue(exprValue, exprPositions));
239                exprStmts.forEach(stmt => stmts.push(stmt));
240            }
241            const returnStmt = new ArkReturnStmt(exprValue);
242            returnStmt.setOperandOriginalPositions(exprPositions);
243            stmts.push(returnStmt);
244            if (this.declaringMethod.getSubSignature().getReturnType() instanceof UnknownType) {
245                this.declaringMethod.getSubSignature().setReturnType(exprValue.getType());
246            }
247            return stmts;
248        }
249        stmts.push(new ArkReturnVoidStmt());
250        if (this.declaringMethod.getSubSignature().getReturnType() instanceof UnknownType) {
251            if (this.declaringMethod.containsModifier(ModifierType.ASYNC)) {
252                const promise = this.declaringMethod.getDeclaringArkFile().getScene().getSdkGlobal(PROMISE);
253                if (promise instanceof ArkClass) {
254                    this.declaringMethod.getSubSignature().setReturnType(new ClassType(promise.getSignature()));
255                } else {
256                    this.declaringMethod.getSubSignature().setReturnType(new UnclearReferenceType(PROMISE, [VoidType.getInstance()]));
257                }
258            } else {
259                this.declaringMethod.getSubSignature().setReturnType(VoidType.getInstance());
260            }
261        }
262        return stmts;
263    }
264
265    private blockToStmts(block: ts.Block): Stmt[] {
266        const stmts: Stmt[] = [];
267        for (const statement of block.statements) {
268            this.tsNodeToStmts(statement).forEach(stmt => stmts.push(stmt));
269        }
270        return stmts;
271    }
272
273    private expressionStatementToStmts(expressionStatement: ts.ExpressionStatement): Stmt[] {
274        const exprNode = expressionStatement.expression;
275        const { value: exprValue, valueOriginalPositions: exprPositions, stmts: stmts } = this.tsNodeToValueAndStmts(exprNode);
276        if (exprValue instanceof AbstractInvokeExpr) {
277            this.addInvokeStmts(exprValue, exprPositions, stmts);
278        } else if (this.shouldGenerateExtraAssignStmt(exprNode)) {
279            const { stmts: exprStmts } = this.generateAssignStmtForValue(exprValue, exprPositions);
280            exprStmts.forEach(stmt => stmts.push(stmt));
281        }
282        return stmts;
283    }
284
285    private addInvokeStmts(invokeExpr: AbstractInvokeExpr, exprPositions: FullPosition[], stmts: Stmt[]): void {
286        const invokeStmt = new ArkInvokeStmt(invokeExpr);
287        invokeStmt.setOperandOriginalPositions(exprPositions);
288        stmts.push(invokeStmt);
289
290        let hasRepeat: boolean = false;
291        for (const stmt of stmts) {
292            if (stmt instanceof ArkAssignStmt && stmt.getRightOp() instanceof ArkStaticInvokeExpr) {
293                const rightOp = stmt.getRightOp() as ArkStaticInvokeExpr;
294                if (rightOp.getMethodSignature().getMethodSubSignature().getMethodName() === COMPONENT_REPEAT) {
295                    const createMethodSignature = ArkSignatureBuilder.buildMethodSignatureFromClassNameAndMethodName(
296                        COMPONENT_REPEAT,
297                        COMPONENT_CREATE_FUNCTION
298                    );
299                    const createInvokeExpr = new ArkStaticInvokeExpr(createMethodSignature, rightOp.getArgs());
300                    stmt.setRightOp(createInvokeExpr);
301                    hasRepeat = true;
302                }
303            }
304        }
305        if (hasRepeat) {
306            const popMethodSignature = ArkSignatureBuilder.buildMethodSignatureFromClassNameAndMethodName(COMPONENT_REPEAT, COMPONENT_POP_FUNCTION);
307            const popInvokeExpr = new ArkStaticInvokeExpr(popMethodSignature, []);
308            const popInvokeStmt = new ArkInvokeStmt(popInvokeExpr);
309            stmts.push(popInvokeStmt);
310        }
311    }
312
313    private shouldGenerateExtraAssignStmt(expression: ts.Expression): boolean {
314        if (ts.isParenthesizedExpression(expression)) {
315            return this.shouldGenerateExtraAssignStmt(expression.expression);
316        }
317        if (
318            (ts.isBinaryExpression(expression) &&
319                (expression.operatorToken.kind === ts.SyntaxKind.FirstAssignment ||
320                    ArkValueTransformer.isCompoundAssignmentOperator(expression.operatorToken.kind))) ||
321            ts.isEtsComponentExpression(expression) ||
322            ts.isVoidExpression(expression) ||
323            ts.isNewExpression(expression) ||
324            ts.isCallExpression(expression) ||
325            (ts.isPrefixUnaryExpression(expression) &&
326                (expression.operator === ts.SyntaxKind.PlusPlusToken || expression.operator === ts.SyntaxKind.MinusMinusToken)) ||
327            (ts.isPostfixUnaryExpression(expression) &&
328                (expression.operator === ts.SyntaxKind.PlusPlusToken || expression.operator === ts.SyntaxKind.MinusMinusToken))
329        ) {
330            return false;
331        }
332
333        return true;
334    }
335
336    private typeAliasDeclarationToStmts(typeAliasDeclaration: ts.TypeAliasDeclaration): Stmt[] {
337        const aliasName = typeAliasDeclaration.name.text;
338        const rightOp = typeAliasDeclaration.type;
339        let rightType = this.arkValueTransformer.resolveTypeNode(rightOp);
340        if (rightType instanceof AbstractTypeExpr) {
341            rightType = rightType.getType();
342        }
343
344        const aliasType = new AliasType(aliasName, rightType, new AliasTypeSignature(aliasName, this.declaringMethod.getSignature()));
345        if (typeAliasDeclaration.typeParameters) {
346            const genericTypes = buildTypeParameters(typeAliasDeclaration.typeParameters, this.sourceFile, this.declaringMethod);
347            aliasType.setGenericTypes(genericTypes);
348            aliasType.setOriginalType(buildGenericType(rightType, aliasType));
349            rightType = aliasType.getOriginalType();
350        }
351
352        let expr = this.generateAliasTypeExpr(rightOp, aliasType);
353
354        if ((ts.isTypeQueryNode(rightOp) || ts.isTypeReferenceNode(rightOp)) && rightOp.typeArguments) {
355            let realGenericTypes: Type[] = [];
356            rightOp.typeArguments.forEach(typeArgument => {
357                realGenericTypes.push(this.arkValueTransformer.resolveTypeNode(typeArgument));
358            });
359            expr.setRealGenericTypes(realGenericTypes);
360        }
361
362        const modifiers = typeAliasDeclaration.modifiers ? buildModifiers(typeAliasDeclaration) : 0;
363        aliasType.setModifiers(modifiers);
364
365        const aliasTypeDefineStmt = new ArkAliasTypeDefineStmt(aliasType, expr);
366        const leftPosition = FullPosition.buildFromNode(typeAliasDeclaration.name, this.sourceFile);
367        const rightPosition = FullPosition.buildFromNode(rightOp, this.sourceFile);
368        const operandOriginalPositions = [leftPosition, rightPosition];
369        aliasTypeDefineStmt.setOperandOriginalPositions(operandOriginalPositions);
370
371        this.getAliasTypeMap().set(aliasName, [aliasType, aliasTypeDefineStmt]);
372
373        return [aliasTypeDefineStmt];
374    }
375
376    private generateAliasTypeExpr(rightOp: ts.TypeNode, aliasType: AliasType): AliasTypeExpr {
377        let rightType = aliasType.getOriginalType();
378        let expr: AliasTypeExpr;
379        if (ts.isImportTypeNode(rightOp)) {
380            expr = this.resolveImportTypeNode(rightOp);
381        } else if (ts.isTypeQueryNode(rightOp)) {
382            const localName = rightOp.exprName.getText(this.sourceFile);
383            const originalLocal = Array.from(this.arkValueTransformer.getLocals()).find(local => local.getName() === localName);
384            if (originalLocal === undefined || rightType instanceof UnclearReferenceType) {
385                expr = new AliasTypeExpr(new Local(localName, rightType), true);
386            } else {
387                expr = new AliasTypeExpr(originalLocal, true);
388            }
389        } else if (ts.isTypeReferenceNode(rightOp)) {
390            // For type A = B<number> stmt and B is also an alias type with the same scope of A,
391            // rightType here is AliasType with real generic type number.
392            // The originalObject in expr should be the object without real generic type, so try to find it in this scope.
393            if (rightType instanceof AliasType) {
394                const existAliasType = this.getAliasTypeMap().get(rightType.getName());
395                if (existAliasType) {
396                    expr = new AliasTypeExpr(existAliasType[0], false);
397                } else {
398                    expr = new AliasTypeExpr(rightType, false);
399                }
400            } else {
401                expr = new AliasTypeExpr(rightType, false);
402            }
403        } else {
404            expr = new AliasTypeExpr(rightType, false);
405
406            // 对于type A = {x:1, y:2}语句,当前阶段即可精确获取ClassType类型,需找到对应的ArkClass作为originalObject
407            // 对于其他情况此处为UnclearReferenceTye并由类型推导进行查找和处理
408            if (rightType instanceof ClassType) {
409                const classObject = ModelUtils.getClassWithName(rightType.getClassSignature().getClassName(), this.declaringMethod.getDeclaringArkClass());
410                if (classObject) {
411                    expr.setOriginalObject(classObject);
412                }
413            }
414        }
415        return expr;
416    }
417
418    private resolveImportTypeNode(importTypeNode: ts.ImportTypeNode): AliasTypeExpr {
419        const importType = 'typeAliasDefine';
420        let importFrom = '';
421        let importClauseName = '';
422
423        if (ts.isLiteralTypeNode(importTypeNode.argument)) {
424            if (ts.isStringLiteral(importTypeNode.argument.literal)) {
425                importFrom = importTypeNode.argument.literal.text;
426            }
427        }
428
429        const importQualifier = importTypeNode.qualifier;
430        if (importQualifier !== undefined) {
431            importClauseName = importQualifier.getText(this.sourceFile);
432        }
433
434        let importInfo = new ImportInfo();
435        importInfo.build(importClauseName, importType, importFrom, LineColPosition.buildFromNode(importTypeNode, this.sourceFile), 0);
436        importInfo.setDeclaringArkFile(this.declaringMethod.getDeclaringArkFile());
437
438        return new AliasTypeExpr(importInfo, importTypeNode.isTypeOf);
439    }
440
441    public switchStatementToValueAndStmts(switchStatement: ts.SwitchStatement): ValueAndStmts[] {
442        const valueAndStmtsOfSwitchAndCases: ValueAndStmts[] = [];
443        const exprStmts: Stmt[] = [];
444        let { value: exprValue, valueOriginalPositions: exprPositions, stmts: exprTempStmts } = this.tsNodeToValueAndStmts(switchStatement.expression);
445        exprTempStmts.forEach(stmt => exprStmts.push(stmt));
446        if (IRUtils.moreThanOneAddress(exprValue)) {
447            ({ value: exprValue, valueOriginalPositions: exprPositions, stmts: exprTempStmts } = this.generateAssignStmtForValue(exprValue, exprPositions));
448            exprTempStmts.forEach(stmt => exprStmts.push(stmt));
449        }
450        valueAndStmtsOfSwitchAndCases.push({
451            value: exprValue,
452            valueOriginalPositions: exprPositions,
453            stmts: exprStmts,
454        });
455
456        for (const clause of switchStatement.caseBlock.clauses) {
457            if (ts.isCaseClause(clause)) {
458                const clauseStmts: Stmt[] = [];
459                let { value: clauseValue, valueOriginalPositions: clausePositions, stmts: clauseTempStmts } = this.tsNodeToValueAndStmts(clause.expression);
460                clauseTempStmts.forEach(stmt => clauseStmts.push(stmt));
461                if (IRUtils.moreThanOneAddress(clauseValue)) {
462                    ({
463                        value: clauseValue,
464                        valueOriginalPositions: clausePositions,
465                        stmts: clauseTempStmts,
466                    } = this.generateAssignStmtForValue(clauseValue, clausePositions));
467                    clauseTempStmts.forEach(stmt => clauseStmts.push(stmt));
468                }
469                valueAndStmtsOfSwitchAndCases.push({
470                    value: clauseValue,
471                    valueOriginalPositions: clausePositions,
472                    stmts: clauseStmts,
473                });
474            }
475        }
476        return valueAndStmtsOfSwitchAndCases;
477    }
478
479    private forStatementToStmts(forStatement: ts.ForStatement): Stmt[] {
480        const stmts: Stmt[] = [];
481        if (forStatement.initializer) {
482            this.tsNodeToValueAndStmts(forStatement.initializer).stmts.forEach(stmt => stmts.push(stmt));
483        }
484        const dummyInitializerStmt = new DummyStmt(ArkIRTransformer.DUMMY_LOOP_INITIALIZER_STMT);
485        stmts.push(dummyInitializerStmt);
486
487        if (forStatement.condition) {
488            const { value: conditionValue, stmts: conditionStmts } = this.arkValueTransformer.conditionToValueAndStmts(forStatement.condition);
489            conditionStmts.forEach(stmt => stmts.push(stmt));
490            stmts.push(new ArkIfStmt(conditionValue as ArkConditionExpr));
491        } else {
492            // The omitted condition always evaluates to true.
493            const trueConstant = ValueUtil.getBooleanConstant(true);
494            const conditionExpr = new ArkConditionExpr(trueConstant, trueConstant, RelationalBinaryOperator.Equality);
495            stmts.push(new ArkIfStmt(conditionExpr));
496        }
497        if (forStatement.incrementor) {
498            this.tsNodeToValueAndStmts(forStatement.incrementor).stmts.forEach(stmt => stmts.push(stmt));
499        }
500        return stmts;
501    }
502
503    private rangeForStatementToStmts(forOfStatement: ts.ForOfStatement | ts.ForInStatement): Stmt[] {
504        const stmts: Stmt[] = [];
505        let { value: iterableValue, valueOriginalPositions: iterablePositions, stmts: iterableStmts } = this.tsNodeToValueAndStmts(forOfStatement.expression);
506        iterableStmts.forEach(stmt => stmts.push(stmt));
507        if (!(iterableValue instanceof Local)) {
508            ({
509                value: iterableValue,
510                valueOriginalPositions: iterablePositions,
511                stmts: iterableStmts,
512            } = this.generateAssignStmtForValue(iterableValue, iterablePositions));
513            iterableStmts.forEach(stmt => stmts.push(stmt));
514        }
515        const iteratorMethodSubSignature = new MethodSubSignature(Builtin.ITERATOR_FUNCTION, [], Builtin.ITERATOR_CLASS_TYPE);
516        const iteratorMethodSignature = new MethodSignature(ClassSignature.DEFAULT, iteratorMethodSubSignature);
517        const iteratorInvokeExpr = new ArkInstanceInvokeExpr(iterableValue as Local, iteratorMethodSignature, []);
518        const iteratorInvokeExprPositions = [iterablePositions[0], ...iterablePositions];
519        const {
520            value: iterator,
521            valueOriginalPositions: iteratorPositions,
522            stmts: iteratorStmts,
523        } = this.generateAssignStmtForValue(iteratorInvokeExpr, iteratorInvokeExprPositions);
524        iteratorStmts.forEach(stmt => stmts.push(stmt));
525        (iterator as Local).setType(Builtin.ITERATOR_CLASS_TYPE);
526
527        const nextMethodSubSignature = new MethodSubSignature(Builtin.ITERATOR_NEXT, [], Builtin.ITERATOR_RESULT_CLASS_TYPE);
528        const nextMethodSignature = new MethodSignature(ClassSignature.DEFAULT, nextMethodSubSignature);
529        const iteratorNextInvokeExpr = new ArkInstanceInvokeExpr(iterator as Local, nextMethodSignature, []);
530        const iteratorNextInvokeExprPositions = [iteratorPositions[0], ...iteratorPositions];
531        const {
532            value: iteratorResult,
533            valueOriginalPositions: iteratorResultPositions,
534            stmts: iteratorResultStmts,
535        } = this.generateAssignStmtForValue(iteratorNextInvokeExpr, iteratorNextInvokeExprPositions);
536        iteratorResultStmts.forEach(stmt => stmts.push(stmt));
537        (iteratorResult as Local).setType(Builtin.ITERATOR_RESULT_CLASS_TYPE);
538        const doneFieldSignature = new FieldSignature(Builtin.ITERATOR_RESULT_DONE, Builtin.ITERATOR_RESULT_CLASS_SIGNATURE, BooleanType.getInstance(), false);
539        const doneFieldRef = new ArkInstanceFieldRef(iteratorResult as Local, doneFieldSignature);
540        const doneFieldRefPositions = [iteratorResultPositions[0], ...iteratorResultPositions];
541        const {
542            value: doneFlag,
543            valueOriginalPositions: doneFlagPositions,
544            stmts: doneFlagStmts,
545        } = this.generateAssignStmtForValue(doneFieldRef, doneFieldRefPositions);
546        doneFlagStmts.forEach(stmt => stmts.push(stmt));
547        (doneFlag as Local).setType(BooleanType.getInstance());
548        const conditionExpr = new ArkConditionExpr(doneFlag, ValueUtil.getBooleanConstant(true), RelationalBinaryOperator.Equality);
549        const conditionExprPositions = [doneFlagPositions[0], ...doneFlagPositions, FullPosition.DEFAULT];
550        const ifStmt = new ArkIfStmt(conditionExpr);
551        ifStmt.setOperandOriginalPositions(conditionExprPositions);
552        stmts.push(ifStmt);
553
554        const valueFieldSignature = new FieldSignature(
555            Builtin.ITERATOR_RESULT_VALUE,
556            Builtin.ITERATOR_RESULT_CLASS_SIGNATURE,
557            UnknownType.getInstance(),
558            false
559        );
560        const valueFieldRef = new ArkInstanceFieldRef(iteratorResult as Local, valueFieldSignature);
561        const valueFieldRefPositions = [iteratorResultPositions[0], ...iteratorResultPositions];
562        const {
563            value: yieldValue,
564            valueOriginalPositions: yieldValuePositions,
565            stmts: yieldValueStmts,
566        } = this.generateAssignStmtForValue(valueFieldRef, valueFieldRefPositions);
567        yieldValueStmts.forEach(stmt => stmts.push(stmt));
568
569        const castExpr = new ArkCastExpr(yieldValue, UnknownType.getInstance());
570        const castExprPositions = [yieldValuePositions[0], ...yieldValuePositions];
571        const initializerNode = forOfStatement.initializer;
572        if (ts.isVariableDeclarationList(initializerNode)) {
573            const isConst = (initializerNode.flags & ts.NodeFlags.Const) !== 0;
574            const {
575                value: initValue,
576                valueOriginalPositions: initOriPos,
577                stmts: initStmts,
578            } = this.arkValueTransformer.variableDeclarationToValueAndStmts(initializerNode.declarations[0], isConst, false);
579            const assignStmt = new ArkAssignStmt(initValue, castExpr);
580            assignStmt.setOperandOriginalPositions([...initOriPos, ...castExprPositions]);
581            stmts.push(assignStmt);
582            initStmts.forEach(stmt => stmts.push(stmt));
583        } else {
584            // initializer maybe an expression
585            const { value: initValue, valueOriginalPositions: initOriPos, stmts: initStmts } = this.tsNodeToValueAndStmts(initializerNode);
586            const assignStmt = new ArkAssignStmt(initValue, castExpr);
587            assignStmt.setOperandOriginalPositions([...initOriPos, ...castExprPositions]);
588            initStmts.forEach(stmt => stmts.push(stmt));
589            stmts.push(assignStmt);
590        }
591        return stmts;
592    }
593
594    private whileStatementToStmts(whileStatement: ts.WhileStatement): Stmt[] {
595        const stmts: Stmt[] = [];
596        const dummyInitializerStmt = new DummyStmt(ArkIRTransformer.DUMMY_LOOP_INITIALIZER_STMT);
597        stmts.push(dummyInitializerStmt);
598
599        const { value: conditionExpr, stmts: conditionStmts } = this.arkValueTransformer.conditionToValueAndStmts(whileStatement.expression);
600        conditionStmts.forEach(stmt => stmts.push(stmt));
601        stmts.push(new ArkIfStmt(conditionExpr as ArkConditionExpr));
602        return stmts;
603    }
604
605    private doStatementToStmts(doStatement: ts.DoStatement): Stmt[] {
606        const stmts: Stmt[] = [];
607        const { value: conditionExpr, stmts: conditionStmts } = this.arkValueTransformer.conditionToValueAndStmts(doStatement.expression);
608        conditionStmts.forEach(stmt => stmts.push(stmt));
609        stmts.push(new ArkIfStmt(conditionExpr as ArkConditionExpr));
610        return stmts;
611    }
612
613    private variableStatementToStmts(variableStatement: ts.VariableStatement): Stmt[] {
614        return this.variableDeclarationListToStmts(variableStatement.declarationList);
615    }
616
617    private variableDeclarationListToStmts(variableDeclarationList: ts.VariableDeclarationList): Stmt[] {
618        return this.arkValueTransformer.variableDeclarationListToValueAndStmts(variableDeclarationList).stmts;
619    }
620
621    private ifStatementToStmts(ifStatement: ts.IfStatement): Stmt[] {
622        const stmts: Stmt[] = [];
623        if (this.inBuilderMethod) {
624            const {
625                value: conditionExpr,
626                valueOriginalPositions: conditionExprPositions,
627                stmts: conditionStmts,
628            } = this.arkValueTransformer.conditionToValueAndStmts(ifStatement.expression);
629            conditionStmts.forEach(stmt => stmts.push(stmt));
630            const createMethodSignature = ArkSignatureBuilder.buildMethodSignatureFromClassNameAndMethodName(COMPONENT_IF, COMPONENT_CREATE_FUNCTION);
631            const {
632                value: conditionLocal,
633                valueOriginalPositions: conditionLocalPositions,
634                stmts: assignConditionStmts,
635            } = this.generateAssignStmtForValue(conditionExpr, conditionExprPositions);
636            assignConditionStmts.forEach(stmt => stmts.push(stmt));
637            const createInvokeExpr = new ArkStaticInvokeExpr(createMethodSignature, [conditionLocal]);
638            const createInvokeExprPositions = [conditionLocalPositions[0], ...conditionLocalPositions];
639            const { stmts: createStmts } = this.generateAssignStmtForValue(createInvokeExpr, createInvokeExprPositions);
640            createStmts.forEach(stmt => stmts.push(stmt));
641            const branchMethodSignature = ArkSignatureBuilder.buildMethodSignatureFromClassNameAndMethodName(COMPONENT_IF, COMPONENT_BRANCH_FUNCTION);
642            const branchInvokeExpr = new ArkStaticInvokeExpr(branchMethodSignature, [ValueUtil.getOrCreateNumberConst(0)]);
643            const branchInvokeExprPositions = [conditionLocalPositions[0], FullPosition.DEFAULT];
644            const branchInvokeStmt = new ArkInvokeStmt(branchInvokeExpr);
645            branchInvokeStmt.setOperandOriginalPositions(branchInvokeExprPositions);
646            stmts.push(branchInvokeStmt);
647            this.tsNodeToStmts(ifStatement.thenStatement).forEach(stmt => stmts.push(stmt));
648            if (ifStatement.elseStatement) {
649                const branchElseMethodSignature = ArkSignatureBuilder.buildMethodSignatureFromClassNameAndMethodName(COMPONENT_IF, COMPONENT_BRANCH_FUNCTION);
650                const branchElseInvokeExpr = new ArkStaticInvokeExpr(branchElseMethodSignature, [ValueUtil.getOrCreateNumberConst(1)]);
651                const branchElseInvokeExprPositions = [FullPosition.buildFromNode(ifStatement.elseStatement, this.sourceFile), FullPosition.DEFAULT];
652                const branchElseInvokeStmt = new ArkInvokeStmt(branchElseInvokeExpr);
653                branchElseInvokeStmt.setOperandOriginalPositions(branchElseInvokeExprPositions);
654                stmts.push(branchElseInvokeStmt);
655
656                this.tsNodeToStmts(ifStatement.elseStatement).forEach(stmt => stmts.push(stmt));
657            }
658            const popMethodSignature = ArkSignatureBuilder.buildMethodSignatureFromClassNameAndMethodName(COMPONENT_IF, COMPONENT_POP_FUNCTION);
659            const popInvokeExpr = new ArkStaticInvokeExpr(popMethodSignature, []);
660            const popInvokeStmt = new ArkInvokeStmt(popInvokeExpr);
661            stmts.push(popInvokeStmt);
662        } else {
663            const {
664                value: conditionExpr,
665                valueOriginalPositions: conditionExprPositions,
666                stmts: conditionStmts,
667            } = this.arkValueTransformer.conditionToValueAndStmts(ifStatement.expression);
668            conditionStmts.forEach(stmt => stmts.push(stmt));
669            const ifStmt = new ArkIfStmt(conditionExpr as ArkConditionExpr);
670            ifStmt.setOperandOriginalPositions(conditionExprPositions);
671            stmts.push(ifStmt);
672        }
673        return stmts;
674    }
675
676    private gotoStatementToStmts(gotoStatement: ts.BreakStatement | ts.ContinueStatement): Stmt[] {
677        return [];
678    }
679
680    private throwStatementToStmts(throwStatement: ts.ThrowStatement): Stmt[] {
681        const stmts: Stmt[] = [];
682        const { value: throwValue, valueOriginalPositions: throwValuePositions, stmts: throwStmts } = this.tsNodeToValueAndStmts(throwStatement.expression);
683        throwStmts.forEach(stmt => stmts.push(stmt));
684        const throwStmt = new ArkThrowStmt(throwValue);
685        throwStmt.setOperandOriginalPositions(throwValuePositions);
686        stmts.push(throwStmt);
687        return stmts;
688    }
689
690    private catchClauseToStmts(catchClause: ts.CatchClause): Stmt[] {
691        const stmts: Stmt[] = [];
692        if (catchClause.variableDeclaration) {
693            const {
694                value: catchValue,
695                valueOriginalPositions: catchOriPos,
696                stmts: catchStmts,
697            } = this.arkValueTransformer.variableDeclarationToValueAndStmts(catchClause.variableDeclaration, false, false);
698            const caughtExceptionRef = new ArkCaughtExceptionRef(UnknownType.getInstance());
699            const assignStmt = new ArkAssignStmt(catchValue, caughtExceptionRef);
700            assignStmt.setOperandOriginalPositions(catchOriPos);
701            stmts.push(assignStmt);
702            catchStmts.forEach(stmt => stmts.push(stmt));
703        }
704        return stmts;
705    }
706
707    private expressionInExportToStmts(expression: ts.Node): Stmt[] {
708        if (ts.isNewExpression(expression) || ts.isObjectLiteralExpression(expression)) {
709            return this.newClassInExportToStmts(expression);
710        }
711        return [];
712    }
713
714    private newClassInExportToStmts(expression: ts.NewExpression | ts.ObjectLiteralExpression): Stmt[] {
715        let stmts: Stmt[] = [];
716        let { value: rightValue, valueOriginalPositions: rightPositions, stmts: rightStmts } = this.tsNodeToValueAndStmts(expression);
717        rightStmts.forEach(stmt => stmts.push(stmt));
718        let leftValue = this.arkValueTransformer.addNewLocal(DEFAULT);
719        let leftPositions = rightPositions;
720        const assignStmt = new ArkAssignStmt(leftValue, rightValue);
721        assignStmt.setOperandOriginalPositions([...leftPositions, ...rightPositions]);
722        stmts.push(assignStmt);
723        return stmts;
724    }
725
726    public mapStmtsToTsStmt(stmts: Stmt[], node: ts.Node): void {
727        for (const stmt of stmts) {
728            if (!this.stmtsHaveOriginalText.has(stmt)) {
729                this.stmtsHaveOriginalText.add(stmt);
730                stmt.setOriginPositionInfo(LineColPosition.buildFromNode(node, this.sourceFile));
731                stmt.setOriginalText(node.getText(this.sourceFile));
732            }
733        }
734    }
735
736    public static tokenToUnaryOperator(token: ts.SyntaxKind): UnaryOperator | null {
737        switch (token) {
738            case ts.SyntaxKind.MinusToken:
739                return UnaryOperator.Neg;
740            case ts.SyntaxKind.TildeToken:
741                return UnaryOperator.BitwiseNot;
742            case ts.SyntaxKind.ExclamationToken:
743                return UnaryOperator.LogicalNot;
744            default:
745        }
746        return null;
747    }
748
749    public static tokenToBinaryOperator(token: ts.SyntaxKind): BinaryOperator | null {
750        switch (token) {
751            case ts.SyntaxKind.QuestionQuestionToken:
752                return NormalBinaryOperator.NullishCoalescing;
753            case ts.SyntaxKind.AsteriskAsteriskToken:
754                return NormalBinaryOperator.Exponentiation;
755            case ts.SyntaxKind.SlashToken:
756                return NormalBinaryOperator.Division;
757            case ts.SyntaxKind.PlusToken:
758                return NormalBinaryOperator.Addition;
759            case ts.SyntaxKind.MinusToken:
760                return NormalBinaryOperator.Subtraction;
761            case ts.SyntaxKind.AsteriskToken:
762                return NormalBinaryOperator.Multiplication;
763            case ts.SyntaxKind.PercentToken:
764                return NormalBinaryOperator.Remainder;
765            case ts.SyntaxKind.LessThanLessThanToken:
766                return NormalBinaryOperator.LeftShift;
767            case ts.SyntaxKind.GreaterThanGreaterThanToken:
768                return NormalBinaryOperator.RightShift;
769            case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
770                return NormalBinaryOperator.UnsignedRightShift;
771            case ts.SyntaxKind.AmpersandToken:
772                return NormalBinaryOperator.BitwiseAnd;
773            case ts.SyntaxKind.BarToken:
774                return NormalBinaryOperator.BitwiseOr;
775            case ts.SyntaxKind.CaretToken:
776                return NormalBinaryOperator.BitwiseXor;
777            case ts.SyntaxKind.AmpersandAmpersandToken:
778                return NormalBinaryOperator.LogicalAnd;
779            case ts.SyntaxKind.BarBarToken:
780                return NormalBinaryOperator.LogicalOr;
781            case ts.SyntaxKind.LessThanToken:
782                return RelationalBinaryOperator.LessThan;
783            case ts.SyntaxKind.LessThanEqualsToken:
784                return RelationalBinaryOperator.LessThanOrEqual;
785            case ts.SyntaxKind.GreaterThanToken:
786                return RelationalBinaryOperator.GreaterThan;
787            case ts.SyntaxKind.GreaterThanEqualsToken:
788                return RelationalBinaryOperator.GreaterThanOrEqual;
789            case ts.SyntaxKind.EqualsEqualsToken:
790                return RelationalBinaryOperator.Equality;
791            case ts.SyntaxKind.ExclamationEqualsToken:
792                return RelationalBinaryOperator.InEquality;
793            case ts.SyntaxKind.EqualsEqualsEqualsToken:
794                return RelationalBinaryOperator.StrictEquality;
795            case ts.SyntaxKind.ExclamationEqualsEqualsToken:
796                return RelationalBinaryOperator.StrictInequality;
797            default:
798        }
799        return null;
800    }
801
802    public generateAssignStmtForValue(value: Value, valueOriginalPositions: FullPosition[]): ValueAndStmts {
803        const leftOp = this.arkValueTransformer.generateTempLocal(value.getType());
804        const leftOpPosition = valueOriginalPositions[0];
805        const assignStmt = new ArkAssignStmt(leftOp, value);
806        assignStmt.setOperandOriginalPositions([leftOpPosition, ...valueOriginalPositions]);
807        return {
808            value: leftOp,
809            valueOriginalPositions: [leftOpPosition],
810            stmts: [assignStmt],
811        };
812    }
813
814    public generateIfStmtForValues(
815        leftValue: Value,
816        leftOpOriginalPositions: FullPosition[],
817        rightValue: Value,
818        rightOpOriginalPositions: FullPosition[]
819    ): Stmt[] {
820        const stmts: Stmt[] = [];
821        if (IRUtils.moreThanOneAddress(leftValue)) {
822            const {
823                value: tempLeftValue,
824                valueOriginalPositions: tempLeftPositions,
825                stmts: leftStmts,
826            } = this.generateAssignStmtForValue(leftValue, leftOpOriginalPositions);
827            leftStmts.forEach(stmt => stmts.push(stmt));
828            leftValue = tempLeftValue;
829            leftOpOriginalPositions = tempLeftPositions;
830        }
831        if (IRUtils.moreThanOneAddress(rightValue)) {
832            const {
833                value: tempRightValue,
834                valueOriginalPositions: tempRightPositions,
835                stmts: rightStmts,
836            } = this.generateAssignStmtForValue(rightValue, rightOpOriginalPositions);
837            rightStmts.forEach(stmt => stmts.push(stmt));
838            rightValue = tempRightValue;
839            rightOpOriginalPositions = tempRightPositions;
840        }
841
842        const conditionExpr = new ArkConditionExpr(leftValue, rightValue, RelationalBinaryOperator.Equality);
843        const conditionPositions = [...leftOpOriginalPositions, ...rightOpOriginalPositions];
844        const ifStmt = new ArkIfStmt(conditionExpr);
845        ifStmt.setOperandOriginalPositions([...conditionPositions]);
846        stmts.push(ifStmt);
847        return stmts;
848    }
849
850    public setBuilderMethodContextFlag(builderMethodContextFlag: boolean): void {
851        this.builderMethodContextFlag = builderMethodContextFlag;
852    }
853}
854