• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 { Value } from './Value';
17import { ArkMethod } from '../model/ArkMethod';
18import { IntersectionType, Type, UnionType, UnknownType } from './Type';
19import { IRInference } from '../common/IRInference';
20import { ArkBaseModel } from '../model/ArkBaseModel';
21import { ModelUtils } from '../common/ModelUtils';
22import { ArkClass } from '../model/ArkClass';
23
24/**
25 * abstract type expr represents the type operations of types or values.
26 * AbstractTypeExpr is different from AbstractExpr.
27 * @category core/base/typeExpr
28 * @extends Type
29 * @example
30 *  ```typescript
31 *  let a = number;
32 *  type A = typeof a;
33 *  let b: keyof typeof a;
34 *  ```
35 */
36export abstract class AbstractTypeExpr extends Type {
37    abstract getUses(): Value[];
38
39    abstract getType(): Type;
40
41    public inferType(arkMethod: ArkMethod): void {
42        return;
43    }
44}
45
46/**
47 * typeQuery type expr represents the get type of value with typeof.
48 * @category core/base/typeExpr
49 * @extends AbstractTypeExpr
50 * @example
51 ```typescript
52 // opValue is a and type A is number
53 let a = number;
54 type A = typeof a;
55 ```
56 */
57
58export class TypeQueryExpr extends AbstractTypeExpr {
59    private opValue: Value | ArkBaseModel;
60    private genericTypes?: Type[];
61
62    constructor(opValue: Value | ArkBaseModel, generateTypes?: Type[]) {
63        super();
64        this.opValue = opValue;
65        this.genericTypes = generateTypes;
66    }
67
68    public setOpValue(opValue: Value | ArkBaseModel): void {
69        this.opValue = opValue;
70    }
71
72    public getOpValue(): Value | ArkBaseModel {
73        return this.opValue;
74    }
75
76    public setGenerateTypes(types: Type[]): void {
77        this.genericTypes = types;
78    }
79
80    public getGenerateTypes(): Type[] | undefined {
81        return this.genericTypes;
82    }
83
84    public addGenericType(gType: Type): void {
85        if (!this.genericTypes) {
86            this.genericTypes = [];
87        }
88        this.genericTypes.push(gType);
89    }
90
91    public getUses(): Value[] {
92        const opValue = this.getOpValue();
93        if (opValue instanceof ArkBaseModel) {
94            return [];
95        }
96        let uses: Value[] = [];
97        uses.push(opValue);
98        uses.push(...opValue.getUses());
99        return uses;
100    }
101
102    public getType(): Type {
103        const opValue = this.getOpValue();
104        if (opValue instanceof ArkBaseModel) {
105            return ModelUtils.parseArkBaseModel2Type(opValue) ?? UnknownType.getInstance();
106        }
107        return opValue.getType();
108    }
109
110    public getTypeString(): string {
111        const opValue = this.getOpValue();
112        const gTypes = this.getGenerateTypes();
113        const genericStr = gTypes && gTypes.length > 0 ? `<${gTypes.join(',')}>` : '';
114        if (opValue instanceof ArkClass || opValue instanceof ArkMethod) {
115            return `typeof ${opValue.getSignature().toString()}${genericStr}`;
116        }
117        return `typeof ${opValue.toString()}${genericStr}`;
118    }
119
120    public inferType(arkMethod: ArkMethod): void {
121        IRInference.inferTypeQueryExpr(this, arkMethod);
122    }
123}
124
125/**
126 * keyof type expr represents the type operator with keyof.
127 * It should be an internal expr.
128 * the final type should be transferred to union type, unless it cannot find out all types within the union type.
129 * @category core/base/typeExpr
130 * @extends AbstractTypeExpr
131 * @example
132 ```typescript
133 // opType is {a: 1, b: 2} and type of A is KeyofTypeExpr, which can be transferred to union type {'a', 'b'}
134 type A = keyof {a: 1, b: 2};
135
136 // opType is number and type of B is KeyofTypeExpr, which can be transferred to union type "toString" | "toFixed" | "toExponential" | ...
137 type B = keyof number;
138 ```
139 */
140export class KeyofTypeExpr extends AbstractTypeExpr {
141    private opType: Type;
142
143    constructor(opType: Type) {
144        super();
145        this.opType = opType;
146    }
147
148    public getOpType(): Type {
149        return this.opType;
150    }
151
152    public setOpType(opType: Type): void {
153        this.opType = opType;
154    }
155
156    public getUses(): Value[] {
157        let uses: Value[] = [];
158        if (this.getOpType() instanceof TypeQueryExpr) {
159            uses.push(...(this.getOpType() as TypeQueryExpr).getUses());
160        }
161        return uses;
162    }
163
164    public getType(): Type {
165        return this;
166    }
167
168    public getTypeString(): string {
169        if (this.getOpType() instanceof UnionType || this.getOpType() instanceof IntersectionType) {
170            return `keyof (${this.getOpType().toString()})`;
171        }
172        return `keyof ${this.getOpType().toString()}`;
173    }
174
175    public inferType(arkMethod: ArkMethod): void {
176        IRInference.inferKeyofTypeExpr(this, arkMethod);
177    }
178}
179