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