• 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 { BasicBlock } from '../core/graph/BasicBlock';
17import { ArkClass } from '../core/model/ArkClass';
18import { ArkFile } from '../core/model/ArkFile';
19import { ArkMethod } from '../core/model/ArkMethod';
20import { ArkNamespace } from '../core/model/ArkNamespace';
21import { Printer } from './Printer';
22import { Cfg } from '../core/graph/Cfg';
23
24/**
25 * @category save
26 */
27export class DotMethodPrinter extends Printer {
28    method: ArkMethod;
29    nesting: boolean;
30
31    constructor(method: ArkMethod, nesting: boolean = false) {
32        super();
33        this.method = method;
34        this.nesting = nesting;
35    }
36
37    public dump(): string {
38        this.printer.clear();
39        if (this.nesting) {
40            this.printer.writeIndent().writeLine(`subgraph "cluster_${this.method.getSignature()}" {`);
41        } else {
42            this.printer.writeIndent().writeLine(`digraph "${this.method.getSignature()}" {`);
43        }
44        this.printer.incIndent();
45        this.printer.writeIndent().writeLine(`label="${this.method.getSignature()}";`);
46
47        let blocks = (this.method.getCfg() as Cfg)?.getBlocks();
48        let prefix = `Node${this.stringHashCode(this.method.getSignature().toString())}`;
49        this.printBlocks(blocks, prefix);
50
51        this.printer.decIndent();
52        this.printer.writeIndent().writeLine('}');
53
54        return this.printer.toString();
55    }
56
57    protected stringHashCode(name: string): number {
58        let hashCode = 0;
59        for (let i = 0; i < name.length; i++) {
60            hashCode += name.charCodeAt(i);
61        }
62        return Math.abs(hashCode);
63    }
64
65    private printBlocks(blocks: Set<BasicBlock>, prefix: string): void {
66        if (!blocks) {
67            return;
68        }
69        let blockToNode: Map<BasicBlock, string> = new Map<BasicBlock, string>();
70        let index = 0;
71        for (let block of blocks) {
72            let name = prefix + index++;
73            blockToNode.set(block, name);
74            /** Node0 [label="entry"]; */
75            this.printer.writeIndent().writeLine(`${name} [label="${this.getBlockContent(block, this.printer.getIndent())}"];`);
76        }
77
78        for (let block of blocks) {
79            for (let nextBlock of block.getSuccessors()) {
80                // Node0 -> Node1;
81                this.printer.writeIndent().writeLine(`${blockToNode.get(block)} -> ${blockToNode.get(nextBlock)};`);
82            }
83
84            let exceptionalNextBlock = block.getExceptionalSuccessorBlocks();
85            if (!exceptionalNextBlock) {
86                continue;
87            }
88            for (const nextBlock of exceptionalNextBlock) {
89                this.printer.writeIndent().writeLine(`${blockToNode.get(block)} -> ${blockToNode.get(nextBlock)}[style="dotted"];`);
90            }
91        }
92    }
93
94    private getBlockContent(block: BasicBlock, indent: string): string {
95        let content: string[] = [`id:${block.getId()}`];
96        for (let stmt of block.getStmts()) {
97            content.push(stmt.toString().replace(/"/g, '\\"'));
98        }
99        return content.join('\n    ' + indent);
100    }
101}
102
103/**
104 * @category save
105 */
106export class DotClassPrinter extends Printer {
107    cls: ArkClass;
108    nesting: boolean;
109
110    constructor(cls: ArkClass, nesting: boolean = false) {
111        super();
112        this.cls = cls;
113        this.nesting = nesting;
114    }
115
116    public dump(): string {
117        this.printer.clear();
118        if (!this.nesting) {
119            this.printer.writeLine(`digraph "${this.cls.getName()}" {`);
120            this.printer.incIndent();
121        }
122
123        for (let method of this.cls.getMethods()) {
124            let mtd = new DotMethodPrinter(method, true);
125            this.printer.write(mtd.dump());
126        }
127
128        if (!this.nesting) {
129            this.printer.decIndent();
130            this.printer.writeLine(`}`);
131        }
132
133        return this.printer.toString();
134    }
135}
136
137/**
138 * @category save
139 */
140export class DotNamespacePrinter extends Printer {
141    ns: ArkNamespace;
142    nesting: boolean;
143
144    constructor(ns: ArkNamespace, nesting: boolean = false) {
145        super();
146        this.ns = ns;
147        this.nesting = nesting;
148    }
149
150    public dump(): string {
151        this.printer.clear();
152        if (!this.nesting) {
153            this.printer.writeLine(`digraph "${this.ns.getName()}" {`);
154            this.printer.incIndent();
155        }
156
157        for (let method of this.ns.getAllMethodsUnderThisNamespace()) {
158            let mtd = new DotMethodPrinter(method, true);
159            this.printer.write(mtd.dump());
160        }
161
162        if (!this.nesting) {
163            this.printer.decIndent();
164            this.printer.writeLine(`}`);
165        }
166
167        return this.printer.toString();
168    }
169}
170
171/**
172 * @category save
173 */
174export class DotFilePrinter extends Printer {
175    arkFile: ArkFile;
176
177    constructor(arkFile: ArkFile) {
178        super();
179        this.arkFile = arkFile;
180    }
181
182    public dump(): string {
183        this.printer.clear();
184        this.printer.writeLine(`digraph "${this.arkFile.getName()}" {`);
185        this.printer.incIndent();
186
187        for (let ns of this.arkFile.getNamespaces()) {
188            let nsPrinter = new DotNamespacePrinter(ns, true);
189            this.printer.write(nsPrinter.dump());
190        }
191
192        // print class
193        for (let cls of this.arkFile.getClasses()) {
194            let clsPrinter = new DotClassPrinter(cls, true);
195            this.printer.write(clsPrinter.dump());
196        }
197
198        this.printer.decIndent();
199        this.printer.writeLine('}');
200
201        return this.printer.toString();
202    }
203}
204