• 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 */
15import { ArkMethod } from '../model/ArkMethod';
16import {
17    AliasType,
18    AnnotationNamespaceType,
19    AnyType,
20    ArrayType,
21    ClassType,
22    FunctionType,
23    GenericType,
24    LexicalEnvType,
25    NullType,
26    Type,
27    UnclearReferenceType,
28    UndefinedType,
29    UnionType,
30    UnknownType,
31} from '../base/Type';
32import { Local } from '../base/Local';
33import { TypeInference } from './TypeInference';
34import {
35    AbstractExpr,
36    AbstractInvokeExpr,
37    AliasTypeExpr,
38    ArkInstanceInvokeExpr,
39    ArkPtrInvokeExpr,
40    ArkStaticInvokeExpr
41} from '../base/Expr';
42import Logger, { LOG_MODULE_TYPE } from '../../utils/logger';
43import { Scene } from '../../Scene';
44import { ArkClass } from '../model/ArkClass';
45import { findArkExport, ModelUtils } from './ModelUtils';
46import { ArkField, FieldCategory } from '../model/ArkField';
47import { CALL_BACK } from './EtsConst';
48import {
49    AliasClassSignature,
50    BaseSignature,
51    ClassSignature,
52    FieldSignature, FileSignature,
53    MethodSignature,
54    MethodSubSignature
55} from '../model/ArkSignature';
56import { CONSTRUCTOR_NAME, FUNCTION, IMPORT, SUPER_NAME, THIS_NAME } from './TSConst';
57import { Builtin } from './Builtin';
58import { ArkBody } from '../model/ArkBody';
59import { ArkAssignStmt, ArkInvokeStmt } from '../base/Stmt';
60import {
61    AbstractFieldRef,
62    AbstractRef,
63    ArkArrayRef,
64    ArkInstanceFieldRef,
65    ArkParameterRef,
66    ArkStaticFieldRef
67} from '../base/Ref';
68import { Value } from '../base/Value';
69import { Constant } from '../base/Constant';
70import {
71    ANONYMOUS_CLASS_PREFIX,
72    CALL_SIGNATURE_NAME,
73    DEFAULT_ARK_CLASS_NAME, LEXICAL_ENV_NAME_PREFIX,
74    NAME_DELIMITER,
75    NAME_PREFIX,
76    UNKNOWN_CLASS_NAME
77} from './Const';
78import { ValueUtil } from './ValueUtil';
79import { ArkFile } from '../model/ArkFile';
80import { AbstractTypeExpr, KeyofTypeExpr, TypeQueryExpr } from '../base/TypeExpr';
81import { ArkBaseModel } from '../model/ArkBaseModel';
82
83const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'IRInference');
84
85export class IRInference {
86    private static inferExportInfos(file: ArkFile): void {
87        file.getExportInfos().forEach(exportInfo => {
88            if (exportInfo.getArkExport() === undefined) {
89                let arkExport = findArkExport(exportInfo);
90                exportInfo.setArkExport(arkExport);
91                if (arkExport) {
92                    exportInfo.setExportClauseType(arkExport.getExportType());
93                }
94            }
95        });
96        file.getNamespaces().forEach(namespace => {
97            namespace.getExportInfos().forEach(exportInfo => {
98                if (exportInfo.getArkExport() === undefined) {
99                    let arkExport = findArkExport(exportInfo);
100                    exportInfo.setArkExport(arkExport);
101                    arkExport !== null ? exportInfo.setExportClauseType(arkExport.getExportType()) : true;
102                }
103            });
104        });
105    }
106
107    private static inferImportInfos(file: ArkFile): void {
108        file.getImportInfos().forEach(importInfo => {
109            importInfo.getLazyExportInfo();
110        });
111    }
112
113    public static inferFile(file: ArkFile): void {
114        this.inferImportInfos(file);
115        ModelUtils.getAllClassesInFile(file).forEach(arkClass => {
116            TypeInference.inferGenericType(arkClass.getGenericsTypes(), arkClass);
117            const defaultArkMethod = arkClass.getDefaultArkMethod();
118            if (defaultArkMethod) {
119                TypeInference.inferTypeInMethod(defaultArkMethod);
120            }
121            arkClass.getFields().forEach(arkField => TypeInference.inferTypeInArkField(arkField));
122            const methods = arkClass.getMethods().sort((a, b) => {
123                const name = a.getName().split(NAME_DELIMITER).reverse().join();
124                const anotherName = b.getName().split(NAME_DELIMITER).reverse().join();
125                if (name.startsWith(anotherName)) {
126                    return 1;
127                } else if (anotherName.startsWith(name)) {
128                    return -1;
129                }
130                return 0;
131            });
132            arkClass.getAllHeritageClasses();
133            methods.forEach(arkMethod => TypeInference.inferTypeInMethod(arkMethod));
134        });
135        this.inferExportInfos(file);
136    }
137
138    public static inferStaticInvokeExpr(expr: ArkStaticInvokeExpr, arkMethod: ArkMethod): AbstractInvokeExpr {
139        const fileSignature = expr.getMethodSignature().getDeclaringClassSignature().getDeclaringFileSignature();
140        if (fileSignature !== FileSignature.DEFAULT && fileSignature !== Builtin.BUILT_IN_CLASSES_FILE_SIGNATURE) {
141            return expr;
142        }
143        const arkClass = arkMethod.getDeclaringArkClass();
144        const methodName = expr.getMethodSignature().getMethodSubSignature().getMethodName();
145        expr.getArgs().forEach(arg => TypeInference.inferValueType(arg, arkMethod));
146        if (methodName === IMPORT) {
147            const arg = expr.getArg(0);
148            let type;
149            if (arg instanceof Constant) {
150                type = TypeInference.inferDynamicImportType(arg.getValue(), arkClass);
151            }
152            if (type) {
153                expr.getMethodSignature().getMethodSubSignature().setReturnType(type);
154            }
155            return expr;
156        } else if (methodName === SUPER_NAME) {
157            const superClass = arkClass.getSuperClass();
158            if (superClass !== null) {
159                const newMethodSignature = new MethodSignature(superClass.getSignature(), expr.getMethodSignature().getMethodSubSignature());
160                expr.setMethodSignature(newMethodSignature);
161            }
162            return expr;
163        }
164        const className = expr.getMethodSignature().getDeclaringClassSignature().getClassName();
165        if (className && className !== UNKNOWN_CLASS_NAME) {
166            const baseType = TypeInference.inferBaseType(className, arkClass);
167            if (baseType) {
168                let result = this.inferInvokeExpr(expr, baseType, methodName, arkClass.getDeclaringArkFile().getScene());
169                if (result) {
170                    this.inferArgs(result, arkMethod);
171                    return result;
172                }
173            }
174            return expr;
175        }
176        return this.inferStaticInvokeExprByMethodName(methodName, arkMethod, expr);
177    }
178
179    private static inferStaticInvokeExprByMethodName(methodName: string, arkMethod: ArkMethod, expr: AbstractInvokeExpr): AbstractInvokeExpr {
180        const arkClass = arkMethod.getDeclaringArkClass();
181        const arkExport =
182            ModelUtils.getStaticMethodWithName(methodName, arkClass) ??
183            arkMethod.getFunctionLocal(methodName) ??
184            ModelUtils.findDeclaredLocal(new Local(methodName), arkMethod) ??
185            ModelUtils.getArkExportInImportInfoWithName(methodName, arkClass.getDeclaringArkFile()) ??
186            arkClass.getDeclaringArkFile().getScene().getSdkGlobal(methodName);
187        let method;
188        let signature;
189        if (arkExport instanceof ArkMethod) {
190            method = arkExport;
191        } else if (arkExport instanceof ArkClass) {
192            method = arkExport.getMethodWithName(CONSTRUCTOR_NAME);
193        } else if (arkExport instanceof Local) {
194            const type = TypeInference.replaceAliasType(arkExport.getType());
195            if (type instanceof ClassType) {
196                const cls = arkClass.getDeclaringArkFile().getScene().getClass(type.getClassSignature());
197                method = cls?.getMethodWithName(CONSTRUCTOR_NAME) ?? cls?.getMethodWithName(CALL_SIGNATURE_NAME);
198            } else if (type instanceof FunctionType) {
199                signature = type.getMethodSignature();
200            }
201        } else if (arkExport instanceof AliasType && arkExport.getOriginalType() instanceof FunctionType) {
202            signature = (arkExport.getOriginalType() as FunctionType).getMethodSignature();
203        }
204        if (method) {
205            signature = method.matchMethodSignature(expr.getArgs());
206            TypeInference.inferSignatureReturnType(signature, method);
207        }
208        if (signature) {
209            if (arkExport instanceof Local) {
210                expr = new ArkPtrInvokeExpr(signature, arkExport, expr.getArgs(), expr.getRealGenericTypes());
211            } else {
212                expr.setMethodSignature(signature);
213            }
214            this.inferArgs(expr, arkMethod);
215        }
216        return expr;
217    }
218
219    public static inferInstanceInvokeExpr(expr: ArkInstanceInvokeExpr, arkMethod: ArkMethod): AbstractInvokeExpr {
220        const arkClass = arkMethod.getDeclaringArkClass();
221        TypeInference.inferRealGenericTypes(expr.getRealGenericTypes(), arkClass);
222        this.inferBase(expr, arkMethod);
223
224        const baseType: Type = TypeInference.replaceAliasType(expr.getBase().getType());
225        let methodName = expr.getMethodSignature().getMethodSubSignature().getMethodName();
226        if (methodName.startsWith(NAME_PREFIX)) {
227            const declaringStmt = arkMethod.getBody()?.getLocals().get(methodName)?.getDeclaringStmt();
228            if (declaringStmt instanceof ArkAssignStmt && declaringStmt.getRightOp() instanceof ArkInstanceFieldRef) {
229                const rightOp = declaringStmt.getRightOp() as ArkInstanceFieldRef;
230                methodName = rightOp.getBase().getName() + '.' + rightOp.getFieldName();
231            }
232        }
233        const scene = arkClass.getDeclaringArkFile().getScene();
234        if (methodName === 'forEach' && baseType instanceof ArrayType) {
235            this.processForEach(expr.getArg(0), baseType, scene);
236            return expr;
237        }
238        expr.getArgs().forEach(arg => TypeInference.inferValueType(arg, arkMethod));
239        let result = this.inferInvokeExpr(expr, baseType, methodName, scene) ?? this.processExtendFunc(expr, arkMethod, methodName);
240        if (result) {
241            this.inferArgs(result, arkMethod);
242            return result;
243        }
244        logger.warn('invoke ArkInstanceInvokeExpr MethodSignature type fail: ', expr.toString());
245        return expr;
246    }
247
248    /**
249     * process arkUI function with Annotation @Extend @Styles @AnimatableExtend
250     * @param expr
251     * @param arkMethod
252     * @param methodName
253     */
254    private static processExtendFunc(expr: AbstractInvokeExpr, arkMethod: ArkMethod, methodName: string): AbstractInvokeExpr | null {
255        const type = TypeInference.inferBaseType(methodName, arkMethod.getDeclaringArkClass());
256        if (type instanceof FunctionType) {
257            const methodSignature = type.getMethodSignature();
258            // because of last stmt is ArkReturnVoidStmt, the ArkInvokeStmt at -2 before ArkReturnVoidStmt.
259            const stmts = arkMethod.getDeclaringArkFile().getScene().getMethod(methodSignature)?.getCfg()?.getStmts();
260            if (stmts) {
261                const endStmt = stmts[stmts.length - 2];
262                if (endStmt instanceof ArkInvokeStmt) {
263                    methodSignature.getMethodSubSignature().setReturnType(endStmt.getInvokeExpr().getType());
264                }
265            }
266            expr.setMethodSignature(methodSignature);
267            return expr;
268        }
269        return null;
270    }
271
272    public static inferFieldRef(ref: ArkInstanceFieldRef, arkMethod: ArkMethod): AbstractRef {
273        this.inferBase(ref, arkMethod);
274        const baseType: Type = TypeInference.replaceAliasType(ref.getBase().getType());
275        if (baseType instanceof ArrayType && ref.getFieldName() !== 'length') {
276            return new ArkArrayRef(ref.getBase(), ValueUtil.createConst(ref.getFieldName()));
277        }
278
279        let newFieldSignature = this.generateNewFieldSignature(ref, arkMethod.getDeclaringArkClass(), baseType);
280        if (newFieldSignature) {
281            if (newFieldSignature.isStatic()) {
282                return new ArkStaticFieldRef(newFieldSignature);
283            }
284            ref.setFieldSignature(newFieldSignature);
285        }
286        return ref;
287    }
288
289    private static inferBase(instance: ArkInstanceFieldRef | ArkInstanceInvokeExpr, arkMethod: ArkMethod): void {
290        const base = instance.getBase();
291        if (base.getName() === THIS_NAME) {
292            const name = instance instanceof ArkInstanceFieldRef ? instance.getFieldName() :
293                instance.getMethodSignature().getMethodSubSignature().getMethodName();
294            if (name.includes('.')) {
295                return;
296            }
297            const declaringArkClass = arkMethod.getDeclaringArkClass();
298            if (declaringArkClass.isAnonymousClass()) {
299                let newBase = this.inferThisLocal(arkMethod);
300                if (newBase) {
301                    instance.setBase(newBase);
302                }
303            } else if (base.getType() instanceof UnknownType) {
304                base.setType(new ClassType(declaringArkClass.getSignature(), declaringArkClass.getRealTypes()));
305            }
306        } else {
307            this.inferLocal(instance.getBase(), arkMethod);
308        }
309    }
310
311    public static inferThisLocal(arkMethod: ArkMethod): Local | null {
312        const arkClass = arkMethod.getDeclaringArkClass();
313        if (!arkClass.isAnonymousClass()) {
314            return null;
315        }
316
317        const value = arkMethod.getBody()?.getUsedGlobals()?.get(THIS_NAME);
318        if (value instanceof Local) {
319            return value;
320        } else {
321            const thisType = TypeInference.inferBaseType(arkClass.getSignature().getDeclaringClassName(), arkClass);
322            if (thisType instanceof ClassType) {
323                const newBase = new Local(THIS_NAME, thisType);
324                let usedGlobals = arkMethod.getBody()?.getUsedGlobals();
325                if (!usedGlobals) {
326                    usedGlobals = new Map();
327                    arkMethod.getBody()?.setUsedGlobals(usedGlobals);
328                }
329                usedGlobals.set(THIS_NAME, newBase);
330                return newBase;
331            }
332        }
333        return null;
334    }
335
336    private static inferArgs(expr: AbstractInvokeExpr, arkMethod: ArkMethod): void {
337        const scene = arkMethod.getDeclaringArkFile().getScene();
338        const parameters = expr.getMethodSignature().getMethodSubSignature().getParameters();
339        let realTypes: Type[] = [];
340        const len = expr.getArgs().length;
341        for (let index = 0; index < len; index++) {
342            const arg = expr.getArg(index);
343            if (index >= parameters.length) {
344                break;
345            }
346            const argType = arg.getType();
347            const paramType = parameters[index].getType();
348            this.inferArg(expr, argType, paramType, scene, realTypes);
349        }
350        if (realTypes.length > 0 && !expr.getRealGenericTypes()) {
351            expr.setRealGenericTypes(realTypes);
352        }
353    }
354
355    private static inferArg(expr: AbstractInvokeExpr, argType: Type, paramType: Type, scene: Scene, realTypes: Type[]): void {
356        if (paramType instanceof UnionType) {
357            paramType.getTypes().forEach(t => this.inferArg(expr, argType, t, scene, realTypes));
358        } else if (paramType instanceof AliasType) {
359            this.inferArg(expr, argType, paramType.getOriginalType(), scene, realTypes);
360        } else if (paramType instanceof ArrayType && argType instanceof ArrayType) {
361            this.inferArg(expr, argType.getBaseType(), paramType.getBaseType(), scene, realTypes);
362        } else if (expr instanceof ArkInstanceInvokeExpr && expr.getBase().getType() instanceof ArrayType) {
363            if (paramType instanceof ArrayType && paramType.getBaseType() instanceof GenericType) {
364                this.inferArg(expr, argType, (expr.getBase().getType() as ArrayType).getBaseType(), scene, realTypes);
365            }
366        }
367
368        if (paramType instanceof ClassType && scene.getProjectSdkMap().has(paramType.getClassSignature().getDeclaringFileSignature().getProjectName())) {
369            this.inferArgTypeWithSdk(paramType, scene, argType);
370        } else if (paramType instanceof GenericType || paramType instanceof AnyType) {
371            realTypes.push(argType);
372        } else if (paramType instanceof FunctionType && argType instanceof FunctionType) {
373            if (paramType.getMethodSignature().getParamLength() > 0 && paramType.getMethodSignature().getType() instanceof GenericType) {
374                const paramMethod = scene.getMethod(expr.getMethodSignature());
375                const argMethod = scene.getMethod(argType.getMethodSignature());
376                if (paramMethod && paramMethod.getGenericTypes() && argMethod) {
377                    TypeInference.inferTypeInMethod(argMethod);
378                }
379            }
380            const realTypes = expr.getRealGenericTypes();
381            TypeInference.inferFunctionType(argType, paramType.getMethodSignature().getMethodSubSignature(), realTypes);
382        }
383    }
384
385    public static inferRightWithSdkType(leftType: Type, rightType: Type, ackClass: ArkClass): void {
386        if (leftType instanceof AliasType) {
387            this.inferRightWithSdkType(TypeInference.replaceAliasType(leftType), rightType, ackClass);
388        } else if (leftType instanceof UnionType) {
389            leftType.getTypes().forEach(t => this.inferRightWithSdkType(t, rightType, ackClass));
390        } else if (leftType instanceof ClassType) {
391            IRInference.inferArgTypeWithSdk(leftType, ackClass.getDeclaringArkFile().getScene(), rightType);
392        } else if (rightType instanceof ArrayType && leftType instanceof ArrayType) {
393            const baseType = TypeInference.replaceAliasType(leftType.getBaseType());
394            if (baseType instanceof ClassType) {
395                IRInference.inferArgTypeWithSdk(baseType, ackClass.getDeclaringArkFile().getScene(), rightType.getBaseType());
396            }
397        }
398    }
399
400    public static inferArgTypeWithSdk(sdkType: ClassType, scene: Scene, argType: Type): void {
401        if (!scene.getProjectSdkMap().has(sdkType.getClassSignature().getDeclaringFileSignature().getProjectName())) {
402            return;
403        }
404        if (argType instanceof UnionType) {
405            argType.getTypes().forEach(t => this.inferArgTypeWithSdk(sdkType, scene, t));
406        } else if (argType instanceof ClassType && argType.getClassSignature().getClassName().startsWith(ANONYMOUS_CLASS_PREFIX)) {
407            this.inferAnonymousClass(scene.getClass(argType.getClassSignature()), sdkType.getClassSignature());
408        } else if (argType instanceof FunctionType) {
409            const param = scene.getClass(sdkType.getClassSignature())?.getMethodWithName(CALL_SIGNATURE_NAME)?.getSignature().getMethodSubSignature();
410            const realTypes = sdkType.getRealGenericTypes();
411            TypeInference.inferFunctionType(argType, param, realTypes);
412        }
413    }
414
415    private static inferInvokeExpr(expr: AbstractInvokeExpr, baseType: Type, methodName: string, scene: Scene): AbstractInvokeExpr | null {
416        if (baseType instanceof AliasType) {
417            return this.inferInvokeExpr(expr, baseType.getOriginalType(), methodName, scene);
418        } else if (baseType instanceof UnionType) {
419            for (let type of baseType.flatType()) {
420                if (type instanceof UndefinedType || type instanceof NullType) {
421                    continue;
422                }
423                let result = this.inferInvokeExpr(expr, type, methodName, scene);
424                if (result) {
425                    return result;
426                }
427            }
428        }
429        if (baseType instanceof ClassType) {
430            return this.inferInvokeExprWithDeclaredClass(expr, baseType, methodName, scene);
431        } else if (baseType instanceof AnnotationNamespaceType) {
432            const namespace = scene.getNamespace(baseType.getNamespaceSignature());
433            if (namespace) {
434                const foundMethod = ModelUtils.findPropertyInNamespace(methodName, namespace);
435                if (foundMethod instanceof ArkMethod) {
436                    let signature = foundMethod.matchMethodSignature(expr.getArgs());
437                    TypeInference.inferSignatureReturnType(signature, foundMethod);
438                    expr.setMethodSignature(signature);
439                    return expr instanceof ArkInstanceInvokeExpr ? new ArkStaticInvokeExpr(signature, expr.getArgs(), expr.getRealGenericTypes()) : expr;
440                }
441            }
442        } else if (baseType instanceof FunctionType) {
443            return IRInference.inferInvokeExprWithFunction(methodName, expr, baseType, scene);
444        } else if (baseType instanceof ArrayType) {
445            return IRInference.inferInvokeExprWithArray(methodName, expr, baseType, scene);
446        }
447        return null;
448    }
449
450    private static inferInvokeExprWithArray(methodName: string, expr: AbstractInvokeExpr, baseType: ArrayType, scene: Scene): AbstractInvokeExpr | null {
451        const arrayInterface = scene.getSdkGlobal(Builtin.ARRAY);
452        if (arrayInterface instanceof ArkClass) {
453            return this.inferInvokeExpr(expr, new ClassType(arrayInterface.getSignature(), [baseType.getBaseType()]), methodName, scene);
454        } else if (methodName === Builtin.ITERATOR_FUNCTION) {
455            expr.getMethodSignature().getMethodSubSignature().setReturnType(Builtin.ITERATOR_CLASS_TYPE);
456            expr.setRealGenericTypes([baseType.getBaseType()]);
457            return expr;
458        }
459        return null;
460    }
461
462    private static inferInvokeExprWithFunction(methodName: string, expr: AbstractInvokeExpr, baseType: FunctionType, scene: Scene): AbstractInvokeExpr | null {
463        if (methodName === CALL_SIGNATURE_NAME) {
464            expr.setMethodSignature(baseType.getMethodSignature());
465            return expr;
466        }
467        const funcInterface = scene.getSdkGlobal(FUNCTION);
468        if (funcInterface instanceof ArkClass) {
469            const method = ModelUtils.findPropertyInClass(methodName, funcInterface);
470            if (method instanceof ArkMethod) {
471                expr.setRealGenericTypes([baseType]);
472                expr.setMethodSignature(method.getSignature());
473                return expr;
474            }
475        }
476        return null;
477    }
478
479    private static inferInvokeExprWithDeclaredClass(
480        expr: AbstractInvokeExpr,
481        baseType: ClassType,
482        methodName: string,
483        scene: Scene
484    ): AbstractInvokeExpr | null {
485        if (Builtin.isBuiltinClass(baseType.getClassSignature().getClassName())) {
486            expr.setMethodSignature(new MethodSignature(baseType.getClassSignature(), expr.getMethodSignature().getMethodSubSignature()));
487        }
488        let declaredClass = scene.getClass(baseType.getClassSignature());
489        if (!declaredClass) {
490            const globalClass = scene.getSdkGlobal(baseType.getClassSignature().getClassName());
491            if (globalClass instanceof ArkClass) {
492                declaredClass = globalClass;
493            }
494        }
495        const method = declaredClass ? ModelUtils.findPropertyInClass(methodName, declaredClass) : null;
496        if (method instanceof ArkMethod) {
497            const methodSignature = method.matchMethodSignature(expr.getArgs());
498            TypeInference.inferSignatureReturnType(methodSignature, method);
499            expr.setMethodSignature(this.replaceMethodSignature(expr.getMethodSignature(), methodSignature));
500            expr.setRealGenericTypes(IRInference.getRealTypes(expr, declaredClass, baseType, method));
501            if (method.isStatic() && expr instanceof ArkInstanceInvokeExpr) {
502                return new ArkStaticInvokeExpr(methodSignature, expr.getArgs(), expr.getRealGenericTypes());
503            }
504            return expr;
505        } else if (method instanceof ArkField) {
506            const type = method.getType();
507            let methodSignature;
508            if (type instanceof FunctionType) {
509                methodSignature = type.getMethodSignature();
510            } else if (type instanceof ClassType && type.getClassSignature().getClassName().endsWith(CALL_BACK)) {
511                const callback = scene.getClass(type.getClassSignature())?.getMethodWithName(CALL_SIGNATURE_NAME);
512                if (callback) {
513                    methodSignature = callback.getSignature();
514                }
515            }
516            if (methodSignature) {
517                const ptr =
518                    expr instanceof ArkInstanceInvokeExpr
519                        ? new ArkInstanceFieldRef(expr.getBase(), method.getSignature())
520                        : new ArkStaticFieldRef(method.getSignature());
521                expr = new ArkPtrInvokeExpr(methodSignature, ptr, expr.getArgs(), expr.getRealGenericTypes());
522            }
523            return expr;
524        } else if (methodName === CONSTRUCTOR_NAME) {
525            //sdk隐式构造
526            const subSignature = new MethodSubSignature(methodName, [], new ClassType(baseType.getClassSignature()));
527            expr.setMethodSignature(new MethodSignature(baseType.getClassSignature(), subSignature));
528            return expr;
529        } else if (methodName === Builtin.ITERATOR_NEXT &&
530            baseType.getClassSignature().getDeclaringFileSignature().getProjectName() === Builtin.DUMMY_PROJECT_NAME) {
531            expr.getMethodSignature().getMethodSubSignature().setReturnType(Builtin.ITERATOR_RESULT_CLASS_TYPE);
532            expr.setRealGenericTypes(baseType.getRealGenericTypes());
533            return expr;
534        }
535        return null;
536    }
537
538    private static getRealTypes(expr: AbstractInvokeExpr, declaredClass: ArkClass | null, baseType: ClassType, method: ArkMethod): Type[] | undefined {
539        let realTypes;
540        const tmp: Type[] = [];
541        if (method.getGenericTypes()) {
542            expr.getMethodSignature().getMethodSubSignature().getParameters()
543                .filter(p => !p.getName().startsWith(LEXICAL_ENV_NAME_PREFIX))
544                .forEach((p, i) => {
545                    if (TypeInference.checkType(p.getType(), t => t instanceof GenericType)) {
546                        tmp.push(expr.getArg(i).getType());
547                    }
548                });
549        }
550        if (tmp.length > 0) {
551            realTypes = tmp;
552        } else if (declaredClass?.hasComponentDecorator()) {
553            realTypes = [new ClassType(declaredClass?.getSignature())];
554        } else {
555            realTypes = baseType.getRealGenericTypes() ?? declaredClass?.getRealTypes();
556        }
557        return realTypes;
558    }
559
560    public static replaceMethodSignature(init: MethodSignature, declared: MethodSignature): MethodSignature {
561        const className = init.getDeclaringClassSignature().getClassName();
562        let classSignature;
563        if (declared.getDeclaringClassSignature().getClassName().endsWith('Interface')) {
564            classSignature = new AliasClassSignature(className, declared.getDeclaringClassSignature());
565        }
566        let newSubSignature;
567        if (classSignature || newSubSignature) {
568            return new MethodSignature(classSignature ?? declared.getDeclaringClassSignature(), newSubSignature ?? declared.getMethodSubSignature());
569        }
570        return declared;
571    }
572
573    private static processForEach(arg: Value, baseType: ArrayType, scene: Scene): void {
574        const argType = arg.getType();
575        if (argType instanceof FunctionType) {
576            const argMethodSignature = argType.getMethodSignature();
577            const argMethod = scene.getMethod(argMethodSignature);
578            if (argMethod != null && argMethod.getBody()) {
579                const body = argMethod.getBody() as ArkBody;
580                const firstStmt = body.getCfg().getStartingStmt();
581                if (firstStmt instanceof ArkAssignStmt && firstStmt.getRightOp() instanceof ArkParameterRef) {
582                    const parameterRef = firstStmt.getRightOp() as ArkParameterRef;
583                    parameterRef.setType(baseType.getBaseType());
584                    const argMethodParams = argMethod.getSignature().getMethodSubSignature().getParameters();
585                    const actualParam = argMethodParams[argMethodParams.length - 1];
586                    actualParam.setType(baseType.getBaseType());
587                }
588                TypeInference.inferTypeInMethod(argMethod);
589            }
590        } else {
591            logger.warn(`arg of forEach must be callable`);
592        }
593    }
594
595    public static inferLocal(base: Local, arkMethod: ArkMethod): void {
596        const arkClass = arkMethod.getDeclaringArkClass();
597        let baseType: Type | null | undefined = base.getType();
598        if (baseType instanceof UnclearReferenceType) {
599            baseType = TypeInference.inferUnclearRefName(baseType.getName(), arkClass);
600        } else if (TypeInference.isUnclearType(baseType)) {
601            const declaringStmt = base.getDeclaringStmt();
602            if (!declaringStmt || !declaringStmt.getOriginalText() || declaringStmt.getOriginalText()?.startsWith(base.getName())) {
603                baseType = ModelUtils.findDeclaredLocal(base, arkMethod)?.getType() ?? TypeInference.inferBaseType(base.getName(), arkClass);
604            }
605        }
606        if (baseType instanceof UnionType || (baseType && !TypeInference.isUnclearType(baseType))) {
607            base.setType(baseType);
608        }
609    }
610
611    private static generateNewFieldSignature(ref: AbstractFieldRef, arkClass: ArkClass, baseType: Type): FieldSignature | null {
612        if (baseType instanceof UnionType) {
613            for (let type of baseType.flatType()) {
614                if (type instanceof UndefinedType || type instanceof NullType) {
615                    continue;
616                }
617                let newFieldSignature = this.generateNewFieldSignature(ref, arkClass, type);
618                if (!TypeInference.isUnclearType(newFieldSignature?.getType())) {
619                    return newFieldSignature;
620                }
621            }
622            return null;
623        } else if (baseType instanceof AliasType) {
624            return this.generateNewFieldSignature(ref, arkClass, baseType.getOriginalType());
625        }
626        const fieldName = ref.getFieldName().replace(/[\"|\']/g, '');
627        const propertyAndType = TypeInference.inferFieldType(baseType, fieldName, arkClass);
628        let propertyType = IRInference.repairType(propertyAndType?.[1], fieldName, arkClass);
629        let staticFlag: boolean;
630        let signature: BaseSignature;
631        if (baseType instanceof ClassType) {
632            const property = propertyAndType?.[0];
633            if (property instanceof ArkField && property.getCategory() !== FieldCategory.ENUM_MEMBER &&
634                !(property.getType() instanceof GenericType)) {
635                return property.getSignature();
636            }
637            staticFlag =
638                baseType.getClassSignature().getClassName() === DEFAULT_ARK_CLASS_NAME ||
639                ((property instanceof ArkField || property instanceof ArkMethod) && property.isStatic());
640            signature = property instanceof ArkMethod ? property.getSignature().getDeclaringClassSignature() : baseType.getClassSignature();
641        } else if (baseType instanceof AnnotationNamespaceType) {
642            staticFlag = true;
643            signature = baseType.getNamespaceSignature();
644        } else {
645            return null;
646        }
647        return new FieldSignature(fieldName, signature, propertyType ?? ref.getType(), staticFlag);
648    }
649
650    private static repairType(propertyType: Type | undefined, fieldName: string, arkClass: ArkClass): Type | undefined {
651        if (!propertyType || propertyType instanceof UnknownType) {
652            const newType = TypeInference.inferBaseType(fieldName, arkClass);
653            if (newType) {
654                propertyType = newType;
655            }
656        } else if (TypeInference.isUnclearType(propertyType)) {
657            const newType = TypeInference.inferUnclearedType(propertyType, arkClass);
658            if (newType) {
659                propertyType = newType;
660            }
661        }
662        return propertyType;
663    }
664
665    public static inferAnonymousClass(anon: ArkClass | null, declaredSignature: ClassSignature, set: Set<string> = new Set()): void {
666        if (!anon) {
667            return;
668        }
669        const key = anon.getSignature().toString();
670        if (set.has(key)) {
671            return;
672        } else {
673            set.add(key);
674        }
675        const scene = anon.getDeclaringArkFile().getScene();
676        const declaredClass = scene.getClass(declaredSignature);
677        if (!declaredClass) {
678            return;
679        }
680        for (const anonField of anon.getFields()) {
681            const property = ModelUtils.findPropertyInClass(anonField.getName(), declaredClass);
682            if (property instanceof ArkField) {
683                this.assignAnonField(property, anonField, scene, set);
684            } else if (property instanceof ArkMethod) {
685                const type = anonField.getType();
686                if (type instanceof FunctionType) {
687                    this.assignAnonMethod(scene.getMethod(type.getMethodSignature()), property);
688                }
689                anonField.setSignature(
690                    new FieldSignature(anonField.getName(), property.getDeclaringArkClass().getSignature(), new FunctionType(property.getSignature()))
691                );
692            }
693        }
694        for (const anonMethod of anon.getMethods()) {
695            this.assignAnonMethod(anonMethod, declaredClass.getMethodWithName(anonMethod.getName()));
696        }
697    }
698
699    private static assignAnonMethod(anonMethod: ArkMethod | null, declaredMethod: ArkMethod | null): void {
700        if (declaredMethod && anonMethod) {
701            anonMethod.setDeclareSignatures(declaredMethod.matchMethodSignature(anonMethod.getSubSignature().getParameters()));
702        }
703    }
704
705    private static assignAnonField(property: ArkField, anonField: ArkField, scene: Scene, set: Set<string>): void {
706        function deepInfer(anonType: Type, declaredSignature: ClassSignature): void {
707            if (anonType instanceof ClassType && anonType.getClassSignature().getClassName().startsWith(ANONYMOUS_CLASS_PREFIX)) {
708                IRInference.inferAnonymousClass(scene.getClass(anonType.getClassSignature()), declaredSignature, set);
709            }
710        }
711
712        const type = property.getSignature().getType();
713        const fieldInitializer = anonField.getInitializer();
714        const lastStmt = fieldInitializer[fieldInitializer.length - 1];
715        if (lastStmt instanceof ArkAssignStmt) {
716            const rightType = lastStmt.getRightOp().getType();
717            if (type instanceof ClassType) {
718                deepInfer(rightType, type.getClassSignature());
719            } else if (type instanceof ArrayType && type.getBaseType() instanceof ClassType && rightType instanceof ArrayType) {
720                const baseType = rightType.getBaseType();
721                const classSignature = (type.getBaseType() as ClassType).getClassSignature();
722                if (baseType instanceof UnionType) {
723                    baseType.getTypes().forEach(t => deepInfer(t, classSignature));
724                } else {
725                    deepInfer(rightType.getBaseType(), classSignature);
726                }
727            } else if (type instanceof FunctionType && rightType instanceof FunctionType) {
728                TypeInference.inferFunctionType(rightType, type.getMethodSignature().getMethodSubSignature(), type.getRealGenericTypes());
729            }
730            const leftOp = lastStmt.getLeftOp();
731            if (leftOp instanceof AbstractFieldRef) {
732                leftOp.setFieldSignature(property.getSignature());
733            }
734        }
735        anonField.setSignature(property.getSignature());
736    }
737
738    public static inferAliasTypeExpr(expr: AliasTypeExpr, arkMethod: ArkMethod): AbstractExpr {
739        const originalObject = expr.getOriginalObject();
740        let model;
741        if (originalObject instanceof Local) {
742            model = ModelUtils.findArkModelByRefName(originalObject.getName(), arkMethod.getDeclaringArkClass());
743        } else if (originalObject instanceof AbstractTypeExpr) {
744            originalObject.inferType(arkMethod);
745            model = originalObject;
746        } else if (originalObject instanceof Type) {
747            const type = TypeInference.inferUnclearedType(originalObject, arkMethod.getDeclaringArkClass());
748
749            // If original Object is ClassType, AliasType or UnclearReferenceType with real generic types,
750            // the type after infer should be revert back to the object itself.
751            if (type instanceof ClassType) {
752                const scene = arkMethod.getDeclaringArkFile().getScene();
753                model = ModelUtils.findArkModelBySignature(type.getClassSignature(), scene);
754            } else if (type instanceof AliasType) {
755                const scene = arkMethod.getDeclaringArkFile().getScene();
756                model = ModelUtils.findArkModelBySignature(type.getSignature(), scene);
757            } else if (type) {
758                model = type;
759            }
760            if (expr.getRealGenericTypes() !== undefined && originalObject instanceof UnclearReferenceType) {
761                expr.setRealGenericTypes(originalObject.getGenericTypes());
762            }
763        }
764
765        if (AliasTypeExpr.isAliasTypeOriginalModel(model)) {
766            expr.setOriginalObject(model);
767        }
768        return expr;
769    }
770
771    public static inferTypeQueryExpr(expr: TypeQueryExpr, arkMethod: ArkMethod): void {
772        let gTypes = expr.getGenerateTypes();
773        if (gTypes) {
774            for (let i = 0; i < gTypes.length; i++) {
775                const newType = TypeInference.inferUnclearedType(gTypes[i], arkMethod.getDeclaringArkClass());
776                if (newType) {
777                    gTypes[i] = newType;
778                }
779            }
780        }
781
782        const opValue = expr.getOpValue();
783        let opValueType;
784        if (opValue instanceof ArkBaseModel) {
785            opValueType = ModelUtils.parseArkBaseModel2Type(opValue) ?? UnknownType.getInstance();
786        } else {
787            opValueType = opValue.getType();
788        }
789
790        if (!TypeInference.isUnclearType(opValueType)) {
791            return;
792        }
793        if (opValue instanceof Local) {
794            const newOpValueType = TypeInference.inferBaseType(opValue.getName(), arkMethod.getDeclaringArkClass());
795            const scene = arkMethod.getDeclaringArkFile().getScene();
796            if (newOpValueType instanceof ClassType) {
797                const newOpValue = ModelUtils.findArkModelBySignature(newOpValueType.getClassSignature(), scene);
798                if (newOpValue instanceof ArkBaseModel) {
799                    expr.setOpValue(newOpValue);
800                }
801            } else if (newOpValueType instanceof FunctionType) {
802                const newOpValue = ModelUtils.findArkModelBySignature(newOpValueType.getMethodSignature(), scene);
803                if (newOpValue instanceof ArkBaseModel) {
804                    expr.setOpValue(newOpValue);
805                }
806            } else {
807                this.inferLocal(opValue, arkMethod);
808            }
809        } else if (opValue instanceof AbstractRef || opValue instanceof AbstractExpr) {
810            expr.setOpValue(opValue.inferType(arkMethod));
811        }
812    }
813
814    public static inferKeyofTypeExpr(expr: KeyofTypeExpr, arkMethod: ArkMethod): void {
815        const opType = expr.getOpType();
816        if (TypeInference.isUnclearType(opType)) {
817            if (opType instanceof TypeQueryExpr) {
818                this.inferTypeQueryExpr(opType, arkMethod);
819            } else {
820                const type = TypeInference.inferUnclearedType(opType, arkMethod.getDeclaringArkClass());
821                if (type) {
822                    expr.setOpType(type);
823                }
824            }
825        }
826    }
827
828    public static inferParameterRef(ref: ArkParameterRef, arkMethod: ArkMethod): AbstractRef {
829        const paramType = ref.getType();
830        if (paramType instanceof UnknownType || paramType instanceof UnclearReferenceType) {
831            const signature = arkMethod.getDeclareSignatures()?.[0] ?? arkMethod.getSignature();
832            const type1 = signature.getMethodSubSignature().getParameters()[ref.getIndex()]?.getType();
833            if (!TypeInference.isUnclearType(type1)) {
834                ref.setType(type1);
835                return ref;
836            }
837        } else if (paramType instanceof LexicalEnvType) {
838            paramType
839                .getClosures()
840                .filter(c => TypeInference.isUnclearType(c.getType()))
841                .forEach(e => this.inferLocal(e, arkMethod));
842            return ref;
843        }
844        let type = TypeInference.inferUnclearedType(paramType, arkMethod.getDeclaringArkClass());
845        if (type) {
846            ref.setType(type);
847        }
848        return ref;
849    }
850}
851