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 { Printer } from './Printer'; 17import { ArkFile } from '../core/model/ArkFile'; 18import { ArkMethod } from '../core/model/ArkMethod'; 19import { ArkNamespace } from '../core/model/ArkNamespace'; 20import { ArkClass } from '../core/model/ArkClass'; 21import { ArkField } from '../core/model/ArkField'; 22import { 23 AliasType, 24 AnnotationNamespaceType, 25 AnnotationTypeQueryType, 26 AnyType, 27 ArrayType, 28 BigIntType, 29 BooleanType, 30 ClassType, 31 EnumValueType, 32 FunctionType, 33 GenericType, 34 IntersectionType, 35 LiteralType, 36 NeverType, 37 NullType, 38 NumberType, 39 StringType, 40 TupleType, 41 Type, 42 UnclearReferenceType, 43 UndefinedType, 44 UnionType, 45 UnknownType, 46 VoidType, 47} from '../core/base/Type'; 48import { Value } from '../core/base/Value'; 49import { 50 ArkAssignStmt, 51 ArkIfStmt, 52 ArkInvokeStmt, 53 ArkReturnStmt, 54 ArkReturnVoidStmt, 55 ArkThrowStmt, 56 Stmt, 57} from '../core/base/Stmt'; 58import { 59 ArkAwaitExpr, 60 ArkCastExpr, 61 ArkConditionExpr, 62 ArkDeleteExpr, 63 ArkInstanceInvokeExpr, 64 ArkInstanceOfExpr, 65 ArkNewArrayExpr, 66 ArkNewExpr, 67 ArkNormalBinopExpr, 68 ArkPhiExpr, 69 ArkPtrInvokeExpr, 70 ArkStaticInvokeExpr, 71 ArkTypeOfExpr, 72 ArkUnopExpr, 73 ArkYieldExpr, 74} from '../core/base/Expr'; 75import { Constant } from '../core/base/Constant'; 76import { MethodParameter } from '../core/model/builder/ArkMethodBuilder'; 77import { ImportInfo } from '../core/model/ArkImport'; 78import { ExportInfo } from '../core/model/ArkExport'; 79import { AliasTypeSignature, ClassSignature, FieldSignature, FileSignature, MethodSignature, NamespaceSignature } from '../core/model/ArkSignature'; 80import { LineColPosition } from '../core/base/Position'; 81import { ArkArrayRef, ArkCaughtExceptionRef, ArkInstanceFieldRef, ArkParameterRef, ArkStaticFieldRef, ArkThisRef, ClosureFieldRef, GlobalRef } from '../core/base/Ref'; 82import { Local } from '../core/base/Local'; 83import { Cfg } from '../core/graph/Cfg'; 84import { BasicBlock } from '../core/graph/BasicBlock'; 85import { ArkBody } from '../core/model/ArkBody'; 86import { Decorator } from '../core/base/Decorator'; 87 88export class JsonPrinter extends Printer { 89 constructor(private arkFile: ArkFile) { 90 super(); 91 } 92 93 public dump(): string { 94 const jsonObject = this.serializeArkFile(this.arkFile); 95 return JSON.stringify(jsonObject, null, 2); 96 } 97 98 private serializeArkFile(file: ArkFile): object { 99 return { 100 signature: this.serializeFileSignature(file.getFileSignature()), 101 namespaces: file.getNamespaces().map(ns => this.serializeNamespace(ns)), 102 classes: file.getClasses().map(cls => this.serializeClass(cls)), 103 importInfos: file.getImportInfos().map(info => this.serializeImportInfo(info)), 104 exportInfos: file.getExportInfos().map(info => this.serializeExportInfo(info)), 105 }; 106 } 107 108 private serializeNamespace(namespace: ArkNamespace): object { 109 return { 110 signature: this.serializeNamespaceSignature(namespace.getSignature()), 111 classes: namespace.getClasses().map(cls => this.serializeClass(cls)), 112 namespaces: namespace.getNamespaces().map(ns => this.serializeNamespace(ns)), 113 }; 114 } 115 116 private serializeClass(clazz: ArkClass): object { 117 return { 118 signature: this.serializeClassSignature(clazz.getSignature()), 119 modifiers: clazz.getModifiers(), 120 decorators: clazz.getDecorators().map((decorator) => this.serializeDecorator(decorator)), 121 typeParameters: clazz.getGenericsTypes()?.map((type) => this.serializeType(type)), 122 category: clazz.getCategory(), 123 superClassName: clazz.getSuperClassName(), 124 implementedInterfaceNames: clazz.getImplementedInterfaceNames(), 125 fields: clazz.getFields().map(field => this.serializeField(field)), 126 methods: clazz.getMethods(true).map(method => this.serializeMethod(method)), 127 }; 128 } 129 130 private serializeField(field: ArkField): object { 131 return { 132 signature: this.serializeFieldSignature(field.getSignature()), 133 modifiers: field.getModifiers(), 134 decorators: field.getDecorators().map(decorator => this.serializeDecorator(decorator)), 135 questionToken: field.getQuestionToken(), 136 exclamationToken: field.getExclamationToken(), 137 }; 138 } 139 140 private serializeMethod(method: ArkMethod): object { 141 let body = method.getBody(); 142 return { 143 signature: this.serializeMethodSignature(method.getSignature()), 144 modifiers: method.getModifiers(), 145 decorators: method.getDecorators().map(decorator => this.serializeDecorator(decorator)), 146 typeParameters: method.getGenericTypes()?.map(type => this.serializeType(type)), 147 body: body && this.serializeMethodBody(body), 148 }; 149 } 150 151 private serializeMethodBody(body: ArkBody): object { 152 return { 153 locals: Array.from(body.getLocals().values()).map(local => this.serializeLocal(local)), 154 cfg: this.serializeCfg(body.getCfg()), 155 }; 156 } 157 158 private serializeMethodParameter(parameter: MethodParameter): object { 159 return { 160 name: parameter.getName(), 161 type: this.serializeType(parameter.getType()), 162 isOptional: parameter.isOptional(), 163 isRest: parameter.hasDotDotDotToken(), 164 }; 165 } 166 167 private serializeImportInfo(importInfo: ImportInfo): object { 168 return { 169 importClauseName: importInfo.getImportClauseName(), 170 importType: importInfo.getImportType(), 171 importFrom: importInfo.getFrom(), 172 nameBeforeAs: importInfo.getNameBeforeAs(), 173 modifiers: importInfo.getModifiers(), 174 originTsPosition: this.serializeLineColPosition(importInfo.getOriginTsPosition()), 175 }; 176 } 177 178 private serializeExportInfo(exportInfo: ExportInfo): object { 179 return { 180 exportClauseName: exportInfo.getExportClauseName(), 181 exportClauseType: exportInfo.getExportClauseType(), 182 exportFrom: exportInfo.getFrom(), 183 nameBeforeAs: exportInfo.getNameBeforeAs(), 184 isDefault: exportInfo.isDefault(), 185 modifiers: exportInfo.getModifiers(), 186 originTsPosition: this.serializeLineColPosition(exportInfo.getOriginTsPosition()), 187 }; 188 } 189 190 private serializeDecorator(decorator: Decorator): object { 191 return { 192 kind: decorator.getKind(), 193 }; 194 } 195 196 private serializeLineColPosition(position: LineColPosition): object { 197 return { 198 line: position.getLineNo(), 199 col: position.getColNo(), 200 }; 201 } 202 203 private serializeType(type: Type): object { 204 if (type === undefined) { 205 throw new Error('Type is undefined'); 206 } 207 208 if (type instanceof AnyType) { 209 return { 210 _: 'AnyType', 211 }; 212 } else if (type instanceof UnknownType) { 213 return { 214 _: 'UnknownType', 215 }; 216 } else if (type instanceof VoidType) { 217 return { 218 _: 'VoidType', 219 }; 220 } else if (type instanceof NeverType) { 221 return { 222 _: 'NeverType', 223 }; 224 } else if (type instanceof UnionType) { 225 return { 226 _: 'UnionType', 227 types: type.getTypes().map(type => this.serializeType(type)), 228 }; 229 } else if (type instanceof IntersectionType) { 230 return { 231 _: 'IntersectionType', 232 types: type.getTypes().map((type) => this.serializeType(type)), 233 }; 234 } else if (type instanceof TupleType) { 235 return { 236 _: 'TupleType', 237 types: type.getTypes().map(type => this.serializeType(type)), 238 }; 239 } else if (type instanceof BooleanType) { 240 return { 241 _: 'BooleanType', 242 }; 243 } else if (type instanceof NumberType) { 244 return { 245 _: 'NumberType', 246 }; 247 } else if (type instanceof BigIntType) { 248 return { 249 _: 'BigIntType', 250 }; 251 } else if (type instanceof StringType) { 252 return { 253 _: 'StringType', 254 }; 255 } else if (type instanceof NullType) { 256 return { 257 _: 'NullType', 258 }; 259 } else if (type instanceof UndefinedType) { 260 return { 261 _: 'UndefinedType', 262 }; 263 } else if (type instanceof LiteralType) { 264 return { 265 _: 'LiteralType', 266 literal: type.getLiteralName(), 267 }; 268 } else if (type instanceof ClassType) { 269 return { 270 _: 'ClassType', 271 signature: this.serializeClassSignature(type.getClassSignature()), 272 typeParameters: type.getRealGenericTypes()?.map(type => this.serializeType(type)), 273 }; 274 } else if (type instanceof FunctionType) { 275 return { 276 _: 'FunctionType', 277 signature: this.serializeMethodSignature(type.getMethodSignature()), 278 typeParameters: type.getRealGenericTypes()?.map(type => this.serializeType(type)), 279 }; 280 } else if (type instanceof ArrayType) { 281 return { 282 _: 'ArrayType', 283 elementType: this.serializeType(type.getBaseType()), 284 dimensions: type.getDimension(), 285 }; 286 } else if (type instanceof UnclearReferenceType) { 287 return { 288 _: 'UnclearReferenceType', 289 name: type.getName(), 290 typeParameters: type.getGenericTypes().map(type => this.serializeType(type)), 291 }; 292 } else if (type instanceof GenericType) { 293 let constraint = type.getConstraint(); 294 let defaultType = type.getDefaultType(); 295 return { 296 _: 'GenericType', 297 name: type.getName(), 298 constraint: constraint && this.serializeType(constraint), 299 defaultType: defaultType && this.serializeType(defaultType), 300 }; 301 } else if (type instanceof AliasType) { 302 return { 303 _: 'AliasType', 304 name: type.getName(), 305 originalType: this.serializeType(type.getOriginalType()), 306 signature: this.serializeAliasTypeSignature(type.getSignature()), 307 }; 308 } else if (type instanceof AnnotationNamespaceType) { 309 return { 310 _: 'AnnotationNamespaceType', 311 originType: type.getOriginType(), 312 namespaceSignature: this.serializeNamespaceSignature(type.getNamespaceSignature()), 313 }; 314 } else if (type instanceof AnnotationTypeQueryType) { 315 return { 316 _: 'AnnotationTypeQueryType', 317 originType: type.getOriginType(), 318 }; 319 } else if (type instanceof EnumValueType) { 320 const c = type.getConstant(); 321 return { 322 _: 'EnumValueType', 323 signature: this.serializeFieldSignature(type.getFieldSignature()), 324 constant: c && this.serializeValue(c), 325 }; 326 } else { 327 console.warn(`Unhandled Type: ${type.constructor.name} (${type.toString()})`); 328 return { 329 _: type.constructor.name, 330 text: type.toString(), 331 }; 332 } 333 } 334 335 private serializeFileSignature(file: FileSignature): object { 336 return { 337 projectName: file.getProjectName(), 338 fileName: file.getFileName(), 339 }; 340 } 341 342 private serializeNamespaceSignature(namespace: NamespaceSignature): object { 343 let dns = namespace.getDeclaringNamespaceSignature(); 344 return { 345 name: namespace.getNamespaceName(), 346 declaringFile: this.serializeFileSignature(namespace.getDeclaringFileSignature()), 347 declaringNamespace: dns && this.serializeNamespaceSignature(dns), 348 }; 349 } 350 351 private serializeClassSignature(clazz: ClassSignature): object { 352 let dns = clazz.getDeclaringNamespaceSignature(); 353 return { 354 name: clazz.getClassName(), 355 declaringFile: this.serializeFileSignature(clazz.getDeclaringFileSignature()), 356 declaringNamespace: dns && this.serializeNamespaceSignature(dns), 357 }; 358 } 359 360 private serializeFieldSignature(field: FieldSignature): object { 361 let declaringSignature: ClassSignature | NamespaceSignature = field.getDeclaringSignature(); 362 let declaringClass; 363 if (declaringSignature instanceof ClassSignature) { 364 declaringClass = this.serializeClassSignature(declaringSignature); 365 } else { 366 declaringClass = this.serializeNamespaceSignature(declaringSignature); 367 } 368 return { 369 declaringClass, 370 name: field.getFieldName(), 371 type: this.serializeType(field.getType()), 372 }; 373 } 374 375 private serializeMethodSignature(method: MethodSignature): object { 376 return { 377 declaringClass: this.serializeClassSignature(method.getDeclaringClassSignature()), 378 name: method.getMethodSubSignature().getMethodName(), 379 parameters: method 380 .getMethodSubSignature() 381 .getParameters() 382 .map(param => this.serializeMethodParameter(param)), 383 returnType: this.serializeType(method.getType()), 384 }; 385 } 386 387 private serializeAliasTypeSignature(signature: AliasTypeSignature): object { 388 return { 389 name: signature.getName(), 390 method: this.serializeMethodSignature(signature.getDeclaringMethodSignature()), 391 }; 392 } 393 394 private serializeCfg(cfg: Cfg): object { 395 const visited = new Set<BasicBlock>(); 396 const stack: BasicBlock[] = []; 397 const startingBlock = cfg.getStartingBlock(); 398 if (startingBlock) { 399 stack.push(startingBlock); 400 } 401 let id = 0; 402 while (stack.length > 0) { 403 const block = stack.pop()!; 404 if (visited.has(block)) { 405 continue; 406 } 407 visited.add(block); 408 block.setId(id++); 409 stack.push(...block.getSuccessors()); 410 } 411 return { 412 blocks: Array.from(visited).map(block => this.serializeBasicBlock(block)), 413 }; 414 } 415 416 private serializeBasicBlock(block: BasicBlock): object { 417 const successors = block.getSuccessors().map(succ => succ.getId()); 418 successors.sort((a, b) => a - b); 419 const predecessors = block.getPredecessors().map(pred => pred.getId()); 420 predecessors.sort((a, b) => a - b); 421 return { 422 id: block.getId(), 423 successors, 424 predecessors, 425 stmts: block.getStmts().map(stmt => this.serializeStmt(stmt)), 426 }; 427 } 428 429 private serializeLocal(local: Local): object { 430 return { 431 name: local.getName(), 432 type: this.serializeType(local.getType()), 433 }; 434 } 435 436 private serializeConstant(constant: Constant): object { 437 return { 438 value: constant.getValue(), 439 type: this.serializeType(constant.getType()), 440 }; 441 } 442 443 private serializeValue(value: Value): object { 444 if (value === undefined) { 445 throw new Error('Value is undefined'); 446 } 447 448 if (value instanceof Local) { 449 return { 450 _: 'Local', 451 ...this.serializeLocal(value), 452 }; 453 } else if (value instanceof Constant) { 454 return { 455 _: 'Constant', 456 ...this.serializeConstant(value), 457 }; 458 } else if (value instanceof ArkNewExpr) { 459 return { 460 _: 'NewExpr', 461 classType: this.serializeType(value.getClassType()), 462 }; 463 } else if (value instanceof ArkNewArrayExpr) { 464 return { 465 _: 'NewArrayExpr', 466 elementType: this.serializeType(value.getBaseType()), 467 size: this.serializeValue(value.getSize()), 468 }; 469 } else if (value instanceof ArkDeleteExpr) { 470 return { 471 _: 'DeleteExpr', 472 arg: this.serializeValue(value.getField()), 473 }; 474 } else if (value instanceof ArkAwaitExpr) { 475 return { 476 _: 'AwaitExpr', 477 arg: this.serializeValue(value.getPromise()), 478 }; 479 } else if (value instanceof ArkYieldExpr) { 480 return { 481 _: 'YieldExpr', 482 arg: this.serializeValue(value.getYieldValue()), 483 }; 484 } else if (value instanceof ArkTypeOfExpr) { 485 return { 486 _: 'TypeOfExpr', 487 arg: this.serializeValue(value.getOp()), 488 }; 489 } else if (value instanceof ArkInstanceOfExpr) { 490 return { 491 _: 'InstanceOfExpr', 492 arg: this.serializeValue(value.getOp()), 493 checkType: this.serializeType(value.getCheckType()), 494 }; 495 } else if (value instanceof ArkCastExpr) { 496 return { 497 _: 'CastExpr', 498 arg: this.serializeValue(value.getOp()), 499 type: this.serializeType(value.getType()), 500 }; 501 } else if (value instanceof ArkPhiExpr) { 502 const args = value.getArgs(); 503 const argToBlock = value.getArgToBlock(); 504 return { 505 _: 'PhiExpr', 506 args: args.map(arg => this.serializeValue(arg)), 507 blocks: args.map(arg => argToBlock.get(arg)!.getId()), 508 type: this.serializeType(value.getType()), 509 }; 510 } else if (value instanceof ArkConditionExpr) { 511 return { 512 _: 'ConditionExpr', 513 op: value.getOperator(), 514 left: this.serializeValue(value.getOp1()), 515 right: this.serializeValue(value.getOp2()), 516 type: this.serializeType(value.getType()), 517 }; 518 } else if (value instanceof ArkNormalBinopExpr) { 519 return { 520 _: 'BinopExpr', 521 op: value.getOperator(), 522 left: this.serializeValue(value.getOp1()), 523 right: this.serializeValue(value.getOp2()), 524 }; 525 } else if (value instanceof ArkUnopExpr) { 526 return { 527 _: 'UnopExpr', 528 op: value.getOperator(), 529 arg: this.serializeValue(value.getOp()), 530 }; 531 } else if (value instanceof ArkInstanceInvokeExpr) { 532 return { 533 _: 'InstanceCallExpr', 534 instance: this.serializeValue(value.getBase()), 535 method: this.serializeMethodSignature(value.getMethodSignature()), 536 args: value.getArgs().map(arg => this.serializeValue(arg)), 537 }; 538 } else if (value instanceof ArkStaticInvokeExpr) { 539 return { 540 _: 'StaticCallExpr', 541 method: this.serializeMethodSignature(value.getMethodSignature()), 542 args: value.getArgs().map(arg => this.serializeValue(arg)), 543 }; 544 } else if (value instanceof ArkPtrInvokeExpr) { 545 return { 546 _: 'PtrCallExpr', 547 ptr: this.serializeValue(value.getFuncPtrLocal()), 548 method: this.serializeMethodSignature(value.getMethodSignature()), 549 args: value.getArgs().map(arg => this.serializeValue(arg)), 550 }; 551 } else if (value instanceof ArkThisRef) { 552 return { 553 _: 'ThisRef', 554 type: this.serializeType(value.getType()), 555 }; 556 } else if (value instanceof ArkParameterRef) { 557 return { 558 _: 'ParameterRef', 559 index: value.getIndex(), 560 type: this.serializeType(value.getType()), 561 }; 562 } else if (value instanceof ArkArrayRef) { 563 return { 564 _: 'ArrayRef', 565 array: this.serializeValue(value.getBase()), 566 index: this.serializeValue(value.getIndex()), 567 type: this.serializeType(value.getType()), 568 }; 569 } else if (value instanceof ArkCaughtExceptionRef) { 570 return { 571 _: 'CaughtExceptionRef', 572 type: this.serializeType(value.getType()), 573 }; 574 } else if (value instanceof GlobalRef) { 575 let ref = value.getRef(); 576 return { 577 _: 'GlobalRef', 578 name: value.getName(), 579 ref: ref ? this.serializeValue(ref) : null, 580 }; 581 } else if (value instanceof ClosureFieldRef) { 582 return { 583 _: 'ClosureFieldRef', 584 base: this.serializeLocal(value.getBase()), 585 fieldName: value.getFieldName(), 586 type: this.serializeType(value.getType()), 587 }; 588 } else if (value instanceof ArkInstanceFieldRef) { 589 return { 590 _: 'InstanceFieldRef', 591 instance: this.serializeValue(value.getBase()), 592 field: this.serializeFieldSignature(value.getFieldSignature()), 593 }; 594 } else if (value instanceof ArkStaticFieldRef) { 595 return { 596 _: 'StaticFieldRef', 597 field: this.serializeFieldSignature(value.getFieldSignature()), 598 }; 599 } else { 600 console.warn(`Unhandled Value: ${value.constructor.name} (${value.toString()})`); 601 return { 602 _: value.constructor.name, 603 text: value.toString(), 604 type: this.serializeType(value.getType()), 605 }; 606 } 607 } 608 609 private serializeStmt(stmt: Stmt): object { 610 if (stmt instanceof ArkAssignStmt) { 611 return { 612 _: 'AssignStmt', 613 left: this.serializeValue(stmt.getLeftOp()), 614 right: this.serializeValue(stmt.getRightOp()), 615 }; 616 } else if (stmt instanceof ArkInvokeStmt) { 617 return { 618 _: 'CallStmt', 619 expr: this.serializeValue(stmt.getInvokeExpr()), 620 }; 621 } else if (stmt instanceof ArkIfStmt) { 622 return { 623 _: 'IfStmt', 624 condition: this.serializeValue(stmt.getConditionExpr()), 625 }; 626 } else if (stmt instanceof ArkReturnVoidStmt) { 627 return { 628 _: 'ReturnVoidStmt', 629 }; 630 } else if (stmt instanceof ArkReturnStmt) { 631 return { 632 _: 'ReturnStmt', 633 arg: this.serializeValue(stmt.getOp()), 634 }; 635 } else if (stmt instanceof ArkThrowStmt) { 636 return { 637 _: 'ThrowStmt', 638 arg: this.serializeValue(stmt.getOp()), 639 }; 640 } else { 641 console.warn(`Unhandled Stmt: ${stmt.constructor.name} (${stmt.toString()})`); 642 return { 643 _: stmt.constructor.name, 644 text: stmt.toString(), 645 }; 646 } 647 } 648} 649