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
14QT_BEGIN_NAMESPACE
15
16using namespace Qt::StringLiterals;
17
18static QString urlToMacro(const QString &url)
19{
20 QFileInfo fi(url);
21 return u"Q_QMLTC_" + fi.baseName().toUpper();
22}
23
24static 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
41static 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
58static QString appendSpace(const QString &s)
59{
60 if (s.isEmpty())
61 return s;
62 return s + u" ";
63}
64
65static QString prependSpace(const QString &s)
66{
67 if (s.isEmpty())
68 return s;
69 return u" " + s;
70}
71
72static std::pair<QString, QString> functionSignatures(const QmltcMethodBase &method)
73{
74 const QString name = method.name;
75 const QList<QmltcVariable> &parameterList = method.parameterList;
76
77 QStringList headerParamList;
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 headerSignature = 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
94static QString functionReturnType(const QmltcMethod &m)
95{
96 return appendSpace(s: m.declarationPrefixes.join(sep: u" "_s)) + m.returnType;
97}
98
99void QmltcCodeWriter::writeGlobalHeader(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 headerMacro = 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 <QtCore/qxpfunctional.h>");
122 code.rawAppendToHeader(what: u"#include <QtQml/qqmlengine.h>");
123 code.rawAppendToHeader(what: u"#include <QtCore/qurl.h>"); // used in engine execution
124 code.rawAppendToHeader(what: u"#include <QtQml/qqml.h>"); // used for attached properties
125
126 code.rawAppendToHeader(what: u"#include <private/qqmlengine_p.h>"); // executeRuntimeFunction(), etc.
127 code.rawAppendToHeader(what: u"#include <private/qqmltcobjectcreationhelper_p.h>"); // QmltcSupportLib
128
129 code.rawAppendToHeader(what: u"#include <QtQml/qqmllist.h>"); // QQmlListProperty
130
131 // include custom C++ includes required by used types
132 code.rawAppendToHeader(what: u"// BEGIN(custom_cpp_includes)");
133 for (const auto &requiredInclude : requiredCppIncludes)
134 code.rawAppendToHeader(what: u"#include \"" + requiredInclude + u"\"");
135 code.rawAppendToHeader(what: u"// END(custom_cpp_includes)");
136
137 code.rawAppendToCpp(what: u"#include \"" + hPath + u"\""); // include own .h file
138 code.rawAppendToCpp(what: u"// qmltc support library:");
139 code.rawAppendToCpp(what: u"#include <private/qqmlcppbinding_p.h>"); // QmltcSupportLib
140 code.rawAppendToCpp(what: u"#include <private/qqmlcpponassignment_p.h>"); // QmltcSupportLib
141 code.rawAppendToHeader(what: u"#include <private/qqmlcpptypehelpers_p.h> "); // QmltcSupportLib
142
143 code.rawAppendToCpp(what: u"#include <private/qqmlobjectcreator_p.h>"); // createComponent()
144 code.rawAppendToCpp(what: u"#include <private/qqmlcomponent_p.h>"); // QQmlComponentPrivate::get()
145
146 code.rawAppendToCpp(what: u"");
147 code.rawAppendToCpp(what: u"#include <private/qobject_p.h>"); // NB: for private properties
148 code.rawAppendToCpp(what: u"#include <private/qqmlobjectcreator_p.h>"); // for finalize callbacks
149 code.rawAppendToCpp(what: u"#include <QtQml/qqmlprivate.h>"); // QQmlPrivate::qmlExtendedObject()
150
151 code.rawAppendToCpp(what: u""); // blank line
152 code.rawAppendToCpp(what: u"QT_USE_NAMESPACE // avoid issues with QT_NAMESPACE");
153
154 code.rawAppendToHeader(what: u""); // blank line
155
156 const QStringList namespaces = outNamespace.split(sep: u"::"_s);
157
158 for (const QString &currentNamespace : namespaces) {
159 code.rawAppendToHeader(what: u"namespace %1 {"_s.arg(a: currentNamespace));
160 code.rawAppendToCpp(what: u"namespace %1 {"_s.arg(a: currentNamespace));
161 }
162}
163
164void QmltcCodeWriter::write(QmltcOutputWrapper &code,
165 const QmltcPropertyInitializer &propertyInitializer,
166 const QmltcType &wrappedType)
167{
168 code.rawAppendToHeader(what: u"class " + propertyInitializer.name + u" {");
169
170 {
171 {
172 [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
173
174 code.rawAppendToHeader(what: u"friend class " + wrappedType.cppType + u";");
175 }
176
177 code.rawAppendToHeader(what: u"public:"_s);
178
179 [[maybe_unused]] QmltcOutputWrapper::MemberNameScope typeScope(&code, propertyInitializer.name);
180 {
181 [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
182
183 write(code, ctor: propertyInitializer.constructor);
184 code.rawAppendToHeader(what: u""); // blank line
185
186 for (const auto &propertySetter : propertyInitializer.propertySetters) {
187 write(code, method: propertySetter);
188 }
189 }
190
191 code.rawAppendToHeader(what: u""); // blank line
192 code.rawAppendToHeader(what: u"private:"_s);
193
194 {
195 [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
196
197 write(code, var: propertyInitializer.component);
198 write(code, var: propertyInitializer.initializedCache);
199 }
200 }
201
202 code.rawAppendToHeader(what: u"};"_s);
203 code.rawAppendToHeader(what: u""); // blank line
204}
205
206void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcRequiredPropertiesBundle &requiredPropertiesBundle)
207{
208 code.rawAppendToHeader(what: u"struct " + requiredPropertiesBundle.name + u" {");
209
210 {
211 [[maybe_unused]] QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
212
213 for (const auto &member : requiredPropertiesBundle.members) {
214 write(code, var: member);
215 }
216 }
217
218 code.rawAppendToHeader(what: u"};"_s);
219 code.rawAppendToHeader(what: u""); // blank line
220}
221
222void QmltcCodeWriter::writeGlobalFooter(QmltcOutputWrapper &code, const QString &sourcePath,
223 const QString &outNamespace)
224{
225 const QStringList namespaces = outNamespace.split(sep: u"::"_s);
226
227 for (auto it = namespaces.crbegin(), end = namespaces.crend(); it != end; it++) {
228 code.rawAppendToCpp(what: u"} // namespace %1"_s.arg(a: *it));
229 code.rawAppendToHeader(what: u"} // namespace %1"_s.arg(a: *it));
230 }
231
232 code.rawAppendToHeader(what: u""); // blank line
233 code.rawAppendToHeader(what: u"#endif // %1_H"_s.arg(a: urlToMacro(url: sourcePath)));
234 code.rawAppendToHeader(what: u""); // blank line
235}
236
237static void writeToFile(const QString &path, const QByteArray &data)
238{
239 // When not using dependency files, changing a single qml invalidates all
240 // qml files and would force the recompilation of everything. To avoid that,
241 // we check if the data is equal to the existing file, if yes, don't touch
242 // it so the build system will not recompile unnecessary things.
243 //
244 // If the build system use dependency file, we should anyway touch the file
245 // so qmltc is not re-run
246 QFileInfo fi(path);
247 if (fi.exists() && fi.size() == data.size()) {
248 QFile oldFile(path);
249 if (oldFile.open(flags: QIODevice::ReadOnly)) {
250 if (oldFile.readAll() == data)
251 return;
252 }
253 }
254 QFile file(path);
255 if (!file.open(flags: QIODevice::WriteOnly))
256 qFatal(msg: "Could not open file %s", qPrintable(path));
257 file.write(data);
258}
259
260void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProgram &program)
261{
262 writeGlobalHeader(code, sourcePath: program.url, hPath: program.hPath, cppPath: program.cppPath, outNamespace: program.outNamespace,
263 requiredCppIncludes: program.includes);
264
265 // url method comes first
266 writeUrl(code, urlMethod: program.urlMethod);
267
268 // forward declare all the types first
269 for (const QmltcType &type : std::as_const(t: program.compiledTypes))
270 code.rawAppendToHeader(what: u"class " + type.cppType + u";");
271 // write all the types and their content
272 for (const QmltcType &type : std::as_const(t: program.compiledTypes))
273 write(code, type, exportMacro: program.exportMacro);
274
275 // add typeCount definitions. after all types have been written down (so
276 // they are now complete types as per C++). practically, this only concerns
277 // document root type
278 for (const QmltcType &type : std::as_const(t: program.compiledTypes)) {
279 if (!type.typeCount)
280 continue;
281 code.rawAppendToHeader(what: u""); // blank line
282 code.rawAppendToHeader(what: u"constexpr %1 %2::%3()"_s.arg(args: type.typeCount->returnType,
283 args: type.cppType, args: type.typeCount->name));
284 code.rawAppendToHeader(what: u"{");
285 for (const QString &line : std::as_const(t: type.typeCount->body))
286 code.rawAppendToHeader(what: line, extraIndent: 1);
287 code.rawAppendToHeader(what: u"}");
288 }
289
290 writeGlobalFooter(code, sourcePath: program.url, outNamespace: program.outNamespace);
291
292 writeToFile(path: program.hPath, data: code.code().header.toUtf8());
293 writeToFile(path: program.cppPath, data: code.code().cpp.toUtf8());
294}
295
296template<typename Predicate>
297static void dumpFunctions(QmltcOutputWrapper &code, const QList<QmltcMethod> &functions,
298 Predicate pred)
299{
300 // functions are _ordered_ by access and kind. ordering is important to
301 // provide consistent output
302 QMap<QString, QList<const QmltcMethod *>> orderedFunctions;
303 for (const auto &function : functions) {
304 if (pred(function))
305 orderedFunctions[getFunctionCategory(method: function)].append(t: std::addressof(r: function));
306 }
307
308 for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) {
309 code.rawAppendToHeader(what: it.key() + u":", extraIndent: -1);
310 for (const QmltcMethod *function : std::as_const(t: it.value()))
311 QmltcCodeWriter::write(code, method: *function);
312 }
313}
314
315void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type,
316 const QString &exportMacro)
317{
318 const auto constructClassString = [&]() {
319 QString str = u"class "_s;
320 if (!exportMacro.isEmpty())
321 str.append(s: exportMacro).append(s: u" "_s);
322 str.append(s: type.cppType);
323 QStringList nonEmptyBaseClasses;
324 nonEmptyBaseClasses.reserve(asize: type.baseClasses.size());
325 std::copy_if(first: type.baseClasses.cbegin(), last: type.baseClasses.cend(),
326 result: std::back_inserter(x&: nonEmptyBaseClasses),
327 pred: [](const QString &entry) { return !entry.isEmpty(); });
328 if (!nonEmptyBaseClasses.isEmpty())
329 str += u" : public " + nonEmptyBaseClasses.join(sep: u", public "_s);
330 return str;
331 };
332
333 code.rawAppendToHeader(what: u""); // blank line
334 code.rawAppendToCpp(what: u""); // blank line
335
336 code.rawAppendToHeader(what: constructClassString());
337 code.rawAppendToHeader(what: u"{");
338 for (const QString &mocLine : std::as_const(t: type.mocCode))
339 code.rawAppendToHeader(what: mocLine, extraIndent: 1);
340
341 QmltcOutputWrapper::MemberNameScope typeScope(&code, type.cppType);
342 Q_UNUSED(typeScope);
343 {
344 QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
345 Q_UNUSED(headerIndent);
346
347 // first, write user-visible code, then everything else. someone might
348 // want to look at the generated code, so let's make an effort when
349 // writing it down
350
351 code.rawAppendToHeader(what: u"/* ----------------- */");
352 code.rawAppendToHeader(what: u"/* External C++ API */");
353 code.rawAppendToHeader(what: u"public:", extraIndent: -1);
354
355 if (!type.propertyInitializer.name.isEmpty())
356 write(code, propertyInitializer: type.propertyInitializer, wrappedType: type);
357
358 if (type.requiredPropertiesBundle)
359 write(code, requiredPropertiesBundle: *type.requiredPropertiesBundle);
360
361 // NB: when non-document root, the externalCtor won't be public - but we
362 // really don't care about the output format of such types
363 if (!type.ignoreInit && type.externalCtor.access == QQmlJSMetaMethod::Public) {
364 // TODO: ignoreInit must be eliminated
365
366 QmltcCodeWriter::write(code, ctor: type.externalCtor);
367 if (type.staticCreate)
368 QmltcCodeWriter::write(code, method: *type.staticCreate);
369 }
370
371 // dtor
372 if (type.dtor)
373 QmltcCodeWriter::write(code, dtor: *type.dtor);
374
375 // enums
376 for (const auto &enumeration : std::as_const(t: type.enums))
377 QmltcCodeWriter::write(code, enumeration);
378
379 // visible functions
380 const auto isUserVisibleFunction = [](const QmltcMethod &function) {
381 return function.userVisible;
382 };
383 dumpFunctions(code, functions: type.functions, pred: isUserVisibleFunction);
384
385 code.rawAppendToHeader(what: u"/* ----------------- */");
386 code.rawAppendToHeader(what: u""); // blank line
387 code.rawAppendToHeader(what: u"/* Internal functionality (do NOT use it!) */");
388
389 // below are the hidden parts of the type
390
391 // (rest of the) ctors
392 if (type.ignoreInit) { // TODO: this branch should be eliminated
393 Q_ASSERT(type.baselineCtor.access == QQmlJSMetaMethod::Public);
394 code.rawAppendToHeader(what: u"public:", extraIndent: -1);
395 QmltcCodeWriter::write(code, ctor: type.baselineCtor);
396 } else {
397 code.rawAppendToHeader(what: u"protected:", extraIndent: -1);
398 if (type.externalCtor.access != QQmlJSMetaMethod::Public) {
399 Q_ASSERT(type.externalCtor.access == QQmlJSMetaMethod::Protected);
400 QmltcCodeWriter::write(code, ctor: type.externalCtor);
401 }
402 QmltcCodeWriter::write(code, ctor: type.baselineCtor);
403 QmltcCodeWriter::write(code, method: type.init);
404 QmltcCodeWriter::write(code, method: type.endInit);
405 QmltcCodeWriter::write(code, method: type.setComplexBindings);
406 QmltcCodeWriter::write(code, method: type.beginClass);
407 QmltcCodeWriter::write(code, method: type.completeComponent);
408 QmltcCodeWriter::write(code, method: type.finalizeComponent);
409 QmltcCodeWriter::write(code, method: type.handleOnCompleted);
410 }
411
412 // children
413 for (const auto &child : std::as_const(t: type.children))
414 QmltcCodeWriter::write(code, type: child, exportMacro);
415
416 // (non-visible) functions
417 dumpFunctions(code, functions: type.functions, pred: std::not_fn(fn: isUserVisibleFunction));
418
419 // variables and properties
420 if (!type.variables.isEmpty() || !type.properties.isEmpty()) {
421 code.rawAppendToHeader(what: u""); // blank line
422 code.rawAppendToHeader(what: u"protected:", extraIndent: -1);
423 }
424 for (const auto &property : std::as_const(t: type.properties))
425 write(code, prop: property);
426 for (const auto &variable : std::as_const(t: type.variables))
427 write(code, var: variable);
428 }
429
430 code.rawAppendToHeader(what: u"private:", extraIndent: -1);
431 for (const QString &otherLine : std::as_const(t: type.otherCode))
432 code.rawAppendToHeader(what: otherLine, extraIndent: 1);
433
434 if (type.typeCount) {
435 // add typeCount declaration, definition is added later
436 code.rawAppendToHeader(what: u""); // blank line
437 code.rawAppendToHeader(what: u"protected:");
438 code.rawAppendToHeader(what: u"constexpr static %1 %2();"_s.arg(args: type.typeCount->returnType,
439 args: type.typeCount->name),
440 extraIndent: 1);
441 }
442
443 code.rawAppendToHeader(what: u"};");
444}
445
446void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcEnum &enumeration)
447{
448 code.rawAppendToHeader(what: u"enum " + enumeration.cppType + u" {");
449 for (qsizetype i = 0; i < enumeration.keys.size(); ++i) {
450 QString str;
451 if (enumeration.values.isEmpty()) {
452 str += enumeration.keys.at(i) + u",";
453 } else {
454 str += enumeration.keys.at(i) + u" = " + enumeration.values.at(i) + u",";
455 }
456 code.rawAppendToHeader(what: str, extraIndent: 1);
457 }
458 code.rawAppendToHeader(what: u"};");
459 code.rawAppendToHeader(what: enumeration.ownMocLine);
460}
461
462void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcMethod &method)
463{
464 const auto [hSignature, cppSignature] = functionSignatures(method);
465 // Note: augment return type with preambles in declaration
466 code.rawAppendToHeader(what: (method.type == QQmlJSMetaMethodType::StaticMethod
467 ? u"static " + functionReturnType(m: method)
468 : functionReturnType(m: method))
469 + u" " + hSignature + u";");
470
471 // do not generate method implementation if it is a signal
472 const auto methodType = method.type;
473 if (methodType != QQmlJSMetaMethodType::Signal) {
474 code.rawAppendToCpp(what: u""_s); // blank line
475 if (method.comments.size() > 0) {
476 code.rawAppendToCpp(what: u"/*! \\internal"_s);
477 for (const auto &comment : method.comments)
478 code.rawAppendToCpp(what: comment, extraIndent: 1);
479 code.rawAppendToCpp(what: u"*/"_s);
480 }
481 code.rawAppendToCpp(what: method.returnType);
482 code.rawAppendSignatureToCpp(what: cppSignature);
483 code.rawAppendToCpp(what: u"{");
484 {
485 QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
486 Q_UNUSED(cppIndent);
487 for (const QString &line : std::as_const(t: method.body))
488 code.rawAppendToCpp(what: line);
489 }
490 code.rawAppendToCpp(what: u"}");
491 }
492}
493
494template<typename WriteInitialization>
495static void writeSpecialMethod(QmltcOutputWrapper &code, const QmltcMethodBase &specialMethod,
496 WriteInitialization writeInit)
497{
498 const auto [hSignature, cppSignature] = functionSignatures(method: specialMethod);
499 code.rawAppendToHeader(what: hSignature + u";");
500
501 code.rawAppendToCpp(what: u""); // blank line
502 code.rawAppendSignatureToCpp(what: cppSignature);
503
504 writeInit(specialMethod);
505
506 code.rawAppendToCpp(what: u"{");
507 {
508 QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
509 Q_UNUSED(cppIndent);
510 for (const QString &line : std::as_const(t: specialMethod.body))
511 code.rawAppendToCpp(what: line);
512 }
513 code.rawAppendToCpp(what: u"}");
514}
515
516void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcCtor &ctor)
517{
518 const auto writeInitializerList = [&](const QmltcMethodBase &ctorBase) {
519 auto ctor = static_cast<const QmltcCtor &>(ctorBase);
520 if (!ctor.initializerList.isEmpty()) {
521 code.rawAppendToCpp(what: u":", extraIndent: 1);
522 // double \n to make separate initializer list lines stand out more
523 code.rawAppendToCpp(
524 what: ctor.initializerList.join(sep: u",\n\n" + u" "_s.repeated(times: code.cppIndent + 1)),
525 extraIndent: 1);
526 }
527 };
528
529 writeSpecialMethod(code, specialMethod: ctor, writeInit: writeInitializerList);
530}
531
532void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcDtor &dtor)
533{
534 const auto noop = [](const QmltcMethodBase &) {};
535 writeSpecialMethod(code, specialMethod: dtor, writeInit: noop);
536}
537
538void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcVariable &var)
539{
540 const QString optionalPart = var.defaultValue.isEmpty() ? u""_s : u" = " + var.defaultValue;
541 code.rawAppendToHeader(what: var.cppType + u" " + var.name + optionalPart + u";");
542}
543
544void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProperty &prop)
545{
546 Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet (or at all?)
547 code.rawAppendToHeader(what: u"Q_OBJECT_BINDABLE_PROPERTY(%1, %2, %3, &%1::%4)"_s.arg(
548 args: prop.containingClass, args: prop.cppType, args: prop.name, args: prop.signalName));
549}
550
551void QmltcCodeWriter::writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlMethod)
552{
553 // unlike ordinary methods, url function only exists in .cpp
554 Q_ASSERT(!urlMethod.returnType.isEmpty());
555 const auto [hSignature, _] = functionSignatures(method: urlMethod);
556 Q_UNUSED(_);
557 // Note: augment return type with preambles in declaration
558 code.rawAppendToCpp(what: functionReturnType(m: urlMethod) + u" " + hSignature);
559 code.rawAppendToCpp(what: u"{");
560 {
561 QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
562 Q_UNUSED(cppIndent);
563 for (const QString &line : std::as_const(t: urlMethod.body))
564 code.rawAppendToCpp(what: line);
565 }
566 code.rawAppendToCpp(what: u"}");
567}
568
569QT_END_NAMESPACE
570

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/tools/qmltc/qmltccodewriter.cpp