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