• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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