• 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 { TypeInference } from '../common/TypeInference';
17import { BasicBlock } from '../graph/BasicBlock';
18import { MethodSignature } from '../model/ArkSignature';
19import { Local } from './Local';
20import {
21    AliasType,
22    AnyType,
23    ArrayType,
24    BigIntType,
25    BooleanType,
26    ClassType,
27    FunctionType,
28    GenericType,
29    NullType,
30    NumberType,
31    StringType,
32    Type,
33    UnclearReferenceType,
34    UndefinedType,
35    UnionType,
36    UnknownType,
37} from './Type';
38import { Value } from './Value';
39import { AbstractFieldRef, AbstractRef, ArkInstanceFieldRef, ArkStaticFieldRef } from './Ref';
40import { EMPTY_STRING, ValueUtil } from '../common/ValueUtil';
41import { ArkMethod } from '../model/ArkMethod';
42import { UNKNOWN_FILE_NAME } from '../common/Const';
43import { IRInference } from '../common/IRInference';
44import { ImportInfo } from '../model/ArkImport';
45import { ArkClass, ClassCategory } from '../model/ArkClass';
46import { ArkField } from '../model/ArkField';
47import { ModelUtils } from '../common/ModelUtils';
48
49/**
50 * @category core/base/expr
51 */
52export abstract class AbstractExpr implements Value {
53    abstract getUses(): Value[];
54
55    abstract getType(): Type;
56
57    abstract toString(): string;
58
59    public inferType(arkMethod: ArkMethod): AbstractExpr {
60        return this;
61    }
62}
63
64export abstract class AbstractInvokeExpr extends AbstractExpr {
65    private methodSignature: MethodSignature;
66    private args: Value[];
67    private realGenericTypes?: Type[]; //新增
68
69    constructor(methodSignature: MethodSignature, args: Value[], realGenericTypes?: Type[]) {
70        super();
71        this.methodSignature = methodSignature;
72        this.args = args;
73        this.realGenericTypes = realGenericTypes;
74    }
75
76    /**
77     * Get method Signature. The method signature is consist of ClassSignature and MethodSubSignature.
78     * It is the unique flag of a method. It is usually used to compose a expression string in ArkIRTransformer.
79     * @returns The class method signature, such as ArkStaticInvokeExpr.
80     * @example
81     * 1. 3AC information composed of getMethodSignature ().
82
83     ```typescript
84     let strs: string[] = [];
85     strs.push('staticinvoke <');
86     strs.push(this.getMethodSignature().toString());
87     strs.push('>(');
88     ```
89     */
90    public getMethodSignature(): MethodSignature {
91        return this.methodSignature;
92    }
93
94    public setMethodSignature(newMethodSignature: MethodSignature): void {
95        this.methodSignature = newMethodSignature;
96    }
97
98    /**
99     * Returns an argument used in the expression according to its index.
100     * @param index - the index of the argument.
101     * @returns An argument used in the expression.
102     */
103    public getArg(index: number): Value {
104        return this.args[index];
105    }
106
107    /**
108     * Returns an **array** of arguments used in the expression.
109     * @returns An **array** of arguments used in the expression.
110     * @example
111     * 1. get args number.
112
113     ```typescript
114     const argsNum = expr.getArgs().length;
115     if (argsNum < 5) {
116     ... ...
117     }
118     ```
119
120     2. iterate arg based on expression
121
122     ```typescript
123     for (const arg of this.getArgs()) {
124     strs.push(arg.toString());
125     strs.push(', ');
126     }
127     ```
128     */
129    public getArgs(): Value[] {
130        return this.args;
131    }
132
133    public setArgs(newArgs: Value[]): void {
134        this.args = newArgs;
135    }
136
137    public getType(): Type {
138        const type = this.methodSignature.getType();
139        if (TypeInference.checkType(type, t => t instanceof GenericType || t instanceof AnyType) &&
140            this.realGenericTypes) {
141            return TypeInference.replaceTypeWithReal(type, this.realGenericTypes);
142        }
143        return type;
144    }
145
146    public getRealGenericTypes(): Type[] | undefined {
147        return this.realGenericTypes;
148    }
149
150    public setRealGenericTypes(realTypes: Type[] | undefined): void {
151        if (realTypes) {
152            this.realGenericTypes = realTypes;
153        }
154    }
155
156    public getUses(): Value[] {
157        let uses: Value[] = [];
158        uses.push(...this.args);
159        for (const arg of this.args) {
160            uses.push(...arg.getUses());
161        }
162        return uses;
163    }
164}
165
166export class ArkInstanceInvokeExpr extends AbstractInvokeExpr {
167    private base: Local;
168
169    constructor(base: Local, methodSignature: MethodSignature, args: Value[], realGenericTypes?: Type[]) {
170        super(methodSignature, args, realGenericTypes);
171        this.base = base;
172    }
173
174    /**
175     * Returns the local of the instance of invoke expression.
176     * @returns The local of the invoke expression's instance..
177     */
178    public getBase(): Local {
179        return this.base;
180    }
181
182    public setBase(newBase: Local): void {
183        this.base = newBase;
184    }
185
186    /**
187     * Returns an **array** of values used in this invoke expression,
188     * including all arguments and values each arguments used.
189     * For {@link ArkInstanceInvokeExpr}, the return also contains the caller base and uses of base.
190     * @returns An **array** of arguments used in the invoke expression.
191     */
192    public getUses(): Value[] {
193        let uses: Value[] = [];
194        uses.push(this.base);
195        uses.push(...this.base.getUses());
196        uses.push(...this.getArgs());
197        for (const arg of this.getArgs()) {
198            uses.push(...arg.getUses());
199        }
200        return uses;
201    }
202
203    public toString(): string {
204        let strs: string[] = [];
205        strs.push('instanceinvoke ');
206        strs.push(this.base.toString());
207        strs.push('.<');
208        strs.push(this.getMethodSignature().toString());
209        strs.push('>(');
210        if (this.getArgs().length > 0) {
211            for (const arg of this.getArgs()) {
212                strs.push(arg.toString());
213                strs.push(', ');
214            }
215            strs.pop();
216        }
217        strs.push(')');
218        return strs.join('');
219    }
220
221    public inferType(arkMethod: ArkMethod): AbstractInvokeExpr {
222        return IRInference.inferInstanceInvokeExpr(this, arkMethod);
223    }
224}
225
226export class ArkStaticInvokeExpr extends AbstractInvokeExpr {
227    constructor(methodSignature: MethodSignature, args: Value[], realGenericTypes?: Type[]) {
228        super(methodSignature, args, realGenericTypes);
229    }
230
231    public toString(): string {
232        let strs: string[] = [];
233        strs.push('staticinvoke <');
234        strs.push(this.getMethodSignature().toString());
235        strs.push('>(');
236        if (this.getArgs().length > 0) {
237            for (const arg of this.getArgs()) {
238                strs.push(arg.toString());
239                strs.push(', ');
240            }
241            strs.pop();
242        }
243        strs.push(')');
244        return strs.join('');
245    }
246
247    public inferType(arkMethod: ArkMethod): AbstractInvokeExpr {
248        return IRInference.inferStaticInvokeExpr(this, arkMethod);
249    }
250}
251
252/**
253 *     1. Local PtrInvokeExpr
254 *
255 *      ```typescript
256 *      func foo():void {
257 *      }
258 *      let ptr = foo;
259 *      ptr();
260 *      ```
261 *     2. FieldRef PtrInvokeExpr
262 *
263 *      ```typescript
264 *      class A {
265 *          b:()=> void()
266 *      }
267 *      new A().b()
268 *      ```
269 */
270export class ArkPtrInvokeExpr extends AbstractInvokeExpr {
271    private funPtr: Local | AbstractFieldRef;
272
273    constructor(methodSignature: MethodSignature, ptr: Local | AbstractFieldRef, args: Value[], realGenericTypes?: Type[]) {
274        super(methodSignature, args, realGenericTypes);
275        this.funPtr = ptr;
276    }
277
278    public setFunPtrLocal(ptr: Local | AbstractFieldRef): void {
279        this.funPtr = ptr;
280    }
281
282    public getFuncPtrLocal(): Local | AbstractFieldRef {
283        return this.funPtr;
284    }
285
286    public toString(): string {
287        let strs: string[] = [];
288        strs.push('ptrinvoke <');
289        let ptrName: string = '';
290        if (this.funPtr instanceof Local) {
291            ptrName = this.funPtr.getName();
292        } else if (this.funPtr instanceof ArkInstanceFieldRef) {
293            ptrName = this.funPtr.getBase().getName() + '.' + this.funPtr.getFieldName();
294        } else if (this.funPtr instanceof ArkStaticFieldRef) {
295            ptrName = this.funPtr.getFieldName();
296        }
297        strs.push(this.getMethodSignature().toString(ptrName));
298        strs.push('>(');
299        if (this.getArgs().length > 0) {
300            for (const arg of this.getArgs()) {
301                strs.push(arg.toString());
302                strs.push(', ');
303            }
304            strs.pop();
305        }
306        strs.push(')');
307        return strs.join('');
308    }
309
310    public getUses(): Value[] {
311        let uses: Value[] = [];
312        uses.push(this.getFuncPtrLocal());
313        uses.push(...this.getArgs());
314        for (const arg of this.getArgs()) {
315            uses.push(...arg.getUses());
316        }
317        return uses;
318    }
319}
320
321export class ArkNewExpr extends AbstractExpr {
322    private classType: ClassType;
323
324    constructor(classType: ClassType) {
325        super();
326        this.classType = classType;
327    }
328
329    public getClassType(): ClassType {
330        return this.classType;
331    }
332
333    public getUses(): Value[] {
334        return [];
335    }
336
337    public getType(): Type {
338        return this.classType;
339    }
340
341    public toString(): string {
342        return 'new ' + this.classType;
343    }
344
345    public inferType(arkMethod: ArkMethod): ArkNewExpr {
346        const classSignature = this.classType.getClassSignature();
347        if (classSignature.getDeclaringFileSignature().getFileName() === UNKNOWN_FILE_NAME) {
348            const className = classSignature.getClassName();
349            let type: Type | null | undefined = ModelUtils.findDeclaredLocal(new Local(className), arkMethod, 1)?.getType();
350            if (TypeInference.isUnclearType(type)) {
351                type = TypeInference.inferUnclearRefName(className, arkMethod.getDeclaringArkClass());
352            }
353            if (type instanceof AliasType) {
354                const originalType = TypeInference.replaceAliasType(type);
355                if (originalType instanceof FunctionType) {
356                    type = originalType.getMethodSignature().getMethodSubSignature().getReturnType();
357                } else {
358                    type = originalType;
359                }
360            }
361            if (type && type instanceof ClassType) {
362                const instanceType = this.constructorSignature(type, arkMethod) ?? type;
363                this.classType.setClassSignature(instanceType.getClassSignature());
364                TypeInference.inferRealGenericTypes(this.classType.getRealGenericTypes(), arkMethod.getDeclaringArkClass());
365            }
366        }
367        return this;
368    }
369
370    private constructorSignature(type: ClassType, arkMethod: ArkMethod): ClassType | undefined {
371        const classConstructor = arkMethod.getDeclaringArkFile().getScene().getClass(type.getClassSignature());
372        if (classConstructor?.getCategory() === ClassCategory.INTERFACE) {
373            const type = classConstructor.getMethodWithName('construct-signature')?.getReturnType();
374            if (type) {
375                const returnType = TypeInference.replaceAliasType(type);
376                return returnType instanceof ClassType ? returnType : undefined;
377            }
378        }
379        return undefined;
380    }
381}
382
383export class ArkNewArrayExpr extends AbstractExpr {
384    private baseType: Type;
385    private size: Value;
386
387    private fromLiteral: boolean;
388
389    constructor(baseType: Type, size: Value, fromLiteral: boolean = false) {
390        super();
391        this.baseType = baseType;
392        this.size = size;
393        this.fromLiteral = fromLiteral;
394    }
395
396    public getSize(): Value {
397        return this.size;
398    }
399
400    public setSize(newSize: Value): void {
401        this.size = newSize;
402    }
403
404    public getType(): ArrayType {
405        return new ArrayType(this.baseType, 1);
406    }
407
408    public getBaseType(): Type {
409        return this.baseType;
410    }
411
412    public setBaseType(newType: Type): void {
413        this.baseType = newType;
414    }
415
416    public isFromLiteral(): boolean {
417        return this.fromLiteral;
418    }
419
420    public inferType(arkMethod: ArkMethod): ArkNewArrayExpr {
421        const type = TypeInference.inferUnclearedType(this.baseType, arkMethod.getDeclaringArkClass());
422        if (type) {
423            this.baseType = type;
424        }
425        return this;
426    }
427
428    public getUses(): Value[] {
429        let uses: Value[] = [this.size];
430        uses.push(...this.size.getUses());
431        return uses;
432    }
433
434    public toString(): string {
435        return 'newarray (' + this.baseType + ')[' + this.size + ']';
436    }
437}
438
439export class ArkDeleteExpr extends AbstractExpr {
440    private field: AbstractFieldRef;
441
442    constructor(field: AbstractFieldRef) {
443        super();
444        this.field = field;
445    }
446
447    public getField(): AbstractFieldRef {
448        return this.field;
449    }
450
451    public setField(newField: AbstractFieldRef): void {
452        this.field = newField;
453    }
454
455    public getType(): Type {
456        return BooleanType.getInstance();
457    }
458
459    public getUses(): Value[] {
460        const uses: Value[] = [];
461        uses.push(this.field);
462        uses.push(...this.field.getUses());
463        return uses;
464    }
465
466    public toString(): string {
467        return 'delete ' + this.field;
468    }
469}
470
471export class ArkAwaitExpr extends AbstractExpr {
472    private promise: Value;
473
474    constructor(promise: Value) {
475        super();
476        this.promise = promise;
477    }
478
479    public getPromise(): Value {
480        return this.promise;
481    }
482
483    public setPromise(newPromise: Value): void {
484        this.promise = newPromise;
485    }
486
487    public getType(): Type {
488        const type = this.promise.getType();
489        if (type instanceof UnclearReferenceType) {
490            return type.getGenericTypes()[0];
491        } else if (type instanceof ClassType) {
492            return type.getRealGenericTypes()?.[0] ?? type;
493        }
494        return type;
495    }
496
497    public inferType(arkMethod: ArkMethod): ArkAwaitExpr {
498        TypeInference.inferValueType(this.promise, arkMethod);
499        return this;
500    }
501
502    public getUses(): Value[] {
503        const uses: Value[] = [];
504        uses.push(this.promise);
505        uses.push(...this.promise.getUses());
506        return uses;
507    }
508
509    public toString(): string {
510        const str = 'await ' + this.promise;
511        return str;
512    }
513}
514
515export class ArkYieldExpr extends AbstractExpr {
516    private yieldValue: Value;
517
518    constructor(yieldValue: Value) {
519        super();
520        this.yieldValue = yieldValue;
521    }
522
523    public getYieldValue(): Value {
524        return this.yieldValue;
525    }
526
527    public setYieldValue(newYieldValue: Value): void {
528        this.yieldValue = newYieldValue;
529    }
530
531    public getType(): Type {
532        return this.yieldValue.getType();
533    }
534
535    public getUses(): Value[] {
536        const uses: Value[] = [];
537        uses.push(this.yieldValue);
538        uses.push(...this.yieldValue.getUses());
539        return uses;
540    }
541
542    public toString(): string {
543        const str = 'yield ' + this.yieldValue;
544        return str;
545    }
546}
547
548export enum NormalBinaryOperator {
549    // TODO: unfold it
550    NullishCoalescing = '??',
551
552    // arithmetic
553    Exponentiation = '**',
554    Division = '/',
555    Addition = '+',
556    Subtraction = '-',
557    Multiplication = '*',
558    Remainder = '%',
559
560    // shift
561    LeftShift = '<<',
562    RightShift = '>>',
563    UnsignedRightShift = '>>>',
564
565    // Bitwise
566    BitwiseAnd = '&',
567    BitwiseOr = '|',
568    BitwiseXor = '^',
569
570    // Logical
571    LogicalAnd = '&&',
572    LogicalOr = '||',
573}
574
575export enum RelationalBinaryOperator {
576    LessThan = '<',
577    LessThanOrEqual = '<=',
578    GreaterThan = '>',
579    GreaterThanOrEqual = '>=',
580    Equality = '==',
581    InEquality = '!=',
582    StrictEquality = '===',
583    StrictInequality = '!==',
584    isPropertyOf = 'in',
585}
586
587export type BinaryOperator = NormalBinaryOperator | RelationalBinaryOperator;
588
589// 二元运算表达式
590export abstract class AbstractBinopExpr extends AbstractExpr {
591    protected op1: Value;
592    protected op2: Value;
593    protected operator: BinaryOperator;
594
595    protected type!: Type;
596
597    constructor(op1: Value, op2: Value, operator: BinaryOperator) {
598        super();
599        this.op1 = op1;
600        this.op2 = op2;
601        this.operator = operator;
602    }
603
604    /**
605     * Returns the first operand in the binary operation expression.
606     * For example, the first operand in `a + b;` is `a`.
607     * @returns The first operand in the binary operation expression.
608     */
609    public getOp1(): Value {
610        return this.op1;
611    }
612
613    public setOp1(newOp1: Value): void {
614        this.op1 = newOp1;
615    }
616
617    /**
618     * Returns the second operand in the binary operation expression.
619     * For example, the second operand in `a + b;` is `b`.
620     * @returns The second operand in the binary operation expression.
621     */
622    public getOp2(): Value {
623        return this.op2;
624    }
625
626    public setOp2(newOp2: Value): void {
627        this.op2 = newOp2;
628    }
629
630    /**
631     * Get the binary operator from the statement.
632     * The binary operator can be divided into two categories,
633     * one is the normal binary operator and the other is relational binary operator.
634     * @returns The binary operator from the statement.
635     * @example
636     ```typescript
637     if (expr instanceof AbstractBinopExpr) {
638     let op1: Value = expr.getOp1();
639     let op2: Value = expr.getOp2();
640     let operator: string = expr.getOperator();
641     ... ...
642     }
643     ```
644     */
645    public getOperator(): BinaryOperator {
646        return this.operator;
647    }
648
649    public getType(): Type {
650        if (!this.type) {
651            this.setType();
652        }
653        return this.type;
654    }
655
656    public getUses(): Value[] {
657        let uses: Value[] = [];
658        uses.push(this.op1);
659        uses.push(...this.op1.getUses());
660        uses.push(this.op2);
661        uses.push(...this.op2.getUses());
662        return uses;
663    }
664
665    public toString(): string {
666        return this.op1 + ' ' + this.operator + ' ' + this.op2;
667    }
668
669    protected inferOpType(op: Value, arkMethod: ArkMethod): void {
670        if (op instanceof AbstractExpr || op instanceof AbstractRef) {
671            TypeInference.inferValueType(op, arkMethod);
672        }
673    }
674
675    protected setType(): void {
676        let op1Type = this.op1.getType();
677        let op2Type = this.op2.getType();
678        if (op1Type instanceof UnionType) {
679            op1Type = op1Type.getCurrType();
680        }
681        if (op2Type instanceof UnionType) {
682            op2Type = op2Type.getCurrType();
683        }
684        let type = UnknownType.getInstance();
685        switch (this.operator) {
686            case '+':
687                if (op1Type === StringType.getInstance() || op2Type === StringType.getInstance()) {
688                    type = StringType.getInstance();
689                }
690                if (op1Type === NumberType.getInstance() && op2Type === NumberType.getInstance()) {
691                    type = NumberType.getInstance();
692                }
693                if (op1Type === BigIntType.getInstance() && op2Type === BigIntType.getInstance()) {
694                    type = BigIntType.getInstance();
695                }
696                break;
697            case '-':
698            case '*':
699            case '/':
700            case '%':
701                if (op1Type === NumberType.getInstance() && op2Type === NumberType.getInstance()) {
702                    type = NumberType.getInstance();
703                }
704                if (op1Type === BigIntType.getInstance() && op2Type === BigIntType.getInstance()) {
705                    type = BigIntType.getInstance();
706                }
707                break;
708            case '!=':
709            case '!==':
710            case '<':
711            case '>':
712            case '<=':
713            case '>=':
714            case '&&':
715            case '||':
716            case '==':
717            case '===':
718            case 'in':
719                type = BooleanType.getInstance();
720                break;
721            case '&':
722            case '|':
723            case '^':
724            case '<<':
725            case '>>':
726                if (op1Type === NumberType.getInstance() && op2Type === NumberType.getInstance()) {
727                    type = NumberType.getInstance();
728                }
729                if (op1Type === BigIntType.getInstance() && op2Type === BigIntType.getInstance()) {
730                    type = BigIntType.getInstance();
731                }
732                break;
733            case '>>>':
734                if (op1Type === NumberType.getInstance() && op2Type === NumberType.getInstance()) {
735                    type = NumberType.getInstance();
736                }
737                break;
738            case '??':
739                if (op1Type === UnknownType.getInstance() || op1Type === UndefinedType.getInstance() || op1Type === NullType.getInstance()) {
740                    type = op2Type;
741                } else {
742                    type = op1Type;
743                }
744                break;
745            default:
746        }
747        this.type = type;
748    }
749
750    public inferType(arkMethod: ArkMethod): AbstractBinopExpr {
751        this.inferOpType(this.op1, arkMethod);
752        this.inferOpType(this.op2, arkMethod);
753        this.setType();
754        return this;
755    }
756}
757
758export class ArkConditionExpr extends AbstractBinopExpr {
759    constructor(op1: Value, op2: Value, operator: RelationalBinaryOperator) {
760        super(op1, op2, operator);
761    }
762
763    public inferType(arkMethod: ArkMethod): ArkConditionExpr {
764        this.inferOpType(this.op1, arkMethod);
765        const op1Type = this.op1.getType();
766        if (this.operator === RelationalBinaryOperator.InEquality && this.op2 === ValueUtil.getOrCreateNumberConst(0)) {
767            if (op1Type instanceof StringType) {
768                this.op2 = ValueUtil.createStringConst(EMPTY_STRING);
769            } else if (op1Type instanceof BooleanType) {
770                this.op2 = ValueUtil.getBooleanConstant(false);
771            } else if (op1Type instanceof ClassType) {
772                this.op2 = ValueUtil.getUndefinedConst();
773            }
774        } else {
775            this.inferOpType(this.getOp2(), arkMethod);
776        }
777        this.type = BooleanType.getInstance();
778        return this;
779    }
780}
781
782export class ArkNormalBinopExpr extends AbstractBinopExpr {
783    constructor(op1: Value, op2: Value, operator: NormalBinaryOperator) {
784        super(op1, op2, operator);
785    }
786}
787
788export class ArkTypeOfExpr extends AbstractExpr {
789    private op: Value;
790
791    constructor(op: Value) {
792        super();
793        this.op = op;
794    }
795
796    public getOp(): Value {
797        return this.op;
798    }
799
800    public setOp(newOp: Value): void {
801        this.op = newOp;
802    }
803
804    public getUses(): Value[] {
805        let uses: Value[] = [];
806        uses.push(this.op);
807        uses.push(...this.op.getUses());
808        return uses;
809    }
810
811    public getType(): Type {
812        return this.op.getType();
813    }
814
815    public toString(): string {
816        return 'typeof ' + this.op;
817    }
818
819    public inferType(arkMethod: ArkMethod): AbstractExpr {
820        if (this.op instanceof AbstractRef || this.op instanceof AbstractExpr) {
821            this.op.inferType(arkMethod);
822        }
823        return this;
824    }
825}
826
827export class ArkInstanceOfExpr extends AbstractExpr {
828    private op: Value;
829    private checkType: Type;
830
831    constructor(op: Value, checkType: Type) {
832        super();
833        this.op = op;
834        this.checkType = checkType;
835    }
836
837    public getOp(): Value {
838        return this.op;
839    }
840
841    public setOp(newOp: Value): void {
842        this.op = newOp;
843    }
844
845    public getCheckType(): Type {
846        return this.checkType;
847    }
848
849    public getType(): Type {
850        return BooleanType.getInstance();
851    }
852
853    public getUses(): Value[] {
854        let uses: Value[] = [];
855        uses.push(this.op);
856        uses.push(...this.op.getUses());
857        return uses;
858    }
859
860    public toString(): string {
861        return this.op + ' instanceof ' + this.checkType;
862    }
863
864    public inferType(arkMethod: ArkMethod): AbstractExpr {
865        TypeInference.inferValueType(this.op, arkMethod);
866        if (TypeInference.isUnclearType(this.checkType)) {
867            const newType = TypeInference.inferUnclearedType(this.checkType, arkMethod.getDeclaringArkClass());
868            if (newType) {
869                this.checkType = newType;
870            }
871        }
872        return this;
873    }
874}
875
876// 类型转换
877export class ArkCastExpr extends AbstractExpr {
878    private op: Value;
879    private type: Type;
880
881    constructor(op: Value, type: Type) {
882        super();
883        this.op = op;
884        this.type = type;
885    }
886
887    public getOp(): Value {
888        return this.op;
889    }
890
891    public setOp(newOp: Value): void {
892        this.op = newOp;
893    }
894
895    public getUses(): Value[] {
896        let uses: Value[] = [];
897        uses.push(this.op);
898        uses.push(...this.op.getUses());
899        return uses;
900    }
901
902    public getType(): Type {
903        return this.type;
904    }
905
906    public inferType(arkMethod: ArkMethod): AbstractExpr {
907        if (TypeInference.isUnclearType(this.getType())) {
908            const type = TypeInference.inferUnclearedType(this.type, arkMethod.getDeclaringArkClass()) ?? this.op.getType();
909            if (type !== undefined && !TypeInference.isUnclearType(type)) {
910                this.type = type;
911                IRInference.inferRightWithSdkType(type, this.op.getType(), arkMethod.getDeclaringArkClass());
912            }
913        }
914        return this;
915    }
916
917    public toString(): string {
918        return '<' + this.type + '>' + this.op;
919    }
920}
921
922export class ArkPhiExpr extends AbstractExpr {
923    private args: Local[];
924    private argToBlock: Map<Local, BasicBlock>;
925
926    constructor() {
927        super();
928        this.args = [];
929        this.argToBlock = new Map();
930    }
931
932    public getUses(): Value[] {
933        let uses: Value[] = [];
934        uses.push(...this.args);
935        return uses;
936    }
937
938    public getArgs(): Local[] {
939        return this.args;
940    }
941
942    public setArgs(args: Local[]): void {
943        this.args = args;
944    }
945
946    public getArgToBlock(): Map<Local, BasicBlock> {
947        return this.argToBlock;
948    }
949
950    public setArgToBlock(argToBlock: Map<Local, BasicBlock>): void {
951        this.argToBlock = argToBlock;
952    }
953
954    public getType(): Type {
955        return this.args[0].getType();
956    }
957
958    public toString(): string {
959        let strs: string[] = [];
960        strs.push('phi(');
961        if (this.args.length > 0) {
962            for (const arg of this.args) {
963                strs.push(arg.toString());
964                strs.push(', ');
965            }
966            strs.pop();
967        }
968        strs.push(')');
969        return strs.join('');
970    }
971}
972
973export enum UnaryOperator {
974    Neg = '-',
975    BitwiseNot = '~',
976    LogicalNot = '!',
977}
978
979// unary operation expression
980export class ArkUnopExpr extends AbstractExpr {
981    private op: Value;
982    private operator: UnaryOperator;
983
984    constructor(op: Value, operator: UnaryOperator) {
985        super();
986        this.op = op;
987        this.operator = operator;
988    }
989
990    public getUses(): Value[] {
991        let uses: Value[] = [];
992        uses.push(this.op);
993        uses.push(...this.op.getUses());
994        return uses;
995    }
996
997    public getOp(): Value {
998        return this.op;
999    }
1000
1001    public setOp(newOp: Value): void {
1002        this.op = newOp;
1003    }
1004
1005    public getType(): Type {
1006        return this.op.getType();
1007    }
1008
1009    /**
1010     * Get the unary operator from the statement, such as `-`,`~`,`!`.
1011     * @returns the unary operator of a statement.
1012     */
1013    public getOperator(): UnaryOperator {
1014        return this.operator;
1015    }
1016
1017    public toString(): string {
1018        return this.operator + this.op;
1019    }
1020}
1021
1022export type AliasTypeOriginalModel = Type | ImportInfo | Local | ArkClass | ArkMethod | ArkField;
1023
1024/**
1025 * Expression of the right hand of the type alias definition statement.
1026 * @category core/base/expr
1027 * @extends AbstractExpr
1028 * @example
1029 ```typescript
1030 let a: number = 123;
1031 type ABC = typeof a;
1032 ```
1033 * The AliasTypeExpr of the previous statement is with local 'a' as the 'originalObject' and 'transferWithTypeOf' is true.
1034 *
1035 * The Following case: import type with no clause name is not supported now,
1036 * whose 'originalObject' is {@link ImportInfo} with 'null' 'lazyExportInfo'.
1037 ```typescript
1038 let a = typeof import('./abc');
1039 ```
1040 */
1041export class AliasTypeExpr extends AbstractExpr {
1042    private originalObject: AliasTypeOriginalModel;
1043    private readonly transferWithTypeOf: boolean = false;
1044    private realGenericTypes?: Type[];
1045
1046    constructor(originalObject: AliasTypeOriginalModel, transferWithTypeOf?: boolean) {
1047        super();
1048        this.originalObject = originalObject;
1049        if (transferWithTypeOf !== undefined) {
1050            this.transferWithTypeOf = transferWithTypeOf;
1051        }
1052    }
1053
1054    public getOriginalObject(): AliasTypeOriginalModel {
1055        return this.originalObject;
1056    }
1057
1058    public setOriginalObject(object: AliasTypeOriginalModel): void {
1059        this.originalObject = object;
1060    }
1061
1062    public getTransferWithTypeOf(): boolean {
1063        return this.transferWithTypeOf;
1064    }
1065
1066    public setRealGenericTypes(realGenericTypes: Type[]): void {
1067        this.realGenericTypes = realGenericTypes;
1068    }
1069
1070    public getRealGenericTypes(): Type[] | undefined {
1071        return this.realGenericTypes;
1072    }
1073
1074    public getType(): Type {
1075        function getTypeOfImportInfo(importInfo: ImportInfo): Type {
1076            const arkExport = importInfo.getLazyExportInfo()?.getArkExport();
1077            const importClauseName = importInfo.getImportClauseName();
1078            let type;
1079            if (importClauseName.includes('.') && arkExport instanceof ArkClass) {
1080                type = TypeInference.inferUnclearRefName(importClauseName, arkExport);
1081            } else if (arkExport) {
1082                type = TypeInference.parseArkExport2Type(arkExport);
1083            }
1084            return type ?? UnknownType.getInstance();
1085        }
1086
1087        const operator = this.getOriginalObject();
1088        if (!this.getTransferWithTypeOf()) {
1089            if (operator instanceof Type) {
1090                return TypeInference.replaceTypeWithReal(operator, this.getRealGenericTypes());
1091            }
1092            if (operator instanceof ImportInfo) {
1093                return getTypeOfImportInfo(operator);
1094            }
1095            if (operator instanceof ArkClass) {
1096                return TypeInference.replaceTypeWithReal(new ClassType(operator.getSignature(), operator.getGenericsTypes()), this.getRealGenericTypes());
1097            }
1098            return UnknownType.getInstance();
1099        }
1100
1101        if (operator instanceof ImportInfo) {
1102            return getTypeOfImportInfo(operator);
1103        }
1104        if (operator instanceof Local || operator instanceof ArkField) {
1105            return operator.getType();
1106        }
1107        if (operator instanceof ArkClass) {
1108            return TypeInference.replaceTypeWithReal(new ClassType(operator.getSignature(), operator.getGenericsTypes()), this.getRealGenericTypes());
1109        }
1110        if (operator instanceof ArkMethod) {
1111            return TypeInference.replaceTypeWithReal(new FunctionType(operator.getSignature(), operator.getGenericTypes()), this.getRealGenericTypes());
1112        }
1113        return UnknownType.getInstance();
1114    }
1115
1116    public inferType(arkMethod: ArkMethod): AbstractExpr {
1117        return IRInference.inferAliasTypeExpr(this, arkMethod);
1118    }
1119
1120    /**
1121     * Returns all used values which mainly used for def-use chain analysis.
1122     * @returns Always returns empty array because her is the alias type definition which has no relationship with value flow.
1123     */
1124    public getUses(): Value[] {
1125        return [];
1126    }
1127
1128    public toString(): string {
1129        let typeOf = '';
1130        if (this.getTransferWithTypeOf()) {
1131            typeOf = 'typeof ';
1132        }
1133
1134        const typeObject = this.getOriginalObject();
1135        if (typeObject instanceof AliasType && this.getRealGenericTypes()) {
1136            return `${typeOf}${typeObject.getSignature().toString()}<${this.getRealGenericTypes()!.join(',')}>`;
1137        }
1138        if (typeObject instanceof Type) {
1139            return `${typeOf}${typeObject.getTypeString()}`;
1140        }
1141        if (typeObject instanceof ImportInfo) {
1142            let res = `${typeOf}import('${typeObject.getFrom()}')`;
1143            if (typeObject.getImportClauseName() !== '') {
1144                res = `${res}.${typeObject.getImportClauseName()}`;
1145            }
1146            return res;
1147        }
1148        if (typeObject instanceof Local) {
1149            return `${typeOf}${typeObject.toString()}`;
1150        }
1151        if (typeObject instanceof ArkClass || typeObject instanceof ArkMethod) {
1152            let res = `${typeOf}${typeObject.getSignature().toString()}`;
1153            if (this.getRealGenericTypes() && typeObject instanceof ArkClass) {
1154                res += `<${this.getRealGenericTypes()!.join(',')}>`;
1155            } else if (this.getRealGenericTypes() && typeObject instanceof ArkMethod) {
1156                const genericTypes = this.getRealGenericTypes()!.join(',');
1157                res = res.replace('(', `<${genericTypes}>(`).replace(/\([^)]*\)/g, `(${genericTypes})`);
1158            }
1159            return res;
1160        }
1161        return `${typeOf}${typeObject.getName()}`;
1162    }
1163
1164    public static isAliasTypeOriginalModel(object: any): object is AliasTypeOriginalModel {
1165        return (
1166            object instanceof Type ||
1167            object instanceof ImportInfo ||
1168            object instanceof Local ||
1169            object instanceof ArkClass ||
1170            object instanceof ArkMethod ||
1171            object instanceof ArkField
1172        );
1173    }
1174}
1175