1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include "qmltccodewriter.h" |
5 | |
6 | #include <QtCore/qfileinfo.h> |
7 | #include <QtCore/qstringbuilder.h> |
8 | #include <QtCore/qstring.h> |
9 | #include <QtCore/qmap.h> |
10 | #include <QtCore/qlist.h> |
11 | |
12 | #include <utility> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | using namespace Qt::StringLiterals; |
17 | |
18 | static QString urlToMacro(const QString &url) |
19 | { |
20 | QFileInfo fi(url); |
21 | return u"Q_QMLTC_" + fi.baseName().toUpper(); |
22 | } |
23 | |
24 | static QString getFunctionCategory(const QmltcMethodBase &method) |
25 | { |
26 | QString category; |
27 | switch (method.access) { |
28 | case QQmlJSMetaMethod::Private: |
29 | category = u"private"_s ; |
30 | break; |
31 | case QQmlJSMetaMethod::Protected: |
32 | category = u"protected"_s ; |
33 | break; |
34 | case QQmlJSMetaMethod::Public: |
35 | category = u"public"_s ; |
36 | break; |
37 | } |
38 | return category; |
39 | } |
40 | |
41 | static QString getFunctionCategory(const QmltcMethod &method) |
42 | { |
43 | QString category = getFunctionCategory(method: static_cast<const QmltcMethodBase &>(method)); |
44 | switch (method.type) { |
45 | case QQmlJSMetaMethodType::Signal: |
46 | category = u"Q_SIGNALS"_s ; |
47 | break; |
48 | case QQmlJSMetaMethodType::Slot: |
49 | category += u" Q_SLOTS"_s ; |
50 | break; |
51 | case QQmlJSMetaMethodType::Method: |
52 | case QQmlJSMetaMethodType::StaticMethod: |
53 | break; |
54 | } |
55 | return category; |
56 | } |
57 | |
58 | static QString appendSpace(const QString &s) |
59 | { |
60 | if (s.isEmpty()) |
61 | return s; |
62 | return s + u" " ; |
63 | } |
64 | |
65 | static QString prependSpace(const QString &s) |
66 | { |
67 | if (s.isEmpty()) |
68 | return s; |
69 | return u" " + s; |
70 | } |
71 | |
72 | static std::pair<QString, QString> functionSignatures(const QmltcMethodBase &method) |
73 | { |
74 | const QString name = method.name; |
75 | const QList<QmltcVariable> ¶meterList = method.parameterList; |
76 | |
77 | QStringList ; |
78 | QStringList cppParamList; |
79 | for (const QmltcVariable &variable : parameterList) { |
80 | const QString commonPart = variable.cppType + u" " + variable.name; |
81 | cppParamList << commonPart; |
82 | headerParamList << commonPart; |
83 | if (!variable.defaultValue.isEmpty()) |
84 | headerParamList.back() += u" = " + variable.defaultValue; |
85 | } |
86 | |
87 | const QString = name + u"(" + headerParamList.join(sep: u", "_s ) + u")" |
88 | + prependSpace(s: method.modifiers.join(sep: u" " )); |
89 | const QString cppSignature = name + u"(" + cppParamList.join(sep: u", "_s ) + u")" |
90 | + prependSpace(s: method.modifiers.join(sep: u" " )); |
91 | return { headerSignature, cppSignature }; |
92 | } |
93 | |
94 | static QString functionReturnType(const QmltcMethod &m) |
95 | { |
96 | return appendSpace(s: m.declarationPrefixes.join(sep: u" "_s )) + m.returnType; |
97 | } |
98 | |
99 | void QmltcCodeWriter::(QmltcOutputWrapper &code, const QString &sourcePath, |
100 | const QString &hPath, const QString &cppPath, |
101 | const QString &outNamespace, |
102 | const QSet<QString> &requiredCppIncludes) |
103 | { |
104 | Q_UNUSED(cppPath); |
105 | const QString preamble = u"// This code is auto-generated by the qmltc tool from the file '" |
106 | + sourcePath + u"'\n// WARNING! All changes made in this file will be lost!\n" ; |
107 | code.rawAppendToHeader(what: preamble); |
108 | code.rawAppendToCpp(what: preamble); |
109 | code.rawAppendToHeader( |
110 | what: u"// NOTE: This generated API is to be considered implementation detail." ); |
111 | code.rawAppendToHeader( |
112 | what: u"// It may change from version to version and should not be relied upon." ); |
113 | |
114 | const QString = urlToMacro(url: sourcePath); |
115 | code.rawAppendToHeader(what: u"#ifndef %1_H"_s .arg(a: headerMacro)); |
116 | code.rawAppendToHeader(what: u"#define %1_H"_s .arg(a: headerMacro)); |
117 | |
118 | code.rawAppendToHeader(what: u"#include <QtCore/qproperty.h>" ); |
119 | code.rawAppendToHeader(what: u"#include <QtCore/qobject.h>" ); |
120 | code.rawAppendToHeader(what: u"#include <QtCore/qcoreapplication.h>" ); |
121 | code.rawAppendToHeader(what: u"#include <QtQml/qqmlengine.h>" ); |
122 | code.rawAppendToHeader(what: u"#include <QtCore/qurl.h>" ); // used in engine execution |
123 | code.rawAppendToHeader(what: u"#include <QtQml/qqml.h>" ); // used for attached properties |
124 | |
125 | code.rawAppendToHeader(what: u"#include <private/qqmlengine_p.h>" ); // executeRuntimeFunction(), etc. |
126 | code.rawAppendToHeader(what: u"#include <private/qqmltcobjectcreationhelper_p.h>" ); // QmltcSupportLib |
127 | |
128 | code.rawAppendToHeader(what: u"#include <QtQml/qqmllist.h>" ); // QQmlListProperty |
129 | |
130 | // include custom C++ includes required by used types |
131 | code.rawAppendToHeader(what: u"// BEGIN(custom_cpp_includes)" ); |
132 | for (const auto &requiredInclude : requiredCppIncludes) |
133 | code.rawAppendToHeader(what: u"#include \"" + requiredInclude + u"\"" ); |
134 | code.rawAppendToHeader(what: u"// END(custom_cpp_includes)" ); |
135 | |
136 | code.rawAppendToCpp(what: u"#include \"" + hPath + u"\"" ); // include own .h file |
137 | code.rawAppendToCpp(what: u"// qmltc support library:" ); |
138 | code.rawAppendToCpp(what: u"#include <private/qqmlcppbinding_p.h>" ); // QmltcSupportLib |
139 | code.rawAppendToCpp(what: u"#include <private/qqmlcpponassignment_p.h>" ); // QmltcSupportLib |
140 | code.rawAppendToHeader(what: u"#include <private/qqmlcpptypehelpers_p.h> " ); // QmltcSupportLib |
141 | |
142 | code.rawAppendToCpp(what: u"#include <private/qqmlobjectcreator_p.h>" ); // createComponent() |
143 | code.rawAppendToCpp(what: u"#include <private/qqmlcomponent_p.h>" ); // QQmlComponentPrivate::get() |
144 | |
145 | code.rawAppendToCpp(what: u"" ); |
146 | code.rawAppendToCpp(what: u"#include <private/qobject_p.h>" ); // NB: for private properties |
147 | code.rawAppendToCpp(what: u"#include <private/qqmlobjectcreator_p.h>" ); // for finalize callbacks |
148 | code.rawAppendToCpp(what: u"#include <QtQml/qqmlprivate.h>" ); // QQmlPrivate::qmlExtendedObject() |
149 | |
150 | code.rawAppendToCpp(what: u"" ); // blank line |
151 | code.rawAppendToCpp(what: u"QT_USE_NAMESPACE // avoid issues with QT_NAMESPACE" ); |
152 | |
153 | code.rawAppendToHeader(what: u"" ); // blank line |
154 | |
155 | const QStringList namespaces = outNamespace.split(sep: u"::"_s ); |
156 | |
157 | for (const QString ¤tNamespace : namespaces) { |
158 | code.rawAppendToHeader(what: u"namespace %1 {"_s .arg(a: currentNamespace)); |
159 | code.rawAppendToCpp(what: u"namespace %1 {"_s .arg(a: currentNamespace)); |
160 | } |
161 | } |
162 | |
163 | void QmltcCodeWriter::(QmltcOutputWrapper &code, const QString &sourcePath, |
164 | const QString &outNamespace) |
165 | { |
166 | const QStringList namespaces = outNamespace.split(sep: u"::"_s ); |
167 | |
168 | for (auto it = namespaces.crbegin(), end = namespaces.crend(); it != end; it++) { |
169 | code.rawAppendToCpp(what: u"} // namespace %1"_s .arg(a: *it)); |
170 | code.rawAppendToHeader(what: u"} // namespace %1"_s .arg(a: *it)); |
171 | } |
172 | |
173 | code.rawAppendToHeader(what: u"" ); // blank line |
174 | code.rawAppendToHeader(what: u"#endif // %1_H"_s .arg(a: urlToMacro(url: sourcePath))); |
175 | code.rawAppendToHeader(what: u"" ); // blank line |
176 | } |
177 | |
178 | static void writeToFile(const QString &path, const QByteArray &data) |
179 | { |
180 | // When not using dependency files, changing a single qml invalidates all |
181 | // qml files and would force the recompilation of everything. To avoid that, |
182 | // we check if the data is equal to the existing file, if yes, don't touch |
183 | // it so the build system will not recompile unnecessary things. |
184 | // |
185 | // If the build system use dependency file, we should anyway touch the file |
186 | // so qmltc is not re-run |
187 | QFileInfo fi(path); |
188 | if (fi.exists() && fi.size() == data.size()) { |
189 | QFile oldFile(path); |
190 | oldFile.open(flags: QIODevice::ReadOnly); |
191 | if (oldFile.readAll() == data) |
192 | return; |
193 | } |
194 | QFile file(path); |
195 | file.open(flags: QIODevice::WriteOnly); |
196 | file.write(data); |
197 | } |
198 | |
199 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProgram &program) |
200 | { |
201 | writeGlobalHeader(code, sourcePath: program.url, hPath: program.hPath, cppPath: program.cppPath, outNamespace: program.outNamespace, |
202 | requiredCppIncludes: program.includes); |
203 | |
204 | // url method comes first |
205 | writeUrl(code, urlMethod: program.urlMethod); |
206 | |
207 | // forward declare all the types first |
208 | for (const QmltcType &type : std::as_const(t: program.compiledTypes)) |
209 | code.rawAppendToHeader(what: u"class " + type.cppType + u";" ); |
210 | // write all the types and their content |
211 | for (const QmltcType &type : std::as_const(t: program.compiledTypes)) |
212 | write(code, type, exportMacro: program.exportMacro); |
213 | |
214 | // add typeCount definitions. after all types have been written down (so |
215 | // they are now complete types as per C++). practically, this only concerns |
216 | // document root type |
217 | for (const QmltcType &type : std::as_const(t: program.compiledTypes)) { |
218 | if (!type.typeCount) |
219 | continue; |
220 | code.rawAppendToHeader(what: u"" ); // blank line |
221 | code.rawAppendToHeader(what: u"constexpr %1 %2::%3()"_s .arg(args: type.typeCount->returnType, |
222 | args: type.cppType, args: type.typeCount->name)); |
223 | code.rawAppendToHeader(what: u"{" ); |
224 | for (const QString &line : std::as_const(t: type.typeCount->body)) |
225 | code.rawAppendToHeader(what: line, extraIndent: 1); |
226 | code.rawAppendToHeader(what: u"}" ); |
227 | } |
228 | |
229 | writeGlobalFooter(code, sourcePath: program.url, outNamespace: program.outNamespace); |
230 | |
231 | writeToFile(path: program.hPath, data: code.code().header.toUtf8()); |
232 | writeToFile(path: program.cppPath, data: code.code().cpp.toUtf8()); |
233 | } |
234 | |
235 | template<typename Predicate> |
236 | static void dumpFunctions(QmltcOutputWrapper &code, const QList<QmltcMethod> &functions, |
237 | Predicate pred) |
238 | { |
239 | // functions are _ordered_ by access and kind. ordering is important to |
240 | // provide consistent output |
241 | QMap<QString, QList<const QmltcMethod *>> orderedFunctions; |
242 | for (const auto &function : functions) { |
243 | if (pred(function)) |
244 | orderedFunctions[getFunctionCategory(method: function)].append(t: std::addressof(r: function)); |
245 | } |
246 | |
247 | for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) { |
248 | code.rawAppendToHeader(what: it.key() + u":" , extraIndent: -1); |
249 | for (const QmltcMethod *function : std::as_const(t: it.value())) |
250 | QmltcCodeWriter::write(code, method: *function); |
251 | } |
252 | } |
253 | |
254 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type, |
255 | const QString &exportMacro) |
256 | { |
257 | const auto constructClassString = [&]() { |
258 | QString str = u"class "_s ; |
259 | if (!exportMacro.isEmpty()) |
260 | str.append(s: exportMacro).append(s: u" "_s ); |
261 | str.append(s: type.cppType); |
262 | QStringList nonEmptyBaseClasses; |
263 | nonEmptyBaseClasses.reserve(asize: type.baseClasses.size()); |
264 | std::copy_if(first: type.baseClasses.cbegin(), last: type.baseClasses.cend(), |
265 | result: std::back_inserter(x&: nonEmptyBaseClasses), |
266 | pred: [](const QString &entry) { return !entry.isEmpty(); }); |
267 | if (!nonEmptyBaseClasses.isEmpty()) |
268 | str += u" : public " + nonEmptyBaseClasses.join(sep: u", public "_s ); |
269 | return str; |
270 | }; |
271 | |
272 | code.rawAppendToHeader(what: u"" ); // blank line |
273 | code.rawAppendToCpp(what: u"" ); // blank line |
274 | |
275 | code.rawAppendToHeader(what: constructClassString()); |
276 | code.rawAppendToHeader(what: u"{" ); |
277 | for (const QString &mocLine : std::as_const(t: type.mocCode)) |
278 | code.rawAppendToHeader(what: mocLine, extraIndent: 1); |
279 | |
280 | QmltcOutputWrapper::MemberNameScope typeScope(&code, type.cppType); |
281 | Q_UNUSED(typeScope); |
282 | { |
283 | QmltcOutputWrapper::HeaderIndentationScope (&code); |
284 | Q_UNUSED(headerIndent); |
285 | |
286 | // first, write user-visible code, then everything else. someone might |
287 | // want to look at the generated code, so let's make an effort when |
288 | // writing it down |
289 | |
290 | code.rawAppendToHeader(what: u"/* ----------------- */" ); |
291 | code.rawAppendToHeader(what: u"/* External C++ API */" ); |
292 | code.rawAppendToHeader(what: u"public:" , extraIndent: -1); |
293 | |
294 | // NB: when non-document root, the externalCtor won't be public - but we |
295 | // really don't care about the output format of such types |
296 | if (!type.ignoreInit && type.externalCtor.access == QQmlJSMetaMethod::Public) { |
297 | // TODO: ignoreInit must be eliminated |
298 | |
299 | QmltcCodeWriter::write(code, ctor: type.externalCtor); |
300 | if (type.staticCreate) |
301 | QmltcCodeWriter::write(code, method: *type.staticCreate); |
302 | } |
303 | |
304 | // dtor |
305 | if (type.dtor) |
306 | QmltcCodeWriter::write(code, dtor: *type.dtor); |
307 | |
308 | // enums |
309 | for (const auto &enumeration : std::as_const(t: type.enums)) |
310 | QmltcCodeWriter::write(code, enumeration); |
311 | |
312 | // visible functions |
313 | const auto isUserVisibleFunction = [](const QmltcMethod &function) { |
314 | return function.userVisible; |
315 | }; |
316 | dumpFunctions(code, functions: type.functions, pred: isUserVisibleFunction); |
317 | |
318 | code.rawAppendToHeader(what: u"/* ----------------- */" ); |
319 | code.rawAppendToHeader(what: u"" ); // blank line |
320 | code.rawAppendToHeader(what: u"/* Internal functionality (do NOT use it!) */" ); |
321 | |
322 | // below are the hidden parts of the type |
323 | |
324 | // (rest of the) ctors |
325 | if (type.ignoreInit) { // TODO: this branch should be eliminated |
326 | Q_ASSERT(type.baselineCtor.access == QQmlJSMetaMethod::Public); |
327 | code.rawAppendToHeader(what: u"public:" , extraIndent: -1); |
328 | QmltcCodeWriter::write(code, ctor: type.baselineCtor); |
329 | } else { |
330 | code.rawAppendToHeader(what: u"protected:" , extraIndent: -1); |
331 | if (type.externalCtor.access != QQmlJSMetaMethod::Public) { |
332 | Q_ASSERT(type.externalCtor.access == QQmlJSMetaMethod::Protected); |
333 | QmltcCodeWriter::write(code, ctor: type.externalCtor); |
334 | } |
335 | QmltcCodeWriter::write(code, ctor: type.baselineCtor); |
336 | QmltcCodeWriter::write(code, method: type.init); |
337 | QmltcCodeWriter::write(code, method: type.endInit); |
338 | QmltcCodeWriter::write(code, method: type.setComplexBindings); |
339 | QmltcCodeWriter::write(code, method: type.beginClass); |
340 | QmltcCodeWriter::write(code, method: type.completeComponent); |
341 | QmltcCodeWriter::write(code, method: type.finalizeComponent); |
342 | QmltcCodeWriter::write(code, method: type.handleOnCompleted); |
343 | } |
344 | |
345 | // children |
346 | for (const auto &child : std::as_const(t: type.children)) |
347 | QmltcCodeWriter::write(code, type: child, exportMacro); |
348 | |
349 | // (non-visible) functions |
350 | dumpFunctions(code, functions: type.functions, pred: std::not_fn(fn: isUserVisibleFunction)); |
351 | |
352 | // variables and properties |
353 | if (!type.variables.isEmpty() || !type.properties.isEmpty()) { |
354 | code.rawAppendToHeader(what: u"" ); // blank line |
355 | code.rawAppendToHeader(what: u"protected:" , extraIndent: -1); |
356 | } |
357 | for (const auto &property : std::as_const(t: type.properties)) |
358 | write(code, prop: property); |
359 | for (const auto &variable : std::as_const(t: type.variables)) |
360 | write(code, var: variable); |
361 | } |
362 | |
363 | code.rawAppendToHeader(what: u"private:" , extraIndent: -1); |
364 | for (const QString &otherLine : std::as_const(t: type.otherCode)) |
365 | code.rawAppendToHeader(what: otherLine, extraIndent: 1); |
366 | |
367 | if (type.typeCount) { |
368 | // add typeCount declaration, definition is added later |
369 | code.rawAppendToHeader(what: u"" ); // blank line |
370 | code.rawAppendToHeader(what: u"protected:" ); |
371 | code.rawAppendToHeader(what: u"constexpr static %1 %2();"_s .arg(args: type.typeCount->returnType, |
372 | args: type.typeCount->name), |
373 | extraIndent: 1); |
374 | } |
375 | |
376 | code.rawAppendToHeader(what: u"};" ); |
377 | } |
378 | |
379 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcEnum &enumeration) |
380 | { |
381 | code.rawAppendToHeader(what: u"enum " + enumeration.cppType + u" {" ); |
382 | for (qsizetype i = 0; i < enumeration.keys.size(); ++i) { |
383 | QString str; |
384 | if (enumeration.values.isEmpty()) { |
385 | str += enumeration.keys.at(i) + u"," ; |
386 | } else { |
387 | str += enumeration.keys.at(i) + u" = " + enumeration.values.at(i) + u"," ; |
388 | } |
389 | code.rawAppendToHeader(what: str, extraIndent: 1); |
390 | } |
391 | code.rawAppendToHeader(what: u"};" ); |
392 | code.rawAppendToHeader(what: enumeration.ownMocLine); |
393 | } |
394 | |
395 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcMethod &method) |
396 | { |
397 | const auto [hSignature, cppSignature] = functionSignatures(method); |
398 | // Note: augment return type with preambles in declaration |
399 | code.rawAppendToHeader(what: (method.type == QQmlJSMetaMethodType::StaticMethod |
400 | ? u"static " + functionReturnType(m: method) |
401 | : functionReturnType(m: method)) |
402 | + u" " + hSignature + u";" ); |
403 | |
404 | // do not generate method implementation if it is a signal |
405 | const auto methodType = method.type; |
406 | if (methodType != QQmlJSMetaMethodType::Signal) { |
407 | code.rawAppendToCpp(what: u""_s ); // blank line |
408 | if (method.comments.size() > 0) { |
409 | code.rawAppendToCpp(what: u"/*! \\internal"_s ); |
410 | for (const auto & : method.comments) |
411 | code.rawAppendToCpp(what: comment, extraIndent: 1); |
412 | code.rawAppendToCpp(what: u"*/"_s ); |
413 | } |
414 | code.rawAppendToCpp(what: method.returnType); |
415 | code.rawAppendSignatureToCpp(what: cppSignature); |
416 | code.rawAppendToCpp(what: u"{" ); |
417 | { |
418 | QmltcOutputWrapper::CppIndentationScope cppIndent(&code); |
419 | Q_UNUSED(cppIndent); |
420 | for (const QString &line : std::as_const(t: method.body)) |
421 | code.rawAppendToCpp(what: line); |
422 | } |
423 | code.rawAppendToCpp(what: u"}" ); |
424 | } |
425 | } |
426 | |
427 | template<typename WriteInitialization> |
428 | static void writeSpecialMethod(QmltcOutputWrapper &code, const QmltcMethodBase &specialMethod, |
429 | WriteInitialization writeInit) |
430 | { |
431 | const auto [hSignature, cppSignature] = functionSignatures(method: specialMethod); |
432 | code.rawAppendToHeader(what: hSignature + u";" ); |
433 | |
434 | code.rawAppendToCpp(what: u"" ); // blank line |
435 | code.rawAppendSignatureToCpp(what: cppSignature); |
436 | |
437 | writeInit(specialMethod); |
438 | |
439 | code.rawAppendToCpp(what: u"{" ); |
440 | { |
441 | QmltcOutputWrapper::CppIndentationScope cppIndent(&code); |
442 | Q_UNUSED(cppIndent); |
443 | for (const QString &line : std::as_const(t: specialMethod.body)) |
444 | code.rawAppendToCpp(what: line); |
445 | } |
446 | code.rawAppendToCpp(what: u"}" ); |
447 | } |
448 | |
449 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcCtor &ctor) |
450 | { |
451 | const auto writeInitializerList = [&](const QmltcMethodBase &ctorBase) { |
452 | auto ctor = static_cast<const QmltcCtor &>(ctorBase); |
453 | if (!ctor.initializerList.isEmpty()) { |
454 | code.rawAppendToCpp(what: u":" , extraIndent: 1); |
455 | // double \n to make separate initializer list lines stand out more |
456 | code.rawAppendToCpp( |
457 | what: ctor.initializerList.join(sep: u",\n\n" + u" "_s .repeated(times: code.cppIndent + 1)), |
458 | extraIndent: 1); |
459 | } |
460 | }; |
461 | |
462 | writeSpecialMethod(code, specialMethod: ctor, writeInit: writeInitializerList); |
463 | } |
464 | |
465 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcDtor &dtor) |
466 | { |
467 | const auto noop = [](const QmltcMethodBase &) {}; |
468 | writeSpecialMethod(code, specialMethod: dtor, writeInit: noop); |
469 | } |
470 | |
471 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcVariable &var) |
472 | { |
473 | const QString optionalPart = var.defaultValue.isEmpty() ? u""_s : u" = " + var.defaultValue; |
474 | code.rawAppendToHeader(what: var.cppType + u" " + var.name + optionalPart + u";" ); |
475 | } |
476 | |
477 | void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProperty &prop) |
478 | { |
479 | Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet (or at all?) |
480 | code.rawAppendToHeader(what: u"Q_OBJECT_BINDABLE_PROPERTY(%1, %2, %3, &%1::%4)"_s .arg( |
481 | args: prop.containingClass, args: prop.cppType, args: prop.name, args: prop.signalName)); |
482 | } |
483 | |
484 | void QmltcCodeWriter::writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlMethod) |
485 | { |
486 | // unlike ordinary methods, url function only exists in .cpp |
487 | Q_ASSERT(!urlMethod.returnType.isEmpty()); |
488 | const auto [hSignature, _] = functionSignatures(method: urlMethod); |
489 | Q_UNUSED(_); |
490 | // Note: augment return type with preambles in declaration |
491 | code.rawAppendToCpp(what: functionReturnType(m: urlMethod) + u" " + hSignature); |
492 | code.rawAppendToCpp(what: u"{" ); |
493 | { |
494 | QmltcOutputWrapper::CppIndentationScope cppIndent(&code); |
495 | Q_UNUSED(cppIndent); |
496 | for (const QString &line : std::as_const(t: urlMethod.body)) |
497 | code.rawAppendToCpp(what: line); |
498 | } |
499 | code.rawAppendToCpp(what: u"}" ); |
500 | } |
501 | |
502 | QT_END_NAMESPACE |
503 | |