• 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 { Local } from '../base/Local';
17import { ArkClass } from '../model/ArkClass';
18import { ArkFile } from '../model/ArkFile';
19import { ArkMethod } from '../model/ArkMethod';
20import { ArkNamespace } from '../model/ArkNamespace';
21import {
22    AliasTypeSignature,
23    ClassSignature,
24    FieldSignature,
25    FileSignature,
26    fileSignatureCompare,
27    LocalSignature,
28    MethodSignature,
29    NamespaceSignature,
30    Signature,
31} from '../model/ArkSignature';
32import { ArkExport, ExportInfo, ExportType, FromInfo } from '../model/ArkExport';
33import { ArkField } from '../model/ArkField';
34import Logger, { LOG_MODULE_TYPE } from '../../utils/logger';
35import { FileUtils, ModulePath } from '../../utils/FileUtils';
36import path from 'path';
37import { Sdk } from '../../Config';
38import { ALL, DEFAULT, THIS_NAME } from './TSConst';
39import { buildDefaultExportInfo } from '../model/builder/ArkExportBuilder';
40import { AnnotationNamespaceType, ClassType, FunctionType, Type, UnclearReferenceType, UnknownType } from '../base/Type';
41import { Scene } from '../../Scene';
42import { DEFAULT_ARK_CLASS_NAME, DEFAULT_ARK_METHOD_NAME, NAME_DELIMITER, TEMP_LOCAL_PREFIX } from './Const';
43import { EMPTY_STRING } from './ValueUtil';
44import { ArkBaseModel } from '../model/ArkBaseModel';
45import { ArkAssignStmt } from '../base/Stmt';
46import { ClosureFieldRef } from '../base/Ref';
47import { SdkUtils } from './SdkUtils';
48
49export class ModelUtils {
50    public static implicitArkUIBuilderMethods: Set<ArkMethod> = new Set();
51
52    /*
53     * Set static field to be null, then all related objects could be freed by GC.
54     * Static field implicitArkUIBuilderMethods is only used during method body building, the dispose method should be called after build all body.
55     */
56    public static dispose(): void {
57        this.implicitArkUIBuilderMethods.clear();
58    }
59
60    public static getMethodSignatureFromArkClass(arkClass: ArkClass, methodName: string): MethodSignature | null {
61        for (const arkMethod of arkClass.getMethods()) {
62            if (arkMethod.getName() === methodName) {
63                return arkMethod.getSignature();
64            }
65        }
66        return null;
67    }
68
69    public static getClassWithNameInNamespaceRecursively(className: string, ns: ArkNamespace): ArkClass | null {
70        if (className === '') {
71            return null;
72        }
73        let res: ArkClass | null = null;
74        res = ns.getClassWithName(className);
75        if (res == null) {
76            let declaringNs = ns.getDeclaringArkNamespace();
77            if (declaringNs != null) {
78                res = this.getClassWithNameInNamespaceRecursively(className, declaringNs);
79            } else {
80                res = this.getClassInFileWithName(className, ns.getDeclaringArkFile());
81            }
82        }
83        return res;
84    }
85
86    public static getClassWithNameFromClass(className: string, startFrom: ArkClass): ArkClass | null {
87        if (!className.includes('.')) {
88            let res: ArkClass | null = null;
89            const arkNamespace = startFrom.getDeclaringArkNamespace();
90            if (arkNamespace) {
91                res = this.getClassWithNameInNamespaceRecursively(className, arkNamespace);
92            } else {
93                res = this.getClassInFileWithName(className, startFrom.getDeclaringArkFile());
94            }
95            return res;
96        } else {
97            const names = className.split('.');
98            let nameSpace = this.getNamespaceWithNameFromClass(names[0], startFrom);
99            for (let i = 1; i < names.length - 1; i++) {
100                if (nameSpace) {
101                    nameSpace = nameSpace.getNamespaceWithName(names[i]);
102                }
103            }
104            if (nameSpace) {
105                return nameSpace.getClassWithName(names[names.length - 1]);
106            }
107        }
108        return null;
109    }
110
111    /**
112     *  search class within the file that contain the given method
113     */
114    public static getClassWithName(className: string, thisClass: ArkClass): ArkClass | null {
115        if (thisClass.getName() === className) {
116            return thisClass;
117        }
118        let classSearched = thisClass.getDeclaringArkNamespace()?.getClassWithName(className);
119        if (!classSearched) {
120            classSearched = thisClass.getDeclaringArkFile().getClassWithName(className);
121        }
122        return classSearched;
123    }
124
125    /** search class within the given file */
126    public static getClassInFileWithName(className: string, arkFile: ArkFile): ArkClass | null {
127        let classSearched = arkFile.getClassWithName(className);
128        if (classSearched != null) {
129            return classSearched;
130        }
131        return null;
132    }
133
134    public static getClassInImportInfoWithName(className: string, arkFile: ArkFile): ArkClass | null {
135        let arkExport = this.getArkExportInImportInfoWithName(className, arkFile);
136        if (arkExport instanceof ArkClass) {
137            return arkExport;
138        }
139        return null;
140    }
141
142    /** search type within the given file import infos */
143    public static getArkExportInImportInfoWithName(name: string, arkFile: ArkFile): ArkExport | null {
144        return arkFile.getImportInfoBy(name)?.getLazyExportInfo()?.getArkExport() ?? null;
145    }
146
147    /** search method within the file that contain the given method */
148    public static getMethodWithName(methodName: string, startFrom: ArkMethod): ArkMethod | null {
149        if (!methodName.includes('.')) {
150            if (startFrom.getName() === methodName) {
151                return startFrom;
152            }
153
154            const thisClass = startFrom.getDeclaringArkClass();
155            let methodSearched: ArkMethod | null = thisClass.getMethodWithName(methodName);
156            if (!methodSearched) {
157                methodSearched = thisClass.getStaticMethodWithName(methodName);
158            }
159            return methodSearched;
160        } else {
161            const names = methodName.split('.');
162            let nameSpace = this.getNamespaceWithName(names[0], startFrom.getDeclaringArkClass());
163            for (let i = 1; i < names.length - 1; i++) {
164                if (nameSpace) {
165                    nameSpace = nameSpace.getNamespaceWithName(names[i]);
166                }
167            }
168            if (nameSpace) {
169                return nameSpace.getDefaultClass().getMethodWithName(names[names.length - 1]);
170            }
171        }
172        return null;
173    }
174
175    public static getNamespaceWithNameFromClass(namespaceName: string, startFrom: ArkClass): ArkNamespace | null {
176        const thisNamespace = startFrom.getDeclaringArkNamespace();
177        let namespaceSearched: ArkNamespace | null = null;
178        if (thisNamespace) {
179            namespaceSearched = thisNamespace.getNamespaceWithName(namespaceName);
180            if (namespaceSearched) {
181                return namespaceSearched;
182            }
183        }
184        const thisFile = startFrom.getDeclaringArkFile();
185        namespaceSearched = this.getNamespaceInFileWithName(namespaceName, thisFile);
186        return namespaceSearched;
187    }
188
189    public static getNamespaceWithName(namespaceName: string, thisClass: ArkClass): ArkNamespace | null {
190        let thisNamespace: ArkNamespace | null | undefined = thisClass.getDeclaringArkNamespace();
191        let namespaceSearched: ArkNamespace | null = null;
192        while (!namespaceSearched && thisNamespace) {
193            namespaceSearched = thisNamespace.getNamespaceWithName(namespaceName);
194            thisNamespace = thisNamespace.getDeclaringArkNamespace();
195        }
196        if (!namespaceSearched) {
197            namespaceSearched = thisClass.getDeclaringArkFile().getNamespaceWithName(namespaceName);
198        }
199        return namespaceSearched;
200    }
201
202    public static getNamespaceInFileWithName(namespaceName: string, arkFile: ArkFile): ArkNamespace | null {
203        let namespaceSearched = arkFile.getNamespaceWithName(namespaceName);
204        if (namespaceSearched) {
205            return namespaceSearched;
206        }
207
208        return null;
209    }
210
211    public static getNamespaceInImportInfoWithName(namespaceName: string, arkFile: ArkFile): ArkNamespace | null {
212        let arkExport = this.getArkExportInImportInfoWithName(namespaceName, arkFile);
213        if (arkExport instanceof ArkNamespace) {
214            return arkExport;
215        }
216        return null;
217    }
218
219    public static getStaticMethodWithName(methodName: string, thisClass: ArkClass): ArkMethod | null {
220        const thisNamespace = thisClass.getDeclaringArkNamespace();
221        if (thisNamespace) {
222            const defaultClass = thisNamespace.getClassWithName(DEFAULT_ARK_CLASS_NAME);
223            if (defaultClass) {
224                const method = defaultClass.getMethodWithName(methodName);
225                if (method) {
226                    return method;
227                }
228            }
229        }
230        return this.getStaticMethodInFileWithName(methodName, thisClass.getDeclaringArkFile());
231    }
232
233    public static getStaticMethodInFileWithName(methodName: string, arkFile: ArkFile): ArkMethod | null {
234        const defaultClass = arkFile.getClasses().find(cls => cls.getName() === DEFAULT_ARK_CLASS_NAME) || null;
235        if (defaultClass) {
236            let method = defaultClass.getMethodWithName(methodName);
237            if (method) {
238                return method;
239            }
240        }
241        return null;
242    }
243
244    public static getStaticMethodInImportInfoWithName(methodName: string, arkFile: ArkFile): ArkMethod | null {
245        let arkExport = this.getArkExportInImportInfoWithName(methodName, arkFile);
246        if (arkExport instanceof ArkMethod) {
247            return arkExport;
248        }
249        return null;
250    }
251
252    public static getLocalInImportInfoWithName(localName: string, arkFile: ArkFile): Local | null {
253        let arkExport = this.getArkExportInImportInfoWithName(localName, arkFile);
254        if (arkExport instanceof Local) {
255            return arkExport;
256        }
257        return null;
258    }
259
260    /* get nested namespaces in a file */
261    public static getAllNamespacesInFile(arkFile: ArkFile): ArkNamespace[] {
262        const arkNamespaces: ArkNamespace[] = arkFile.getNamespaces();
263        for (const arkNamespace of arkFile.getNamespaces()) {
264            this.getAllNamespacesInNamespace(arkNamespace, arkNamespaces);
265        }
266        return arkNamespaces;
267    }
268
269    /* get nested namespaces in a namespace */
270    public static getAllNamespacesInNamespace(arkNamespace: ArkNamespace, allNamespaces: ArkNamespace[]): void {
271        allNamespaces.push(...arkNamespace.getNamespaces());
272        for (const nestedNamespace of arkNamespace.getNamespaces()) {
273            this.getAllNamespacesInNamespace(nestedNamespace, allNamespaces);
274        }
275    }
276
277    public static getAllClassesInFile(arkFile: ArkFile): ArkClass[] {
278        const allClasses = arkFile.getClasses();
279        this.getAllNamespacesInFile(arkFile).forEach(namespace => {
280            allClasses.push(...namespace.getClasses());
281        });
282        return allClasses;
283    }
284
285    public static getAllMethodsInFile(arkFile: ArkFile): ArkMethod[] {
286        const allMethods: ArkMethod[] = [];
287        this.getAllClassesInFile(arkFile).forEach(cls => {
288            allMethods.push(...cls.getMethods());
289        });
290        return allMethods;
291    }
292
293    public static isArkUIBuilderMethod(arkMethod: ArkMethod): boolean {
294        let isArkUIBuilderMethod = arkMethod.hasBuilderDecorator() || this.implicitArkUIBuilderMethods.has(arkMethod);
295
296        if (!isArkUIBuilderMethod && arkMethod.getName() === 'build' && arkMethod.getDeclaringArkClass().hasComponentDecorator() && !arkMethod.isStatic()) {
297            const fileName = arkMethod.getDeclaringArkClass().getDeclaringArkFile().getName();
298            if (fileName.endsWith('.ets')) {
299                isArkUIBuilderMethod = true;
300            }
301        }
302        return isArkUIBuilderMethod;
303    }
304
305    public static getArkClassInBuild(scene: Scene, classType: ClassType): ArkClass | null {
306        const classSignature = classType.getClassSignature();
307        const file = scene.getFile(classSignature.getDeclaringFileSignature());
308        const namespaceSignature = classSignature.getDeclaringNamespaceSignature();
309        if (namespaceSignature) {
310            return file?.getNamespace(namespaceSignature)?.getClass(classSignature) || null;
311        }
312        return file?.getClassWithName(classSignature.getClassName()) || null;
313    }
314
315    public static getDefaultClass(arkClass: ArkClass): ArkClass | null {
316        return arkClass.getDeclaringArkNamespace()?.getDefaultClass() ?? arkClass.getDeclaringArkFile().getDefaultClass();
317    }
318
319    public static getClass(method: ArkMethod, signature: ClassSignature): ArkClass | null {
320        let cls: ArkClass | undefined | null = method.getDeclaringArkFile().getScene().getClass(signature);
321        if (cls) {
322            return cls;
323        }
324        let importInfo = method.getDeclaringArkFile().getImportInfoBy(signature.getClassName());
325        let exportInfo = importInfo ? findExportInfo(importInfo) : null;
326        let arkExport = exportInfo?.getArkExport();
327        if (arkExport instanceof ArkClass) {
328            return arkExport;
329        }
330
331        cls = method.getDeclaringArkClass().getDeclaringArkNamespace()?.getClassWithName(signature.getClassName());
332        if (cls) {
333            return cls;
334        }
335
336        for (const ns of method.getDeclaringArkFile().getAllNamespacesUnderThisFile()) {
337            cls = ns.getClassWithName(signature.getClassName());
338            if (cls) {
339                return cls;
340            }
341        }
342
343        return method.getDeclaringArkFile().getClassWithName(signature.getClassName());
344    }
345
346    public static findPropertyInNamespace(name: string, namespace: ArkNamespace): ArkExport | undefined {
347        return (
348            namespace.getDefaultClass()?.getMethodWithName(name) ??
349            findArkExport(namespace.getExportInfoBy(name)) ??
350            namespace.getClassWithName(name) ??
351            namespace.getNamespaceWithName(name) ??
352            namespace.getDefaultClass()?.getDefaultArkMethod()?.getBody()?.getAliasTypeByName(name) ??
353            namespace.getDefaultClass()?.getDefaultArkMethod()?.getBody()?.getLocals()?.get(name)
354        );
355    }
356
357    public static findPropertyInClass(name: string, arkClass: ArkClass): ArkExport | ArkField | null {
358        let property: ArkExport | ArkField | null =
359            arkClass.getMethodWithName(name) ??
360            arkClass.getStaticMethodWithName(name) ??
361            arkClass.getFieldWithName(name) ??
362            arkClass.getStaticFieldWithName(name);
363        if (property) {
364            return property;
365        }
366        if (arkClass.isDefaultArkClass()) {
367            return findArkExport(arkClass.getDeclaringArkFile().getExportInfoBy(name));
368        }
369        for (const heritage of arkClass.getAllHeritageClasses()) {
370            property = this.findPropertyInClass(name, heritage);
371            if (property) {
372                return property;
373            }
374        }
375        return null;
376    }
377
378    public static findDeclaredLocal(local: Local, arkMethod: ArkMethod, times: number = 0): Local | null {
379        if (arkMethod.getDeclaringArkFile().getScene().getOptions().isScanAbc) {
380            return null;
381        }
382        const name: string = local.getName();
383        if (name === THIS_NAME || name.startsWith(TEMP_LOCAL_PREFIX)) {
384            return null;
385        }
386        const parameter = arkMethod.getParameters().find(p => p.getName() === name);
387        if (parameter) {
388            return new Local(parameter.getName(), parameter.getType());
389        }
390        if (times > 0) {
391            const declaredLocal = arkMethod.getBody()?.getLocals().get(name);
392            if (
393                declaredLocal &&
394                declaredLocal.getDeclaringStmt() instanceof ArkAssignStmt &&
395                !((declaredLocal.getDeclaringStmt() as ArkAssignStmt).getRightOp() instanceof ClosureFieldRef)
396            ) {
397                return declaredLocal;
398            }
399        }
400        let parentName = arkMethod.getName();
401        if (parentName === DEFAULT_ARK_METHOD_NAME) {
402            return null;
403        }
404        let invokeMethod: ArkMethod | null | undefined = arkMethod.getOuterMethod();
405        if (!invokeMethod) {
406            const className = arkMethod.getDeclaringArkClass().getName();
407            const outerStart = className.indexOf(NAME_DELIMITER);
408            const outerEnd = className.lastIndexOf('.');
409            if (outerStart > -1 && outerEnd > -1) {
410                invokeMethod = arkMethod
411                    .getDeclaringArkFile()
412                    .getClassWithName(className.substring(outerStart + 1, outerEnd))
413                    ?.getMethodWithName(className.substring(outerEnd + 1));
414            } else {
415                const cls = arkMethod.getDeclaringArkClass();
416                invokeMethod = cls.getDefaultArkMethod() ?? cls.getDeclaringArkFile().getDefaultClass()?.getDefaultArkMethod();
417            }
418        }
419        if (invokeMethod) {
420            return this.findDeclaredLocal(local, invokeMethod, ++times);
421        }
422        return null;
423    }
424
425    public static findArkModel(baseName: string, arkClass: ArkClass): ArkExport | ArkField | null {
426        let arkModel: ArkExport | ArkField | null =
427            arkClass.getMethodWithName(baseName) ??
428            arkClass.getStaticMethodWithName(baseName) ??
429            arkClass.getFieldWithName(baseName) ??
430            arkClass.getStaticFieldWithName(baseName);
431        if (arkModel) {
432            return arkModel;
433        }
434        arkModel =
435            ModelUtils.getDefaultClass(arkClass)?.getDefaultArkMethod()?.getBody()?.getLocals()?.get(baseName) ??
436            ModelUtils.getClassWithName(baseName, arkClass) ??
437            ModelUtils.getNamespaceWithName(baseName, arkClass) ??
438            ModelUtils.getDefaultClass(arkClass)?.getMethodWithName(baseName) ??
439            ModelUtils.getDefaultClass(arkClass)?.getDefaultArkMethod()?.getBody()?.getAliasTypeByName(baseName) ??
440            ModelUtils.getArkExportInImportInfoWithName(baseName, arkClass.getDeclaringArkFile());
441        if (!arkModel && !arkClass.getDeclaringArkFile().getImportInfoBy(baseName)) {
442            arkModel = arkClass.getDeclaringArkFile().getScene().getSdkGlobal(baseName);
443        }
444        return arkModel;
445    }
446
447    public static findGlobalRef(refName: string, method: ArkMethod): ArkExport | null {
448        return (
449            this.findDeclaredLocal(new Local(refName), method, 1) ??
450            this.getArkExportInImportInfoWithName(refName, method.getDeclaringArkFile()) ??
451            method.getDeclaringArkFile().getScene().getSdkGlobal(refName)
452        );
453    }
454
455    public static findArkModelByRefName(refName: string, arkClass: ArkClass): ArkExport | ArkField | null {
456        const singleNames = refName.split('.');
457        let model = null;
458        for (let i = 0; i < singleNames.length; i++) {
459            if (model instanceof Local || model instanceof ArkField) {
460                const type = model.getType();
461                if (type instanceof ClassType) {
462                    model = arkClass.getDeclaringArkFile().getScene().getClass(type.getClassSignature());
463                } else if (type instanceof AnnotationNamespaceType) {
464                    model = arkClass.getDeclaringArkFile().getScene().getNamespace(type.getNamespaceSignature());
465                }
466            }
467            const name = singleNames[i].replace(/<(\w+)>/, EMPTY_STRING);
468            if (i === 0) {
469                model = this.findArkModel(name, arkClass);
470            } else if (model instanceof ArkClass) {
471                model = this.findPropertyInClass(name, model);
472            } else if (model instanceof ArkNamespace) {
473                model = this.findPropertyInNamespace(name, model);
474            }
475            if (!model) {
476                return null;
477            }
478        }
479        return model;
480    }
481
482    public static findArkModelBySignature(signature: Signature, scene: Scene): ArkExport | ArkField | null {
483        if (signature instanceof ClassSignature) {
484            return scene.getClass(signature);
485        } else if (signature instanceof NamespaceSignature) {
486            return scene.getNamespace(signature);
487        } else if (signature instanceof MethodSignature) {
488            return scene.getMethod(signature);
489        } else if (signature instanceof FieldSignature) {
490            const declare = this.findArkModelBySignature(signature.getDeclaringSignature(), scene);
491            if (declare instanceof ArkClass) {
492                return this.findPropertyInClass(signature.getFieldName(), declare);
493            } else if (declare instanceof ArkNamespace) {
494                return this.findPropertyInNamespace(signature.getFieldName(), declare) || null;
495            }
496            return null;
497        } else if (signature instanceof LocalSignature) {
498            const declare = scene.getMethod(signature.getDeclaringMethodSignature());
499            return declare?.getBody()?.getLocals().get(signature.getName()) ?? declare?.getBody()?.getAliasTypeByName(signature.getName()) ?? null;
500        } else if (signature instanceof AliasTypeSignature) {
501            const declare = scene.getMethod(signature.getDeclaringMethodSignature());
502            return declare?.getBody()?.getAliasTypeByName(signature.getName()) ?? null;
503        }
504        return null;
505    }
506
507    public static parseArkBaseModel2Type(arkBaseModel: ArkBaseModel): Type | null {
508        if (arkBaseModel instanceof ArkClass) {
509            return new ClassType(arkBaseModel.getSignature(), arkBaseModel.getGenericsTypes());
510        } else if (arkBaseModel instanceof ArkNamespace) {
511            return AnnotationNamespaceType.getInstance(arkBaseModel.getSignature());
512        } else if (arkBaseModel instanceof ArkMethod) {
513            return new FunctionType(arkBaseModel.getSignature());
514        } else if (arkBaseModel instanceof ArkField) {
515            if (arkBaseModel.getType() instanceof UnknownType || arkBaseModel.getType() instanceof UnclearReferenceType) {
516                return null;
517            }
518            return arkBaseModel.getType();
519        }
520        return null;
521    }
522}
523
524const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'ModelUtils');
525let moduleMap: Map<string, ModulePath> | undefined;
526
527/**
528 * find arkFile by from info
529 * export xx from '../xx'
530 * import xx from '@ohos/xx'
531 * import xx from '@ohos.xx'
532 * @param im importInfo or exportInfo
533 */
534export function getArkFile(im: FromInfo): ArkFile | null | undefined {
535    const from = im.getFrom();
536    if (!from) {
537        return null;
538    }
539    if (/^([^@]*\/)([^\/]*)$/.test(from)) {
540        //relative path
541        const parentPath = /^\.{1,2}\//.test(from) ? path.dirname(im.getDeclaringArkFile().getFilePath()) : im.getDeclaringArkFile().getProjectDir();
542        const originPath = path.resolve(parentPath, from);
543        return getArkFileFromScene(im, originPath);
544    } else if (/^@[a-z|\-]+?\//.test(from)) {
545        //module path
546        const arkFile = getArkFileFromOtherModule(im);
547        if (arkFile) {
548            return arkFile;
549        }
550    }
551
552    //sdk path
553    const file = SdkUtils.getImportSdkFile(from);
554    if (file) {
555        return file;
556    }
557    const scene = im.getDeclaringArkFile().getScene();
558    for (const sdk of scene.getProjectSdkMap().values()) {
559        const arkFile = getArkFileFormMap(sdk.name, processSdkPath(sdk, from), scene);
560        if (arkFile) {
561            return arkFile;
562        }
563    }
564    return null;
565}
566
567/**
568 * find from info's export
569 * @param fromInfo importInfo or exportInfo
570 */
571export function findExportInfo(fromInfo: FromInfo): ExportInfo | null {
572    let file = getArkFile(fromInfo);
573    if (!file) {
574        logger.warn(`${fromInfo.getOriginName()} ${fromInfo.getFrom()} file not found: ${fromInfo.getDeclaringArkFile()?.getFileSignature()?.toString()}`);
575        return null;
576    }
577    if (fileSignatureCompare(file.getFileSignature(), fromInfo.getDeclaringArkFile().getFileSignature())) {
578        for (let exportInfo of file.getExportInfos()) {
579            if (exportInfo.getOriginName() === fromInfo.getOriginName()) {
580                exportInfo.setArkExport(file.getDefaultClass());
581                return exportInfo;
582            }
583        }
584        return null;
585    }
586    let exportInfo = findExportInfoInfile(fromInfo, file) || null;
587    if (exportInfo === null) {
588        logger.warn('export info not found, ' + fromInfo.getFrom() + ' in file: ' + fromInfo.getDeclaringArkFile().getFileSignature().toString());
589        return null;
590    }
591    const arkExport = findArkExport(exportInfo);
592    exportInfo.setArkExport(arkExport);
593    if (arkExport) {
594        exportInfo.setExportClauseType(arkExport.getExportType());
595    }
596    return exportInfo;
597}
598
599export function findArkExport(exportInfo: ExportInfo | undefined): ArkExport | null {
600    if (!exportInfo) {
601        return null;
602    }
603    let arkExport = exportInfo.getArkExport();
604    if (arkExport || arkExport === null) {
605        return arkExport;
606    }
607    if (!exportInfo.getFrom()) {
608        const name = exportInfo.getOriginName();
609        const defaultClass = exportInfo.getDeclaringArkNamespace()?.getDefaultClass() ?? exportInfo.getDeclaringArkFile().getDefaultClass();
610        if (exportInfo.getExportClauseType() === ExportType.LOCAL) {
611            arkExport = defaultClass.getDefaultArkMethod()?.getBody()?.getExportLocalByName(name);
612        } else if (exportInfo.getExportClauseType() === ExportType.TYPE) {
613            arkExport = defaultClass.getDefaultArkMethod()?.getBody()?.getAliasTypeByName(name);
614        } else {
615            arkExport = findArkExportInFile(name, exportInfo.getDeclaringArkFile());
616        }
617    } else if (exportInfo.getExportClauseType() === ExportType.UNKNOWN) {
618        const result = findExportInfo(exportInfo);
619        if (result) {
620            arkExport = result.getArkExport() || null;
621        }
622    }
623    if (arkExport) {
624        exportInfo.setArkExport(arkExport);
625    } else {
626        const file = exportInfo.getDeclaringArkFile().getFileSignature().toString();
627        logger.warn(`${exportInfo.getExportClauseName()} get arkExport fail from ${exportInfo.getFrom()} at ${file}`);
628    }
629    return arkExport || null;
630}
631
632export function findArkExportInFile(name: string, declaringArkFile: ArkFile): ArkExport | null {
633    let arkExport: ArkExport | undefined | null =
634        declaringArkFile.getNamespaceWithName(name) ??
635        declaringArkFile.getDefaultClass().getDefaultArkMethod()?.getBody()?.getAliasTypeByName(name) ??
636        declaringArkFile.getClassWithName(name) ??
637        declaringArkFile.getDefaultClass().getMethodWithName(name) ??
638        declaringArkFile.getDefaultClass().getDefaultArkMethod()?.getBody()?.getExportLocalByName(name);
639
640    if (!arkExport) {
641        const importInfo = declaringArkFile.getImportInfoBy(name);
642        if (importInfo) {
643            const result = findExportInfo(importInfo);
644            if (result) {
645                arkExport = result.getArkExport();
646            }
647        }
648    }
649    return arkExport || null;
650}
651
652function processSdkPath(sdk: Sdk, formPath: string): string {
653    let originPath = path.join(sdk.path, formPath);
654    if (FileUtils.isDirectory(originPath)) {
655        formPath = path.join(formPath, FileUtils.getIndexFileName(originPath));
656    }
657    return `${formPath}`;
658}
659
660function getArkFileFromScene(im: FromInfo, originPath: string): ArkFile | null {
661    if (FileUtils.isDirectory(originPath)) {
662        originPath = path.join(originPath, FileUtils.getIndexFileName(originPath));
663    }
664    const fileName = path.relative(im.getDeclaringArkFile().getProjectDir(), originPath);
665    const scene = im.getDeclaringArkFile().getScene();
666    if (/\.e?ts$/.test(originPath)) {
667        const fromSignature = new FileSignature(im.getDeclaringArkFile().getProjectName(), fileName);
668        return scene.getFile(fromSignature);
669    }
670    const projectName = im.getDeclaringArkFile().getProjectName();
671    return getArkFileFormMap(projectName, fileName, scene);
672}
673
674function getArkFileFormMap(projectName: string, filePath: string, scene: Scene): ArkFile | null {
675    if (/\.e?ts$/.test(filePath)) {
676        return scene.getFile(new FileSignature(projectName, filePath));
677    }
678    const fileSuffixArray = scene.getOptions().supportFileExts;
679    if (!fileSuffixArray) {
680        return null;
681    }
682    for (const suffix of fileSuffixArray) {
683        const arkFile = scene.getFile(new FileSignature(projectName, filePath + suffix));
684        if (arkFile) {
685            return arkFile;
686        }
687    }
688    return null;
689}
690
691function findExportInfoInfile(fromInfo: FromInfo, file: ArkFile): ExportInfo | undefined {
692    const exportName = fromInfo.isDefault() ? DEFAULT : fromInfo.getOriginName();
693    let exportInfo = file.getExportInfoBy(exportName);
694    if (exportInfo) {
695        return exportInfo;
696    }
697
698    if (exportName === DEFAULT) {
699        exportInfo = file.getExportInfos().find(p => p.isDefault());
700        if (exportInfo) {
701            file.addExportInfo(exportInfo, DEFAULT);
702            return exportInfo;
703        }
704    }
705
706    if (fromInfo.getOriginName() === ALL) {
707        exportInfo = buildDefaultExportInfo(fromInfo, file);
708        file.addExportInfo(exportInfo, ALL);
709    } else if (/\.d\.e?ts$/.test(file.getName())) {
710        let declare = exportName === DEFAULT ? undefined : findArkExportInFile(fromInfo.getOriginName(), file) || undefined;
711        exportInfo = buildDefaultExportInfo(fromInfo, file, declare);
712    }
713
714    return exportInfo;
715}
716
717export function initModulePathMap(ohPkgContentMap: Map<string, { [k: string]: unknown }>): void {
718    if (moduleMap) {
719        moduleMap.clear();
720    }
721    moduleMap = FileUtils.generateModuleMap(ohPkgContentMap);
722}
723
724function getArkFileFromOtherModule(fromInfo: FromInfo): ArkFile | undefined {
725    if (!moduleMap || moduleMap.size === 0) {
726        return undefined;
727    }
728    const from = fromInfo.getFrom()!;
729    let index: number;
730    let file;
731    let modulePath;
732    //find file by given from like '@ohos/module/src/xxx' '@ohos/module/index'
733    if ((index = from.indexOf('src')) > 0 || (index = from.indexOf('Index')) > 0 || (index = from.indexOf('index')) > 0) {
734        modulePath = moduleMap.get(from.substring(0, index).replace(/\/*$/, ''));
735        file = findFileInModule(fromInfo, modulePath, from.substring(index));
736    }
737    if (file) {
738        return file;
739    }
740    modulePath = modulePath ?? moduleMap.get(from);
741    if (!modulePath) {
742        return file;
743    }
744    //find file in module json main path
745    if (modulePath.main) {
746        file = getArkFileFromScene(fromInfo, modulePath.main);
747    }
748    //find file in module path Index.ts
749    if (!file && FileUtils.isDirectory(modulePath.path)) {
750        file = findFileInModule(fromInfo, modulePath, FileUtils.getIndexFileName(modulePath.path));
751    }
752    //find file in module path/src/main/ets/TsIndex.ts
753    if (!file) {
754        file = findFileInModule(fromInfo, modulePath, '/src/main/ets/TsIndex.ts');
755    }
756    return file;
757}
758
759function findFileInModule(fromInfo: FromInfo, modulePath: ModulePath | undefined, contentPath: string): ArkFile | undefined {
760    if (!modulePath) {
761        return undefined;
762    }
763    const originPath = path.join(modulePath.path, contentPath);
764    let file;
765    if (originPath !== modulePath.main) {
766        file = getArkFileFromScene(fromInfo, originPath);
767    }
768    if (file && findExportInfoInfile(fromInfo, file)) {
769        return file;
770    }
771    return undefined;
772}
773