• 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 { UnknownType } from '../../core/base/Type';
17import { ArkMethod } from '../../core/model/ArkMethod';
18import { ArkCodeBuffer } from '../ArkStream';
19import { SourceBase } from './SourceBase';
20import { SourceBody } from './SourceBody';
21import { SourceStmt } from './SourceStmt';
22import { SourceTransformer } from './SourceTransformer';
23import { PrinterUtils } from '../base/PrinterUtils';
24import { Stmt } from '../../core/base/Stmt';
25import { ArkNamespace } from '../../core/model/ArkNamespace';
26import { ArkMetadataKind, CommentsMetadata } from '../../core/model/ArkMetadata';
27import { getLineNo } from '../../core/base/Position';
28import { MethodSignature } from '../../core/model/ArkSignature';
29import { LEXICAL_ENV_NAME_PREFIX } from '../../core/common/Const';
30
31/**
32 * @category save
33 */
34export class SourceMethod extends SourceBase {
35    private method: ArkMethod;
36    private transformer: SourceTransformer;
37
38    public constructor(method: ArkMethod, indent: string = '') {
39        super(method.getDeclaringArkFile(), indent);
40        this.method = method;
41        this.transformer = new SourceTransformer(this);
42        this.inBuilder = this.initInBuilder();
43    }
44
45    public getDeclaringArkNamespace(): ArkNamespace | undefined {
46        return this.method.getDeclaringArkClass().getDeclaringArkNamespace();
47    }
48
49    public setInBuilder(inBuilder: boolean): void {
50        this.inBuilder = inBuilder;
51    }
52
53    public dump(): string {
54        this.printer.clear();
55        const commentsMetadata = this.method.getMetadata(ArkMetadataKind.LEADING_COMMENTS);
56        if (commentsMetadata instanceof CommentsMetadata) {
57            const comments = commentsMetadata.getComments();
58            comments.forEach(comment => {
59                this.printer.writeIndent().writeLine(comment.content);
60            });
61        }
62        if (!this.method.isDefaultArkMethod()) {
63            this.printMethod(this.method);
64        } else {
65            this.printBody(this.method);
66        }
67        return this.printer.toString();
68    }
69
70    public getLine(): number {
71        let line = this.method.getLine();
72        if (line === null && this.method.getDeclareLineCols()) {
73            line = getLineNo(this.method.getDeclareLineCols()![0]);
74        }
75        if (line === null) {
76            line = 0;
77        }
78        if (line > 0) {
79            return line;
80        }
81
82        const stmts: Stmt[] = [];
83        const cfg = this.method.getCfg();
84        if (cfg) {
85            cfg.getStmts()
86                .reverse()
87                .forEach(stmt => stmts.push(stmt));
88        }
89        for (const stmt of stmts) {
90            if (stmt.getOriginPositionInfo().getLineNo() > 0) {
91                return stmt.getOriginPositionInfo().getLineNo();
92            }
93        }
94
95        return line;
96    }
97
98    public dumpDefaultMethod(): SourceStmt[] {
99        let srcBody = new SourceBody(this.printer.getIndent(), this.method, false);
100        return srcBody.getStmts();
101    }
102
103    private printMethod(method: ArkMethod): void {
104        this.printDecorator(method.getDecorators());
105
106        let implementationSig = method.getImplementationSignature();
107
108        if (this.method.getDeclareSignatures()) {
109            for (const methodSig of this.method.getDeclareSignatures()!) {
110                this.printer.writeIndent().writeLine(`${this.methodProtoToString(methodSig)};`);
111            }
112        }
113
114        if (!implementationSig) {
115            return;
116        }
117
118        this.printer.writeIndent().write(this.methodProtoToString(implementationSig!));
119
120        // abstract function no body
121        if (SourceMethod.getPrinterOptions().noMethodBody) {
122            this.printer.writeIndent().writeLine(`;`);
123            return;
124        }
125
126        this.printer.writeLine(' {');
127        this.printer.incIndent();
128        this.printBody(method);
129        this.printer.decIndent();
130
131        this.printer.writeIndent();
132        if (PrinterUtils.isAnonymousMethod(method.getName())) {
133            this.printer.write('}');
134        } else {
135            this.printer.writeLine('}');
136        }
137    }
138
139    private printBody(method: ArkMethod): void {
140        let srcBody = new SourceBody(this.printer.getIndent(), method, this.inBuilder);
141        this.printer.write(srcBody.dump());
142    }
143
144    private methodProtoToString(methodSig: MethodSignature): string {
145        let code = new ArkCodeBuffer();
146        code.writeSpace(this.modifiersToString(this.method.getModifiers()));
147        if (!PrinterUtils.isAnonymousMethod(methodSig.getMethodSubSignature().getMethodName())) {
148            if (this.method.getDeclaringArkClass()?.isDefaultArkClass()) {
149                code.writeSpace('function');
150            }
151            if (this.method.getAsteriskToken()) {
152                code.writeSpace('*');
153            }
154            code.write(this.resolveMethodName(methodSig.getMethodSubSignature().getMethodName()));
155        }
156
157        const genericTypes = this.method.getGenericTypes();
158        if (genericTypes && genericTypes.length > 0) {
159            code.write(`<${this.transformer.typeArrayToString(genericTypes)}>`);
160        }
161
162        let parameters: string[] = [];
163        methodSig
164            .getMethodSubSignature()
165            .getParameters()
166            .forEach(parameter => {
167                let str: string = parameter.getName();
168                if (parameter.hasDotDotDotToken()) {
169                    str = `...${parameter.getName()}`;
170                }
171                if (parameter.isOptional()) {
172                    str += '?';
173                }
174                if (parameter.getType()) {
175                    str += ': ' + this.transformer.typeToString(parameter.getType());
176                }
177                if (!str.startsWith(LEXICAL_ENV_NAME_PREFIX)) {
178                    parameters.push(str);
179                }
180            });
181        code.write(`(${parameters.join(', ')})`);
182        const returnType = methodSig.getMethodSubSignature().getReturnType();
183        if (methodSig.getMethodSubSignature().getMethodName() !== 'constructor' && !(returnType instanceof UnknownType)) {
184            code.write(`: ${this.transformer.typeToString(returnType)}`);
185        }
186        if (PrinterUtils.isAnonymousMethod(methodSig.getMethodSubSignature().getMethodName())) {
187            code.write(' =>');
188        }
189        return code.toString();
190    }
191
192    public toArrowFunctionTypeString(): string {
193        let code = new ArkCodeBuffer();
194
195        let parameters: string[] = [];
196        this.method.getParameters().forEach(parameter => {
197            let str: string = parameter.getName();
198            if (parameter.isOptional()) {
199                str += '?';
200            }
201            if (parameter.getType()) {
202                str += ': ' + this.transformer.typeToString(parameter.getType());
203            }
204            parameters.push(str);
205        });
206        code.write(`(${parameters.join(', ')}) => `);
207        const returnType = this.method.getReturnType();
208        if (!(returnType instanceof UnknownType)) {
209            code.writeSpace(`${this.transformer.typeToString(returnType)}`);
210        }
211
212        return code.toString();
213    }
214
215    private initInBuilder(): boolean {
216        return (
217            this.method.hasBuilderDecorator() ||
218            ((this.method.getName() === 'build' || this.method.getName() === 'pageTransition') &&
219                !this.method.isStatic() &&
220                this.method.getDeclaringArkClass().hasViewTree())
221        );
222    }
223}
224