1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { ArkMethod } from '../../core/model/ArkMethod'; 17import { ArkCodeBuffer } from '../ArkStream'; 18 19import { ArkIfStmt, Stmt } from '../../core/base/Stmt'; 20import { ArkMetadataKind, CommentsMetadata } from '../../core/model/ArkMetadata'; 21import { BasePrinter } from '../base/BasePrinter'; 22import { Cfg } from '../../core/graph/Cfg'; 23import { BasicBlock } from '../../core/graph/BasicBlock'; 24 25/** 26 * @category save 27 */ 28export class ArkIRMethodPrinter extends BasePrinter { 29 private method: ArkMethod; 30 31 public constructor(method: ArkMethod, indent: string = '') { 32 super(indent); 33 this.method = method; 34 } 35 36 public dump(): string { 37 this.printer.clear(); 38 const commentsMetadata = this.method.getMetadata(ArkMetadataKind.LEADING_COMMENTS); 39 if (commentsMetadata instanceof CommentsMetadata) { 40 this.printComments(commentsMetadata); 41 } 42 43 this.printMethod(this.method); 44 45 return this.printer.toString(); 46 } 47 48 public getLine(): number { 49 let line = this.method.getLine(); 50 if (line === null) { 51 line = 0; 52 } 53 if (line > 0) { 54 return line; 55 } 56 57 const stmts: Stmt[] = []; 58 const cfg = this.method.getCfg(); 59 if (cfg) { 60 cfg.getStmts() 61 .reverse() 62 .forEach(stmt => stmts.push(stmt)); 63 } 64 for (const stmt of stmts) { 65 if (stmt.getOriginPositionInfo().getLineNo() > 0) { 66 return stmt.getOriginPositionInfo().getLineNo(); 67 } 68 } 69 70 return line; 71 } 72 73 private printMethod(method: ArkMethod): void { 74 this.printDecorator(method.getDecorators()); 75 this.printer.writeIndent().write(this.methodProtoToString(method)); 76 // abstract function no body 77 if (!method.getBody()) { 78 this.printer.writeLine(''); 79 return; 80 } 81 82 this.printer.writeLine(' {'); 83 this.printer.incIndent(); 84 this.printBody(method); 85 this.printer.decIndent(); 86 this.printer.writeIndent().writeLine('}'); 87 } 88 89 private printBody(method: ArkMethod): void { 90 if (method.getCfg()) { 91 this.printCfg(method.getCfg()!); 92 } 93 } 94 95 protected methodProtoToString(method: ArkMethod): string { 96 let code = new ArkCodeBuffer(); 97 code.writeSpace(this.modifiersToString(method.getModifiers())); 98 99 if (method.getAsteriskToken()) { 100 code.writeSpace('*'); 101 } 102 code.write(this.resolveMethodName(method.getName())); 103 104 const genericTypes = method.getGenericTypes(); 105 if (genericTypes && genericTypes.length > 0) { 106 let typeParameters: string[] = []; 107 genericTypes.forEach(genericType => { 108 typeParameters.push(genericType.toString()); 109 }); 110 code.write(`<${genericTypes.join(', ')}>`); 111 } 112 113 let parameters: string[] = []; 114 method.getParameters().forEach(parameter => { 115 let str: string = parameter.getName(); 116 if (parameter.hasDotDotDotToken()) { 117 str = `...${parameter.getName()}`; 118 } 119 if (parameter.isOptional()) { 120 str += '?'; 121 } 122 if (parameter.getType()) { 123 str += ': ' + parameter.getType().toString(); 124 } 125 parameters.push(str); 126 }); 127 code.write(`(${parameters.join(', ')})`); 128 const returnType = method.getReturnType(); 129 code.write(`: ${returnType.toString()}`); 130 return code.toString(); 131 } 132 133 private printCfg(cfg: Cfg): void { 134 let blocks = cfg.getBlocks(); 135 136 let firstBB = true; 137 for (const block of blocks) { 138 if (!firstBB) { 139 this.printer.writeLine(''); 140 } 141 this.printBasicBlock(block); 142 if (firstBB) { 143 firstBB = false; 144 } 145 } 146 } 147 148 private printBasicBlock(block: BasicBlock): void { 149 let successors = block.getSuccessors(); 150 151 this.printer.writeIndent().writeLine(`label${block.getId()}:`); 152 this.printer.incIndent(); 153 154 if (successors.length === 1) { 155 block.getStmts().map(stmt => { 156 this.printer.writeIndent().writeLine(stmt.toString()); 157 }); 158 this.printer.writeIndent().writeLine(`goto label${successors[0].getId()}`); 159 } else if (successors.length === 2) { 160 for (const stmt of block.getStmts()) { 161 if (stmt instanceof ArkIfStmt) { 162 this.printer.writeIndent().writeLine(`${stmt.toString()} goto label${successors[0].getId()} label${successors[1].getId()}`); 163 } else { 164 this.printer.writeIndent().writeLine(stmt.toString()); 165 } 166 } 167 } else { 168 block.getStmts().map(stmt => { 169 this.printer.writeIndent().writeLine(stmt.toString()); 170 }); 171 } 172 173 this.printer.decIndent(); 174 } 175} 176