Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
moc.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
4
5#include "moc.h"
6#include "generator.h"
7#include "qdatetime.h"
8#include "utils.h"
9#include "outputrevision.h"
10#include <QtCore/qfile.h>
11#include <QtCore/qfileinfo.h>
12#include <QtCore/qdir.h>
13#include <QtCore/qjsondocument.h>
14
15// for normalizeTypeInternal
16#include <private/qmetaobject_moc_p.h>
17#include <private/qduplicatetracker_p.h>
18
20
21using namespace Qt::StringLiterals;
22
23// only moc needs this function
25{
26 return ba.size() ? normalizeTypeInternal(ba.constBegin(), ba.constEnd()) : ba;
27}
28
29const QByteArray &Moc::toFullyQualified(const QByteArray &name) const noexcept
30{
31 if (auto it = knownQObjectClasses.find(name); it != knownQObjectClasses.end())
32 return it.value();
33 if (auto it = knownGadgets.find(name); it != knownGadgets.end())
34 return it.value();
35 return name;
36}
37
39{
40 // figure out whether this is a class declaration, or only a
41 // forward or variable declaration.
42 int i = 0;
44 do {
45 token = lookup(i++);
46 if (token == COLON || token == LBRACE)
47 break;
48 if (token == SEMIC || token == RANGLE)
49 return false;
50 } while (token);
51
52 // support attributes like "class [[deprecated]]] name"
54
55 if (!test(IDENTIFIER)) // typedef struct { ... }
56 return false;
58
59 // support "class IDENT name" and "class IDENT(IDENT) name"
60 // also support "class IDENT name (final|sealed|Q_DECL_FINAL)"
61 if (test(LPAREN)) {
62 until(RPAREN);
63 if (!test(IDENTIFIER))
64 return false;
65 name = lexem();
66 } else if (test(IDENTIFIER)) {
67 const QByteArray lex = lexem();
68 if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
69 name = lex;
70 }
71
72 def->qualified += name;
73 while (test(SCOPE)) {
74 def->qualified += lexem();
75 if (test(IDENTIFIER)) {
76 name = lexem();
77 def->qualified += name;
78 }
79 }
80 def->classname = name;
81
82 if (test(IDENTIFIER)) {
83 const QByteArray lex = lexem();
84 if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
85 return false;
86 }
87
88 if (test(COLON)) {
89 do {
90 test(VIRTUAL);
92 if (test(PRIVATE))
94 else if (test(PROTECTED))
96 else
97 test(PUBLIC);
98 test(VIRTUAL);
99 const Type type = parseType();
100 // ignore the 'class Foo : BAR(Baz)' case
101 if (test(LPAREN)) {
102 until(RPAREN);
103 } else {
105 }
106 } while (test(COMMA));
107
108 if (!def->superclassList.isEmpty()
110 // Q_GADGET subclasses are treated as Q_GADGETs
113 }
114 }
115 if (!test(LBRACE))
116 return false;
117 def->begin = index - 1;
118 bool foundRBrace = until(RBRACE);
119 def->end = index;
120 index = def->begin + 1;
121 return foundRBrace;
122}
123
125{
126 Type type;
127 bool hasSignedOrUnsigned = false;
128 bool isVoid = false;
130 for (;;) {
132 switch (next()) {
133 case SIGNED:
134 case UNSIGNED:
135 hasSignedOrUnsigned = true;
137 case CONST:
138 case VOLATILE:
139 type.name += lexem();
140 type.name += ' ';
141 if (lookup(0) == VOLATILE)
142 type.isVolatile = true;
143 continue;
144 case Q_MOC_COMPAT_TOKEN:
145 case Q_INVOKABLE_TOKEN:
146 case Q_SCRIPTABLE_TOKEN:
147 case Q_SIGNALS_TOKEN:
148 case Q_SLOTS_TOKEN:
149 case Q_SIGNAL_TOKEN:
150 case Q_SLOT_TOKEN:
151 type.name += lexem();
152 return type;
153 case NOTOKEN:
154 return type;
155 default:
156 prev();
157 break;
158 }
159 break;
160 }
161
163 test(ENUM) || test(CLASS) || test(STRUCT);
164 for(;;) {
166 switch (next()) {
167 case IDENTIFIER:
168 // void mySlot(unsigned myArg)
169 if (hasSignedOrUnsigned) {
170 prev();
171 break;
172 }
174 case CHAR:
175 case SHORT:
176 case INT:
177 case LONG:
178 type.name += lexem();
179 // preserve '[unsigned] long long', 'short int', 'long int', 'long double'
180 if (test(LONG) || test(INT) || test(DOUBLE)) {
181 type.name += ' ';
182 prev();
183 continue;
184 }
185 break;
186 case FLOAT:
187 case DOUBLE:
188 case VOID:
189 case BOOL:
190 case AUTO:
191 type.name += lexem();
192 isVoid |= (lookup(0) == VOID);
193 break;
194 case NOTOKEN:
195 return type;
196 default:
197 prev();
198 ;
199 }
200 if (test(LANGLE)) {
201 if (type.name.isEmpty()) {
202 // '<' cannot start a type
203 return type;
204 }
205 type.name += lexemUntil(RANGLE);
206 }
207 if (test(SCOPE)) {
208 type.name += lexem();
209 type.isScoped = true;
210 } else {
211 break;
212 }
213 }
214 while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
215 || test(STAR) || test(AND) || test(ANDAND)) {
216 type.name += ' ';
217 type.name += lexem();
218 if (lookup(0) == AND)
219 type.referenceType = Type::Reference;
220 else if (lookup(0) == ANDAND)
221 type.referenceType = Type::RValueReference;
222 else if (lookup(0) == STAR)
223 type.referenceType = Type::Pointer;
224 }
225 type.rawName = type.name;
226 // transform stupid things like 'const void' or 'void const' into 'void'
227 if (isVoid && type.referenceType == Type::NoReference) {
228 type.name = "void";
229 }
230 return type;
231}
232
233enum class IncludeState {
236 NoInclude,
237};
238
240{
241 bool isTypdefEnum = false; // typedef enum { ... } Foo;
242
243 if (test(CLASS) || test(STRUCT))
244 def->isEnumClass = true;
245
246 if (test(IDENTIFIER)) {
247 def->name = lexem();
248 } else {
249 if (lookup(-1) != TYPEDEF)
250 return false; // anonymous enum
251 isTypdefEnum = true;
252 }
253 if (test(COLON)) { // C++11 strongly typed enum
254 // enum Foo : unsigned long { ... };
256 }
257 if (!test(LBRACE))
258 return false;
259 auto handleInclude = [this]() -> IncludeState {
260 bool hadIncludeBegin = false;
261 if (test(MOC_INCLUDE_BEGIN)) {
263 // we do not return early to handle empty headers in one go
264 hadIncludeBegin = true;
265 }
266 if (test(NOTOKEN)) {
267 next(MOC_INCLUDE_END);
268 currentFilenames.pop();
270 }
271 if (hadIncludeBegin)
273 else
275 };
276 do {
277 handleInclude();
278 if (lookup() == RBRACE) // accept trailing comma
279 break;
280 next(IDENTIFIER);
281 def->values += lexem();
282 handleInclude();
284 } while (test(EQ) ? until(COMMA) : test(COMMA));
285 next(RBRACE);
286 if (isTypdefEnum) {
287 if (!test(IDENTIFIER))
288 return false;
289 def->name = lexem();
290 }
291 return true;
292}
293
295{
296 Q_UNUSED(def);
297 while (hasNext()) {
299 arg.type = parseType();
300 if (arg.type.name == "void")
301 break;
302 if (test(IDENTIFIER))
303 arg.name = lexem();
304 while (test(LBRACK)) {
305 arg.rightType += lexemUntil(RBRACK);
306 }
307 if (test(CONST) || test(VOLATILE)) {
308 arg.rightType += ' ';
309 arg.rightType += lexem();
310 }
311 arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType));
312 arg.typeNameForCast = QByteArray("std::add_pointer_t<"+arg.normalizedType+">");
313 if (test(EQ))
314 arg.isDefault = true;
315 def->arguments += arg;
316 if (!until(COMMA))
317 break;
318 }
319
320 if (!def->arguments.isEmpty()
321 && def->arguments.constLast().normalizedType == "QPrivateSignal") {
322 def->arguments.removeLast();
323 def->isPrivateSignal = true;
324 }
325 if (def->arguments.size() == 1
326 && def->arguments.constLast().normalizedType == "QMethodRawArguments") {
327 def->arguments.removeLast();
328 def->isRawSlot = true;
329 }
330
331 if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<int>::max()))
332 error("number of function arguments exceeds std::numeric_limits<int>::max()");
333}
334
336{
338 ++index;
339 return true;
340 }
341 return false;
342}
343
345{
346 switch (tok) {
347 case Q_MOC_COMPAT_TOKEN:
348 def->isCompat = true;
349 return true;
350 case Q_INVOKABLE_TOKEN:
351 def->isInvokable = true;
352 return true;
353 case Q_SIGNAL_TOKEN:
354 def->isSignal = true;
355 return true;
356 case Q_SLOT_TOKEN:
357 def->isSlot = true;
358 return true;
359 case Q_SCRIPTABLE_TOKEN:
360 def->isInvokable = def->isScriptable = true;
361 return true;
362 default: break;
363 }
364 return false;
365}
366
368{
369 auto rewind = index;
370 if (test(LBRACK) && test(LBRACK) && until(RBRACK) && test(RBRACK))
371 return true;
372 index = rewind;
373 return false;
374}
375
377{
378 next(LPAREN);
379 QByteArray revisionString = lexemUntil(RPAREN);
380 revisionString.remove(0, 1);
381 revisionString.chop(1);
382 const QList<QByteArray> majorMinor = revisionString.split(',');
383 switch (majorMinor.size()) {
384 case 1: {
385 bool ok = false;
386 const int revision = revisionString.toInt(&ok);
387 if (!ok || !QTypeRevision::isValidSegment(revision))
388 error("Invalid revision");
389 return QTypeRevision::fromMinorVersion(revision);
390 }
391 case 2: { // major.minor
392 bool ok = false;
393 const int major = majorMinor[0].toInt(&ok);
394 if (!ok || !QTypeRevision::isValidSegment(major))
395 error("Invalid major version");
396 const int minor = majorMinor[1].toInt(&ok);
397 if (!ok || !QTypeRevision::isValidSegment(minor))
398 error("Invalid minor version");
399 return QTypeRevision::fromVersion(major, minor);
400 }
401 default:
402 error("Invalid revision");
403 return QTypeRevision();
404 }
405}
406
408{
409
410 if (test(Q_REVISION_TOKEN)) {
412 return true;
413 }
414
415 return false;
416}
417
418// returns false if the function should be ignored
419bool Moc::parseFunction(FunctionDef *def, bool inMacro)
420{
421 def->isVirtual = false;
422 def->isStatic = false;
423 //skip modifiers and attributes
424 while (testForFunctionModifiers(def)
426 bool templateFunction = (lookup() == TEMPLATE);
427 def->type = parseType();
428 if (def->type.name.isEmpty()) {
429 if (templateFunction)
430 error("Template function as signal or slot");
431 else
432 error();
433 }
434 bool scopedFunctionName = false;
435 // we might have modifiers and attributes after a tag
436 // note that testFunctionAttribute is handled further below,
437 // and revisions and attributes must come first
438 while (testForFunctionModifiers(def)) {}
439 Type tempType = parseType();
440 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
442 ; // fine
443 else if (def->type.firstToken == Q_SIGNALS_TOKEN)
444 error();
445 else if (def->type.firstToken == Q_SLOTS_TOKEN)
446 error();
447 else {
448 if (!def->tag.isEmpty())
449 def->tag += ' ';
450 def->tag += def->type.name;
451 }
452 def->type = tempType;
453 tempType = parseType();
454 }
455 next(LPAREN, "Not a signal or slot declaration");
456 def->name = tempType.name;
457 scopedFunctionName = tempType.isScoped;
458
459 if (!test(RPAREN)) {
461 next(RPAREN);
462 }
463
464 // support optional macros with compiler specific options
465 while (test(IDENTIFIER))
466 ;
467
468 def->isConst = test(CONST);
469
470 while (test(IDENTIFIER))
471 ;
472
473 if (inMacro) {
474 next(RPAREN);
475 prev();
476 } else {
477 if (test(THROW)) {
478 next(LPAREN);
479 until(RPAREN);
480 }
481
482 if (def->type.name == "auto" && test(ARROW))
483 def->type = parseType(); // Parse trailing return-type
484
485 if (test(SEMIC))
486 ;
487 else if ((def->inlineCode = test(LBRACE)))
488 until(RBRACE);
489 else if ((def->isAbstract = test(EQ)))
490 until(SEMIC);
491 else if (skipCxxAttributes())
492 until(SEMIC);
493 else
494 error();
495 }
496 if (scopedFunctionName) {
497 const QByteArray msg = "Function declaration " + def->name
498 + " contains extra qualification. Ignoring as signal or slot.";
499 warning(msg.constData());
500 return false;
501 }
502
503 QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(' ');
504 if (typeNameParts.contains("auto")) {
505 // We expected a trailing return type but we haven't seen one
506 error("Function declared with auto as return type but missing trailing return type. "
507 "Return type deduction is not supported.");
508 }
509
510 // we don't support references as return types, it's too dangerous
511 if (def->type.referenceType == Type::Reference) {
512 QByteArray rawName = def->type.rawName;
513 def->type = Type("void");
514 def->type.rawName = rawName;
515 }
516
518 return true;
519}
520
522{
523 return test(EXPLICIT) || test(INLINE) ||
524 (test(STATIC) && (def->isStatic = true)) ||
525 (test(VIRTUAL) && (def->isVirtual = true));
526}
527
528// like parseFunction, but never aborts with an error
530{
531 def->isVirtual = false;
532 def->isStatic = false;
533 //skip modifiers and attributes
534 while (testForFunctionModifiers(def)
536 bool tilde = test(TILDE);
537 def->type = parseType();
538 if (def->type.name.isEmpty())
539 return false;
540 bool scopedFunctionName = false;
541 if (test(LPAREN)) {
542 def->name = def->type.name;
543 scopedFunctionName = def->type.isScoped;
544 if (def->name == cdef->classname) {
545 def->isDestructor = tilde;
546 def->isConstructor = !tilde;
547 def->type = Type();
548 } else {
549 // missing type name? => Skip
550 return false;
551 }
552 } else {
553 // ### TODO: The condition before testForFunctionModifiers shoulnd't be necessary,
554 // but otherwise we end up with misparses
555 if (def->isSlot || def->isSignal || def->isInvokable)
556 while (testForFunctionModifiers(def)) {}
557 Type tempType = parseType();
558 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
560 ; // fine
561 else if (def->type.name == "Q_SIGNAL")
562 def->isSignal = true;
563 else if (def->type.name == "Q_SLOT")
564 def->isSlot = true;
565 else {
566 if (!def->tag.isEmpty())
567 def->tag += ' ';
568 def->tag += def->type.name;
569 }
570 def->type = tempType;
571 tempType = parseType();
572 }
573 if (!test(LPAREN))
574 return false;
575 def->name = tempType.name;
576 scopedFunctionName = tempType.isScoped;
577 }
578
579 // we don't support references as return types, it's too dangerous
580 if (def->type.referenceType == Type::Reference) {
581 QByteArray rawName = def->type.rawName;
582 def->type = Type("void");
583 def->type.rawName = rawName;
584 }
585
587
588 if (!test(RPAREN)) {
590 if (!test(RPAREN))
591 return false;
592 }
593 def->isConst = test(CONST);
594 if (scopedFunctionName
595 && (def->isSignal || def->isSlot || def->isInvokable)) {
596 const QByteArray msg = "parsemaybe: Function declaration " + def->name
597 + " contains extra qualification. Ignoring as signal or slot.";
598 warning(msg.constData());
599 return false;
600 }
601 return true;
602}
603
604inline void handleDefaultArguments(QList<FunctionDef> *functionList, FunctionDef &function)
605{
606 // support a function with a default argument by pretending there is an
607 // overload without the argument (the original function is the overload with
608 // all arguments present)
609 while (function.arguments.size() > 0 && function.arguments.constLast().isDefault) {
610 function.wasCloned = true;
611 function.arguments.removeLast();
612 *functionList += function;
613 }
614}
615
616void Moc::prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const
617{
618 auto it = namespaceList.crbegin();
619 const auto rend = namespaceList.crend();
620 for (; it != rend; ++it) {
621 if (inNamespace(&*it))
622 def.qualified.prepend(it->classname + "::");
623 }
624}
625
627{
628 if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<int>::max()))
629 error("number of signals defined in parent class(es) exceeds "
630 "std::numeric_limits<int>::max().");
631
632 if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<int>::max()))
633 error("number of bindable properties exceeds std::numeric_limits<int>::max().");
634
635 if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<int>::max()))
636 error("number of times Q_CLASSINFO macro is used exceeds "
637 "std::numeric_limits<int>::max().");
638
639 if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<int>::max()))
640 error("number of enumerations exceeds std::numeric_limits<int>::max().");
641
642 if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<int>::max()))
643 error("number of super classes exceeds std::numeric_limits<int>::max().");
644
645 if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<int>::max()))
646 error("number of constructor parameters exceeds std::numeric_limits<int>::max().");
647
648 if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<int>::max()))
649 error("number of signals exceeds std::numeric_limits<int>::max().");
650
651 if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<int>::max()))
652 error("number of declared slots exceeds std::numeric_limits<int>::max().");
653
654 if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<int>::max()))
655 error("number of methods exceeds std::numeric_limits<int>::max().");
656
657 if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<int>::max()))
658 error("number of public functions declared in this class exceeds "
659 "std::numeric_limits<int>::max().");
660}
661
663{
664 QList<NamespaceDef> namespaceList;
665 bool templateClass = false;
666 while (hasNext()) {
667 Token t = next();
668 switch (t) {
669 case NAMESPACE: {
670 qsizetype rewind = index;
671 if (test(IDENTIFIER)) {
672 QByteArray nsName = lexem();
673 QByteArrayList nested;
674 while (test(SCOPE)) {
675 /* treat (C++20's) namespace A::inline B {} as A::B
676 this is mostly to not break compilation when encountering such
677 a construct in a header; the interaction of Qt's meta-macros with
678 inline namespaces is still rather poor.
679 */
680 test(INLINE);
681 next(IDENTIFIER);
682 nested.append(nsName);
683 nsName = lexem();
684 }
685 if (test(EQ)) {
686 // namespace Foo = Bar::Baz;
687 until(SEMIC);
688 } else if (test(LPAREN)) {
689 // Ignore invalid code such as: 'namespace __identifier("x")' (QTBUG-56634)
690 until(RPAREN);
691 } else if (!test(SEMIC)) {
692 NamespaceDef def;
693 def.classname = nsName;
694 def.doGenerate = currentFilenames.size() <= 1;
695
696 next(LBRACE);
697 def.begin = index - 1;
698 until(RBRACE);
699 def.end = index;
700 index = def.begin + 1;
701
702 prependNamespaces(def, namespaceList);
703
704 for (const QByteArray &ns : nested) {
705 NamespaceDef parentNs;
706 parentNs.classname = ns;
707 parentNs.qualified = def.qualified;
708 def.qualified += ns + "::";
709 parentNs.begin = def.begin;
710 parentNs.end = def.end;
711 namespaceList += parentNs;
712 }
713
714 while (inNamespace(&def) && hasNext()) {
715 switch (next()) {
716 case NAMESPACE:
717 if (test(IDENTIFIER)) {
718 while (test(SCOPE)) {
719 test(INLINE); // ignore inline namespaces
720 next(IDENTIFIER);
721 }
722 if (test(EQ)) {
723 // namespace Foo = Bar::Baz;
724 until(SEMIC);
725 } else if (!test(SEMIC)) {
726 until(RBRACE);
727 }
728 }
729 break;
730 case Q_NAMESPACE_TOKEN:
731 def.hasQNamespace = true;
732 break;
733 case Q_NAMESPACE_EXPORT_TOKEN:
734 next(LPAREN);
735 while (test(IDENTIFIER))
736 {}
737 next(RPAREN);
738 def.hasQNamespace = true;
739 break;
740 case Q_ENUMS_TOKEN:
741 case Q_ENUM_NS_TOKEN:
742 parseEnumOrFlag(&def, false);
743 break;
744 case Q_ENUM_TOKEN:
745 error("Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
746 break;
747 case Q_FLAGS_TOKEN:
748 case Q_FLAG_NS_TOKEN:
749 parseEnumOrFlag(&def, true);
750 break;
751 case Q_FLAG_TOKEN:
752 error("Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
753 break;
754 case Q_DECLARE_FLAGS_TOKEN:
755 parseFlag(&def);
756 break;
757 case Q_CLASSINFO_TOKEN:
758 parseClassInfo(&def);
759 break;
760 case Q_MOC_INCLUDE_TOKEN:
761 // skip it, the namespace is parsed twice
762 next(LPAREN);
763 lexemUntil(RPAREN);
764 break;
765 case ENUM: {
766 EnumDef enumDef;
767 if (parseEnum(&enumDef))
768 def.enumList += enumDef;
769 } break;
770 case CLASS:
771 case STRUCT: {
772 ClassDef classdef;
773 if (!parseClassHead(&classdef))
774 continue;
775 while (inClass(&classdef) && hasNext())
776 next(); // consume all Q_XXXX macros from this class
777 } break;
778 default: break;
779 }
780 }
781 namespaceList += def;
782 index = rewind;
783 if (!def.hasQNamespace && (!def.classInfoList.isEmpty() || !def.enumDeclarations.isEmpty()))
784 error("Namespace declaration lacks Q_NAMESPACE macro.");
785 }
786 }
787 break;
788 }
789 case SEMIC:
790 case RBRACE:
791 templateClass = false;
792 break;
793 case TEMPLATE:
794 templateClass = true;
795 break;
796 case MOC_INCLUDE_BEGIN:
798 break;
799 case MOC_INCLUDE_END:
800 currentFilenames.pop();
801 break;
802 case Q_DECLARE_INTERFACE_TOKEN:
804 break;
805 case Q_DECLARE_METATYPE_TOKEN:
807 break;
808 case Q_MOC_INCLUDE_TOKEN:
810 break;
811 case USING:
812 if (test(NAMESPACE)) {
813 while (test(SCOPE) || test(IDENTIFIER))
814 ;
815 // Ignore invalid code such as: 'using namespace __identifier("x")' (QTBUG-63772)
816 if (test(LPAREN))
817 until(RPAREN);
818 next(SEMIC);
819 }
820 break;
821 case CLASS:
822 case STRUCT: {
823 if (currentFilenames.size() <= 1)
824 break;
825
826 ClassDef def;
827 if (!parseClassHead(&def))
828 continue;
829
830 while (inClass(&def) && hasNext()) {
831 switch (next()) {
832 case Q_OBJECT_TOKEN:
833 def.hasQObject = true;
834 break;
835 case Q_GADGET_EXPORT_TOKEN:
836 next(LPAREN);
837 while (test(IDENTIFIER))
838 {}
839 next(RPAREN);
841 case Q_GADGET_TOKEN:
842 def.hasQGadget = true;
843 break;
844 default: break;
845 }
846 }
847
848 if (!def.hasQObject && !def.hasQGadget)
849 continue;
850
851 prependNamespaces(def, namespaceList);
852
853 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
854 classHash.insert(def.classname, def.qualified);
855 classHash.insert(def.qualified, def.qualified);
856
857 continue; }
858 default: break;
859 }
860 if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
861 continue;
862 ClassDef def;
863 if (parseClassHead(&def)) {
864 prependNamespaces(def, namespaceList);
865
867 while (inClass(&def) && hasNext()) {
868 switch ((t = next())) {
869 case PRIVATE:
871 if (test(Q_SIGNALS_TOKEN))
872 error("Signals cannot have access specifier");
873 break;
874 case PROTECTED:
876 if (test(Q_SIGNALS_TOKEN))
877 error("Signals cannot have access specifier");
878 break;
879 case PUBLIC:
881 if (test(Q_SIGNALS_TOKEN))
882 error("Signals cannot have access specifier");
883 break;
884 case CLASS: {
885 ClassDef nestedDef;
886 if (parseClassHead(&nestedDef)) {
887 while (inClass(&nestedDef) && inClass(&def)) {
888 t = next();
890 error("Meta object features not supported for nested classes");
891 }
892 }
893 } break;
894 case Q_SIGNALS_TOKEN:
895 parseSignals(&def);
896 break;
897 case Q_SLOTS_TOKEN:
898 switch (lookup(-1)) {
899 case PUBLIC:
900 case PROTECTED:
901 case PRIVATE:
902 parseSlots(&def, access);
903 break;
904 default:
905 error("Missing access specifier for slots");
906 }
907 break;
908 case Q_OBJECT_TOKEN:
909 def.hasQObject = true;
910 if (templateClass)
911 error("Template classes not supported by Q_OBJECT");
912 if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
913 error("Class contains Q_OBJECT macro but does not inherit from QObject");
914 break;
915 case Q_GADGET_EXPORT_TOKEN:
916 next(LPAREN);
917 while (test(IDENTIFIER))
918 {}
919 next(RPAREN);
921 case Q_GADGET_TOKEN:
922 def.hasQGadget = true;
923 if (templateClass)
924 error("Template classes not supported by Q_GADGET");
925 break;
926 case Q_PROPERTY_TOKEN:
927 parseProperty(&def, Named);
928 break;
929 case QT_ANONYMOUS_PROPERTY_TOKEN:
931 break;
932 case Q_PLUGIN_METADATA_TOKEN:
933 parsePluginData(&def);
934 break;
935 case Q_ENUMS_TOKEN:
936 case Q_ENUM_TOKEN:
937 parseEnumOrFlag(&def, false);
938 break;
939 case Q_ENUM_NS_TOKEN:
940 error("Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
941 break;
942 case Q_FLAGS_TOKEN:
943 case Q_FLAG_TOKEN:
944 parseEnumOrFlag(&def, true);
945 break;
946 case Q_FLAG_NS_TOKEN:
947 error("Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
948 break;
949 case Q_DECLARE_FLAGS_TOKEN:
950 parseFlag(&def);
951 break;
952 case Q_CLASSINFO_TOKEN:
953 parseClassInfo(&def);
954 break;
955 case Q_MOC_INCLUDE_TOKEN:
957 break;
958 case Q_INTERFACES_TOKEN:
959 parseInterfaces(&def);
960 break;
961 case Q_PRIVATE_SLOT_TOKEN:
963 break;
964 case Q_PRIVATE_PROPERTY_TOKEN:
966 break;
967 case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
969 break;
970 case ENUM: {
971 EnumDef enumDef;
972 if (parseEnum(&enumDef))
973 def.enumList += enumDef;
974 } break;
975 case SEMIC:
976 case COLON:
977 break;
978 default:
979 FunctionDef funcDef;
980 funcDef.access = access;
981 qsizetype rewind = index--;
982 if (parseMaybeFunction(&def, &funcDef)) {
983 if (funcDef.isConstructor) {
984 if ((access == FunctionDef::Public) && funcDef.isInvokable) {
985 def.constructorList += funcDef;
987 }
988 } else if (funcDef.isDestructor) {
989 // don't care about destructors
990 } else {
992 def.publicList += funcDef;
993 if (funcDef.isSlot) {
994 def.slotList += funcDef;
995 handleDefaultArguments(&def.slotList, funcDef);
996 if (funcDef.revision > 0)
997 ++def.revisionedMethods;
998 } else if (funcDef.isSignal) {
999 def.signalList += funcDef;
1000 handleDefaultArguments(&def.signalList, funcDef);
1001 if (funcDef.revision > 0)
1002 ++def.revisionedMethods;
1003 } else if (funcDef.isInvokable) {
1004 def.methodList += funcDef;
1005 handleDefaultArguments(&def.methodList, funcDef);
1006 if (funcDef.revision > 0)
1007 ++def.revisionedMethods;
1008 }
1009 }
1010 } else {
1011 index = rewind;
1012 }
1013 }
1014 }
1015
1016 next(RBRACE);
1017
1018 if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()
1019 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
1020 continue; // no meta object code required
1021
1022
1023 if (!def.hasQObject && !def.hasQGadget)
1024 error("Class declaration lacks Q_OBJECT macro.");
1025
1026 // Add meta tags to the plugin meta data:
1027 if (!def.pluginData.iid.isEmpty())
1028 def.pluginData.metaArgs = metaArgs;
1029
1030 if (def.hasQObject && !def.superclassList.isEmpty())
1031 checkSuperClasses(&def);
1032
1033 checkProperties(&def);
1034
1035 checkListSizes(def);
1036
1037 classList += def;
1038 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
1039 classHash.insert(def.classname, def.qualified);
1040 classHash.insert(def.qualified, def.qualified);
1041 }
1042 }
1043 for (const auto &n : std::as_const(namespaceList)) {
1044 if (!n.hasQNamespace)
1045 continue;
1046 ClassDef def;
1047 static_cast<BaseDef &>(def) = static_cast<BaseDef>(n);
1048 def.qualified += def.classname;
1049 def.hasQNamespace = true;
1050 auto it = std::find_if(classList.begin(), classList.end(), [&def](const ClassDef &val) {
1051 return def.classname == val.classname && def.qualified == val.qualified;
1052 });
1053
1054 if (it != classList.end()) {
1055 it->classInfoList += def.classInfoList;
1056 Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<int>::max());
1057 it->enumDeclarations.insert(def.enumDeclarations);
1058 it->enumList += def.enumList;
1059 Q_ASSERT(it->enumList.size() <= std::numeric_limits<int>::max());
1060 it->flagAliases.insert(def.flagAliases);
1061 } else {
1064 if (n.doGenerate)
1065 classList += def;
1066 }
1067 }
1068}
1069
1070static bool any_type_contains(const QList<PropertyDef> &properties, const QByteArray &pattern)
1071{
1072 for (const auto &p : properties) {
1073 if (p.type.contains(pattern))
1074 return true;
1075 }
1076 return false;
1077}
1078
1079static bool any_arg_contains(const QList<FunctionDef> &functions, const QByteArray &pattern)
1080{
1081 for (const auto &f : functions) {
1082 for (const auto &arg : f.arguments) {
1083 if (arg.normalizedType.contains(pattern))
1084 return true;
1085 }
1086 }
1087 return false;
1088}
1089
1091{
1093 result
1094#define STREAM_SMART_POINTER(SMART_POINTER) << #SMART_POINTER
1096#undef STREAM_SMART_POINTER
1097#define STREAM_1ARG_TEMPLATE(TEMPLATENAME) << #TEMPLATENAME
1099#undef STREAM_1ARG_TEMPLATE
1100 ;
1101 return result;
1102}
1103
1104static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
1105{
1106 static const QByteArrayList candidates = make_candidates();
1107
1108 QByteArrayList required;
1109 required.reserve(candidates.size());
1110
1111 bool needsQProperty = false;
1112
1113 for (const auto &candidate : candidates) {
1114 const QByteArray pattern = candidate + '<';
1115
1116 for (const auto &c : classes) {
1117 for (const auto &p : c.propertyList)
1118 needsQProperty |= !p.bind.isEmpty();
1119 if (any_type_contains(c.propertyList, pattern) ||
1120 any_arg_contains(c.slotList, pattern) ||
1121 any_arg_contains(c.signalList, pattern) ||
1122 any_arg_contains(c.methodList, pattern)) {
1123 required.push_back(candidate);
1124 break;
1125 }
1126 }
1127 }
1128
1129 if (needsQProperty)
1130 required.push_back("QProperty");
1131
1132 return required;
1133}
1134
1135void Moc::generate(FILE *out, FILE *jsonOutput)
1136{
1138
1139 auto isSlash = [](char ch) { return ch == '/' || ch == '\\'; };
1140 auto rit = std::find_if(fn.crbegin(), fn.crend(), isSlash);
1141 if (rit != fn.crend())
1142 fn = fn.last(rit - fn.crbegin());
1143
1144 fprintf(out, "/****************************************************************************\n"
1145 "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
1146 fprintf(out, "** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
1147 fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
1148 "*****************************************************************************/\n\n");
1149
1150 // include header(s) of user class definitions at _first_ to allow
1151 // for preprocessor definitions possibly affecting standard headers.
1152 // see https://codereview.qt-project.org/c/qt/qtbase/+/445937
1153 if (!noInclude) {
1154 if (includePath.size() && !includePath.endsWith('/'))
1155 includePath += '/';
1156 for (QByteArray inc : std::as_const(includeFiles)) {
1157 if (!inc.isEmpty() && inc.at(0) != '<' && inc.at(0) != '"') {
1158 if (includePath.size() && includePath != "./")
1159 inc.prepend(includePath);
1160 inc = '\"' + inc + '\"';
1161 }
1162 fprintf(out, "#include %s\n", inc.constData());
1163 }
1164 }
1165 if (classList.size() && classList.constFirst().classname == "Qt")
1166 fprintf(out, "#include <QtCore/qobject.h>\n");
1167
1168 fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
1170 fprintf(out, "#include <QtCore/qplugin.h>\n");
1171
1172 const auto qtContainers = requiredQtContainers(classList);
1173 for (const QByteArray &qtContainer : qtContainers)
1174 fprintf(out, "#include <QtCore/%s>\n", qtContainer.constData());
1175
1176 fprintf(out, "\n#include <QtCore/qtmochelpers.h>\n");
1177
1178 fprintf(out, "\n#include <memory>\n\n"); // For std::addressof
1179 fprintf(out, "\n#include <QtCore/qxptype_traits.h>\n"); // is_detected
1180
1181 fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
1182 "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
1183 fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
1184 fprintf(out, "#error \"This file was generated using the moc from %s."
1185 " It\"\n#error \"cannot be used with the include files from"
1186 " this version of Qt.\"\n#error \"(The moc has changed too"
1187 " much.)\"\n", QT_VERSION_STR);
1188 fprintf(out, "#endif\n\n");
1189
1190#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
1191 fprintf(out, "#ifndef Q_CONSTINIT\n"
1192 "#define Q_CONSTINIT\n"
1193 "#endif\n\n");
1194#endif
1195
1196 fprintf(out, "QT_WARNING_PUSH\n");
1197 fprintf(out, "QT_WARNING_DISABLE_DEPRECATED\n");
1198 fprintf(out, "QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
1199
1200 fputs("", out);
1201 for (ClassDef &def : classList) {
1204 generator.generateCode();
1205
1206 // generator.generateCode() should have already registered all strings
1207 if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<int>::max())) {
1208 error("internal limit exceeded: number of parsed strings is too big.");
1209 exit(EXIT_FAILURE);
1210 }
1211 }
1212 fputs("", out);
1213
1214 fprintf(out, "QT_WARNING_POP\n");
1215
1216 if (jsonOutput) {
1217 QJsonObject mocData;
1218 mocData["outputRevision"_L1] = mocOutputRevision;
1219 mocData["inputFile"_L1] = QLatin1StringView(fn.constData());
1220
1221 QJsonArray classesJsonFormatted;
1222
1223 for (const ClassDef &cdef: std::as_const(classList))
1224 classesJsonFormatted.append(cdef.toJson());
1225
1226 if (!classesJsonFormatted.isEmpty())
1227 mocData["classes"_L1] = classesJsonFormatted;
1228
1229 QJsonDocument jsonDoc(mocData);
1230 fputs(jsonDoc.toJson().constData(), jsonOutput);
1231 }
1232}
1233
1235{
1236 QTypeRevision defaultRevision;
1237 if (test(Q_REVISION_TOKEN))
1238 defaultRevision = parseRevision();
1239
1240 next(COLON);
1241 while (inClass(def) && hasNext()) {
1242 switch (next()) {
1243 case PUBLIC:
1244 case PROTECTED:
1245 case PRIVATE:
1246 case Q_SIGNALS_TOKEN:
1247 case Q_SLOTS_TOKEN:
1248 prev();
1249 return;
1250 case SEMIC:
1251 continue;
1252 case FRIEND:
1253 until(SEMIC);
1254 continue;
1255 case USING:
1256 error("'using' directive not supported in 'slots' section");
1257 default:
1258 prev();
1259 }
1260
1261 FunctionDef funcDef;
1262 funcDef.access = access;
1263 if (!parseFunction(&funcDef))
1264 continue;
1265 if (funcDef.revision > 0) {
1266 ++def->revisionedMethods;
1267 } else if (defaultRevision.isValid()) {
1268 funcDef.revision = defaultRevision.toEncodedVersion<int>();
1269 ++def->revisionedMethods;
1270 }
1271 def->slotList += funcDef;
1272 handleDefaultArguments(&def->slotList, funcDef);
1273 }
1274}
1275
1277{
1278 QTypeRevision defaultRevision;
1279 if (test(Q_REVISION_TOKEN))
1280 defaultRevision = parseRevision();
1281
1282 next(COLON);
1283 while (inClass(def) && hasNext()) {
1284 switch (next()) {
1285 case PUBLIC:
1286 case PROTECTED:
1287 case PRIVATE:
1288 case Q_SIGNALS_TOKEN:
1289 case Q_SLOTS_TOKEN:
1290 prev();
1291 return;
1292 case SEMIC:
1293 continue;
1294 case FRIEND:
1295 until(SEMIC);
1296 continue;
1297 case USING:
1298 error("'using' directive not supported in 'signals' section");
1299 default:
1300 prev();
1301 }
1302 FunctionDef funcDef;
1303 funcDef.access = FunctionDef::Public;
1304 parseFunction(&funcDef);
1305 if (funcDef.isVirtual)
1306 warning("Signals cannot be declared virtual");
1307 if (funcDef.inlineCode)
1308 error("Not a signal declaration");
1309 if (funcDef.revision > 0) {
1310 ++def->revisionedMethods;
1311 } else if (defaultRevision.isValid()) {
1312 funcDef.revision = defaultRevision.toEncodedVersion<int>();
1313 ++def->revisionedMethods;
1314 }
1315 def->signalList += funcDef;
1316 handleDefaultArguments(&def->signalList, funcDef);
1317 }
1318}
1319
1321{
1322 propDef.location = index;
1323 propDef.relativeIndex = propertyIndex;
1324
1326 if (type.isEmpty())
1327 error();
1328 propDef.designable = propDef.scriptable = propDef.stored = "true";
1329 propDef.user = "false";
1330 /*
1331 The Q_PROPERTY construct cannot contain any commas, since
1332 commas separate macro arguments. We therefore expect users
1333 to type "QMap" instead of "QMap<QString, QVariant>". For
1334 coherence, we also expect the same for
1335 QValueList<QVariant>, the other template class supported by
1336 QVariant.
1337 */
1339 if (type == "QMap")
1340 type = "QMap<QString,QVariant>";
1341 else if (type == "QValueList")
1342 type = "QValueList<QVariant>";
1343 else if (type == "LongLong")
1344 type = "qlonglong";
1345 else if (type == "ULongLong")
1346 type = "qulonglong";
1347
1348 propDef.type = type;
1349
1350 if (mode == Moc::Named) {
1351 next();
1352 propDef.name = lexem();
1353 }
1354
1355 parsePropertyAttributes(propDef);
1356}
1357
1359{
1360 auto checkIsFunction = [&](const QByteArray &def, const char *name) {
1361 if (def.endsWith(')')) {
1362 QByteArray msg = "Providing a function for ";
1363 msg += name;
1364 msg += " in a property declaration is not be supported in Qt 6.";
1365 error(msg.constData());
1366 }
1367 };
1368
1369 while (test(IDENTIFIER)) {
1370 const Symbol &lsym = symbol();
1371 const QByteArray l = lsym.lexem();
1372 if (l[0] == 'C' && l == "CONSTANT") {
1373 propDef.constant = true;
1374 continue;
1375 } else if (l[0] == 'F' && l == "FINAL") {
1376 propDef.final = true;
1377 continue;
1378 } else if (l[0] == 'N' && l == "NAME") {
1379 next(IDENTIFIER);
1380 propDef.name = lexem();
1381 continue;
1382 } else if (l[0] == 'R' && l == "REQUIRED") {
1383 propDef.required = true;
1384 continue;
1385 } else if (l[0] == 'R' && l == "REVISION" && test(LPAREN)) {
1386 prev();
1387 propDef.revision = parseRevision().toEncodedVersion<int>();
1388 continue;
1389 }
1390
1391 QByteArray v, v2;
1392 if (test(LPAREN)) {
1393 v = lexemUntil(RPAREN);
1394 v = v.mid(1, v.size() - 2); // removes the '(' and ')'
1395 } else if (test(INTEGER_LITERAL)) {
1396 v = lexem();
1397 if (l != "REVISION")
1398 error(lsym);
1399 } else if (test(DEFAULT)) {
1400 v = lexem();
1401 if (l != "READ" && l != "WRITE")
1402 error(lsym);
1403 } else {
1404 next(IDENTIFIER);
1405 v = lexem();
1406 if (test(LPAREN))
1407 v2 = lexemUntil(RPAREN);
1408 else if (v != "true" && v != "false")
1409 v2 = "()";
1410 }
1411 switch (l[0]) {
1412 case 'M':
1413 if (l == "MEMBER")
1414 propDef.member = v;
1415 else
1416 error(lsym);
1417 break;
1418 case 'R':
1419 if (l == "READ")
1420 propDef.read = v;
1421 else if (l == "RESET")
1422 propDef.reset = v;
1423 else if (l == "REVISION") {
1424 bool ok = false;
1425 const int minor = v.toInt(&ok);
1426 if (!ok || !QTypeRevision::isValidSegment(minor))
1427 error(lsym);
1428 propDef.revision = QTypeRevision::fromMinorVersion(minor).toEncodedVersion<int>();
1429 } else
1430 error(lsym);
1431 break;
1432 case 'S':
1433 if (l == "SCRIPTABLE") {
1434 propDef.scriptable = v + v2;
1435 checkIsFunction(propDef.scriptable, "SCRIPTABLE");
1436 } else if (l == "STORED") {
1437 propDef.stored = v + v2;
1438 checkIsFunction(propDef.stored, "STORED");
1439 } else
1440 error(lsym);
1441 break;
1442 case 'W': if (l != "WRITE") error(lsym);
1443 propDef.write = v;
1444 break;
1445 case 'B': if (l != "BINDABLE") error(lsym);
1446 propDef.bind = v;
1447 break;
1448 case 'D': if (l != "DESIGNABLE") error(lsym);
1449 propDef.designable = v + v2;
1450 checkIsFunction(propDef.designable, "DESIGNABLE");
1451 break;
1452 case 'N': if (l != "NOTIFY") error(lsym);
1453 propDef.notify = v;
1454 break;
1455 case 'U': if (l != "USER") error(lsym);
1456 propDef.user = v + v2;
1457 checkIsFunction(propDef.user, "USER");
1458 break;
1459 default:
1460 error(lsym);
1461 }
1462 }
1463 if (propDef.constant && !propDef.write.isNull()) {
1464 const QByteArray msg = "Property declaration " + propDef.name
1465 + " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
1466 propDef.constant = false;
1467 warning(msg.constData());
1468 }
1469 if (propDef.constant && !propDef.notify.isNull()) {
1470 const QByteArray msg = "Property declaration " + propDef.name
1471 + " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
1472 propDef.constant = false;
1473 warning(msg.constData());
1474 }
1475 if (propDef.constant && !propDef.bind.isNull()) {
1476 const QByteArray msg = "Property declaration " + propDef.name
1477 + " is both BINDable and CONSTANT. CONSTANT will be ignored.";
1478 propDef.constant = false;
1479 warning(msg.constData());
1480 }
1481 if (propDef.read == "default" && propDef.bind.isNull()) {
1482 const QByteArray msg = "Property declaration " + propDef.name
1483 + " is not BINDable but default-READable. READ will be ignored.";
1484 propDef.read = "";
1485 warning(msg.constData());
1486 }
1487 if (propDef.write == "default" && propDef.bind.isNull()) {
1488 const QByteArray msg = "Property declaration " + propDef.name
1489 + " is not BINDable but default-WRITEable. WRITE will be ignored.";
1490 propDef.write = "";
1491 warning(msg.constData());
1492 }
1493}
1494
1496{
1497 next(LPAREN);
1498 PropertyDef propDef;
1499 createPropertyDef(propDef, int(def->propertyList.size()), mode);
1500 next(RPAREN);
1501
1502 def->propertyList += propDef;
1503}
1504
1506{
1507 next(LPAREN);
1508 QByteArray metaData;
1509 while (test(IDENTIFIER)) {
1510 QByteArray l = lexem();
1511 if (l == "IID") {
1512 next(STRING_LITERAL);
1513 def->pluginData.iid = unquotedLexem();
1514 } else if (l == "URI") {
1515 next(STRING_LITERAL);
1516 def->pluginData.uri = unquotedLexem();
1517 } else if (l == "FILE") {
1518 next(STRING_LITERAL);
1519 QByteArray metaDataFile = unquotedLexem();
1521 QString::fromLocal8Bit(metaDataFile));
1522 for (const IncludePath &p : std::as_const(includes)) {
1523 if (fi.exists())
1524 break;
1525 if (p.isFrameworkPath)
1526 continue;
1527
1528 fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(metaDataFile.constData()));
1529 // try again, maybe there's a file later in the include paths with the same name
1530 if (fi.isDir()) {
1531 fi = QFileInfo();
1532 continue;
1533 }
1534 }
1535 if (!fi.exists()) {
1536 const QByteArray msg = "Plugin Metadata file " + lexem()
1537 + " does not exist. Declaration will be ignored";
1538 error(msg.constData());
1539 return;
1540 }
1541 QFile file(fi.canonicalFilePath());
1542 if (!file.open(QFile::ReadOnly)) {
1543 QByteArray msg = "Plugin Metadata file " + lexem() + " could not be opened: "
1544 + file.errorString().toUtf8();
1545 error(msg.constData());
1546 return;
1547 }
1548 parsedPluginMetadataFiles.append(fi.canonicalFilePath());
1549 metaData = file.readAll();
1550 }
1551 }
1552
1553 if (!metaData.isEmpty()) {
1554 def->pluginData.metaData = QJsonDocument::fromJson(metaData);
1555 if (!def->pluginData.metaData.isObject()) {
1556 const QByteArray msg = "Plugin Metadata file " + lexem()
1557 + " does not contain a valid JSON object. Declaration will be ignored";
1558 warning(msg.constData());
1559 def->pluginData.iid = QByteArray();
1560 def->pluginData.uri = QByteArray();
1561 return;
1562 }
1563 }
1564
1565 mustIncludeQPluginH = true;
1566 next(RPAREN);
1567}
1568
1570{
1571 int nesting = 0;
1572 QByteArray accessor;
1573 while (1) {
1574 Token t = peek();
1575 if (!nesting && (t == RPAREN || t == COMMA))
1576 break;
1577 t = next();
1578 if (t == LPAREN)
1579 ++nesting;
1580 if (t == RPAREN)
1581 --nesting;
1582 accessor += lexem();
1583 }
1584 return accessor;
1585}
1586
1588{
1589 next(LPAREN);
1590 PropertyDef propDef;
1592
1593 next(COMMA);
1594
1595 createPropertyDef(propDef, int(def->propertyList.size()), mode);
1596
1597 def->propertyList += propDef;
1598}
1599
1600void Moc::parseEnumOrFlag(BaseDef *def, bool isFlag)
1601{
1602 next(LPAREN);
1603 QByteArray identifier;
1604 while (test(IDENTIFIER)) {
1605 identifier = lexem();
1606 while (test(SCOPE) && test(IDENTIFIER)) {
1607 identifier += "::";
1608 identifier += lexem();
1609 }
1610 def->enumDeclarations[identifier] = isFlag;
1611 }
1612 next(RPAREN);
1613}
1614
1616{
1617 next(LPAREN);
1618 QByteArray flagName, enumName;
1619 while (test(IDENTIFIER)) {
1620 flagName = lexem();
1621 while (test(SCOPE) && test(IDENTIFIER)) {
1622 flagName += "::";
1623 flagName += lexem();
1624 }
1625 }
1626 next(COMMA);
1627 while (test(IDENTIFIER)) {
1628 enumName = lexem();
1629 while (test(SCOPE) && test(IDENTIFIER)) {
1630 enumName += "::";
1631 enumName += lexem();
1632 }
1633 }
1634
1635 def->flagAliases.insert(enumName, flagName);
1636 next(RPAREN);
1637}
1638
1640{
1641 bool encounteredQmlMacro = false;
1642 next(LPAREN);
1643 ClassInfoDef infoDef;
1644 next(STRING_LITERAL);
1645 infoDef.name = symbol().unquotedLexem();
1646 if (infoDef.name.startsWith("QML."))
1647 encounteredQmlMacro = true;
1648 next(COMMA);
1649 if (test(STRING_LITERAL)) {
1650 infoDef.value = symbol().unquotedLexem();
1651 } else if (test(Q_REVISION_TOKEN)) {
1652 infoDef.value = QByteArray::number(parseRevision().toEncodedVersion<quint16>());
1653 } else {
1654 // support Q_CLASSINFO("help", QT_TR_NOOP("blah"))
1655 next(IDENTIFIER);
1656 next(LPAREN);
1657 next(STRING_LITERAL);
1658 infoDef.value = symbol().unquotedLexem();
1659 next(RPAREN);
1660 }
1661 next(RPAREN);
1662 def->classInfoList += infoDef;
1663 return encounteredQmlMacro ? EncounteredQmlMacro::Yes : EncounteredQmlMacro::No;
1664}
1665
1667{
1668 if (parseClassInfo(static_cast<BaseDef *>(def)) == EncounteredQmlMacro::Yes)
1669 def->requireCompleteMethodTypes = true;
1670}
1671
1673{
1674 next(LPAREN);
1675 while (test(IDENTIFIER)) {
1676 QList<ClassDef::Interface> iface;
1677 iface += ClassDef::Interface(lexem());
1678 while (test(SCOPE)) {
1679 iface.last().className += lexem();
1680 next(IDENTIFIER);
1681 iface.last().className += lexem();
1682 }
1683 while (test(COLON)) {
1684 next(IDENTIFIER);
1685 iface += ClassDef::Interface(lexem());
1686 while (test(SCOPE)) {
1687 iface.last().className += lexem();
1688 next(IDENTIFIER);
1689 iface.last().className += lexem();
1690 }
1691 }
1692 // resolve from classnames to interface ids
1693 for (qsizetype i = 0; i < iface.size(); ++i) {
1694 const QByteArray iid = interface2IdMap.value(iface.at(i).className);
1695 if (iid.isEmpty())
1696 error("Undefined interface");
1697
1698 iface[i].interfaceId = iid;
1699 }
1700 def->interfaceList += iface;
1701 }
1702 next(RPAREN);
1703}
1704
1706{
1707 next(LPAREN);
1709 next(IDENTIFIER);
1710 interface += lexem();
1711 while (test(SCOPE)) {
1712 interface += lexem();
1713 next(IDENTIFIER);
1714 interface += lexem();
1715 }
1716 next(COMMA);
1717 QByteArray iid;
1718 if (test(STRING_LITERAL)) {
1719 iid = lexem();
1720 } else {
1721 next(IDENTIFIER);
1722 iid = lexem();
1723 }
1725 next(RPAREN);
1726}
1727
1729{
1730 next(LPAREN);
1731 QByteArray typeName = lexemUntil(RPAREN);
1732 typeName.remove(0, 1);
1733 typeName.chop(1);
1735}
1736
1738{
1739 next(LPAREN);
1740 QByteArray include = lexemUntil(RPAREN);
1741 // remove parentheses
1742 include.remove(0, 1);
1743 include.chop(1);
1744 includeFiles.append(include);
1745}
1746
1748{
1749 next(LPAREN);
1750 FunctionDef funcDef;
1751 next(IDENTIFIER);
1752 funcDef.inPrivateClass = lexem();
1753 // also allow void functions
1754 if (test(LPAREN)) {
1755 next(RPAREN);
1756 funcDef.inPrivateClass += "()";
1757 }
1758 next(COMMA);
1759 funcDef.access = access;
1760 parseFunction(&funcDef, true);
1761 def->slotList += funcDef;
1762 handleDefaultArguments(&def->slotList, funcDef);
1763 if (funcDef.revision > 0)
1764 ++def->revisionedMethods;
1765
1766}
1767
1769{
1770 qsizetype from = index;
1771 until(target);
1772 QByteArray s;
1773 while (from <= index) {
1774 QByteArray n = symbols.at(from++-1).lexem();
1775 if (s.size() && n.size()) {
1776 char prev = s.at(s.size()-1);
1777 char next = n.at(0);
1779 || (prev == '<' && next == ':')
1780 || (prev == '>' && next == '>'))
1781 s += ' ';
1782 }
1783 s += n;
1784 }
1785 return s;
1786}
1787
1789 int braceCount = 0;
1790 int brackCount = 0;
1791 int parenCount = 0;
1792 int angleCount = 0;
1793 if (index) {
1794 switch(symbols.at(index-1).token) {
1795 case LBRACE: ++braceCount; break;
1796 case LBRACK: ++brackCount; break;
1797 case LPAREN: ++parenCount; break;
1798 case LANGLE: ++angleCount; break;
1799 default: break;
1800 }
1801 }
1802
1803 //when searching commas within the default argument, we should take care of template depth (anglecount)
1804 // unfortunately, we do not have enough semantic information to know if '<' is the operator< or
1805 // the beginning of a template type. so we just use heuristics.
1806 qsizetype possible = -1;
1807
1808 while (index < symbols.size()) {
1809 Token t = symbols.at(index++).token;
1810 switch (t) {
1811 case LBRACE: ++braceCount; break;
1812 case RBRACE: --braceCount; break;
1813 case LBRACK: ++brackCount; break;
1814 case RBRACK: --brackCount; break;
1815 case LPAREN: ++parenCount; break;
1816 case RPAREN: --parenCount; break;
1817 case LANGLE:
1818 if (parenCount == 0 && braceCount == 0)
1819 ++angleCount;
1820 break;
1821 case RANGLE:
1822 if (parenCount == 0 && braceCount == 0)
1823 --angleCount;
1824 break;
1825 case GTGT:
1826 if (parenCount == 0 && braceCount == 0) {
1827 angleCount -= 2;
1828 t = RANGLE;
1829 }
1830 break;
1831 default: break;
1832 }
1833 if (t == target
1834 && braceCount <= 0
1835 && brackCount <= 0
1836 && parenCount <= 0
1837 && (target != RANGLE || angleCount <= 0)) {
1838 if (target != COMMA || angleCount <= 0)
1839 return true;
1840 possible = index;
1841 }
1842
1843 if (target == COMMA && t == EQ && possible != -1) {
1844 index = possible;
1845 return true;
1846 }
1847
1848 if (braceCount < 0 || brackCount < 0 || parenCount < 0
1849 || (target == RANGLE && angleCount < 0)) {
1850 --index;
1851 break;
1852 }
1853
1854 if (braceCount <= 0 && t == SEMIC) {
1855 // Abort on semicolon. Allow recovering bad template parsing (QTBUG-31218)
1856 break;
1857 }
1858 }
1859
1860 if (target == COMMA && angleCount != 0 && possible != -1) {
1861 index = possible;
1862 return true;
1863 }
1864
1865 return false;
1866}
1867
1869{
1871 const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
1872
1873 if (!knownQObjectClasses.contains(firstSuperclass)) {
1874 // enable once we /require/ include paths
1875#if 0
1876 const QByteArray msg
1877 = "Class "
1878 + def->className
1879 + " contains the Q_OBJECT macro and inherits from "
1880 + def->superclassList.value(0)
1881 + " but that is not a known QObject subclass. You may get compilation errors.";
1882 warning(msg.constData());
1883#endif
1884 return;
1885 }
1886
1887 auto isRegisteredInterface = [&def](QByteArrayView super) {
1888 auto matchesSuperClass = [&super](const auto &ifaces) {
1889 return !ifaces.isEmpty() && ifaces.first().className == super;
1890 };
1891 return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
1892 };
1893
1894 const auto end = def->superclassList.cend();
1895 auto it = def->superclassList.cbegin() + 1;
1896 for (; it != end; ++it) {
1897 const QByteArray &superClass = it->classname;
1898 if (knownQObjectClasses.contains(superClass)) {
1899 const QByteArray msg
1900 = "Class "
1901 + def->classname
1902 + " inherits from two QObject subclasses "
1903 + firstSuperclass
1904 + " and "
1905 + superClass
1906 + ". This is not supported!";
1907 warning(msg.constData());
1908 }
1909
1910 if (interface2IdMap.contains(superClass)) {
1911 if (!isRegisteredInterface(superClass)) {
1912 const QByteArray msg
1913 = "Class "
1914 + def->classname
1915 + " implements the interface "
1916 + superClass
1917 + " but does not list it in Q_INTERFACES. qobject_cast to "
1918 + superClass
1919 + " will not work!";
1920 warning(msg.constData());
1921 }
1922 }
1923 }
1924}
1925
1927{
1928 //
1929 // specify get function, for compatibility we accept functions
1930 // returning pointers, or const char * for QByteArray.
1931 //
1932 QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
1933 auto hasNoAttributes = [&](const PropertyDef &p) {
1934 if (definedProperties.hasSeen(p.name)) {
1935 QByteArray msg = "The property '" + p.name + "' is defined multiple times in class " + cdef->classname + ".";
1936 warning(msg.constData());
1937 }
1938
1939 if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
1940 QByteArray msg = "Property declaration " + p.name + " has neither an associated QProperty<> member"
1941 ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
1942 const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
1943 warning(sym, msg.constData());
1944 if (p.write.isEmpty())
1945 return true;
1946 }
1947 return false;
1948 };
1949 cdef->propertyList.removeIf(hasNoAttributes);
1950
1951 for (PropertyDef &p : cdef->propertyList) {
1952 for (const FunctionDef &f : std::as_const(cdef->publicList)) {
1953 if (f.name != p.read)
1954 continue;
1955 if (!f.isConst) // get functions must be const
1956 continue;
1957 if (f.arguments.size()) // and must not take any arguments
1958 continue;
1960 QByteArray tmp = f.normalizedType;
1961 if (p.type == "QByteArray" && tmp == "const char *")
1962 tmp = "QByteArray";
1963 if (tmp.left(6) == "const ")
1964 tmp = tmp.mid(6);
1965 if (p.type != tmp && tmp.endsWith('*')) {
1966 tmp.chop(1);
1968 } else if (f.type.name.endsWith('&')) { // raw type, not normalized type
1970 }
1971 if (p.type != tmp)
1972 continue;
1973 p.gspec = spec;
1974 break;
1975 }
1976 if (!p.notify.isEmpty()) {
1977 int notifyId = -1;
1978 for (int j = 0; j < int(cdef->signalList.size()); ++j) {
1979 const FunctionDef &f = cdef->signalList.at(j);
1980 if (f.name != p.notify) {
1981 continue;
1982 } else {
1983 notifyId = j /* Signal indexes start from 0 */;
1984 break;
1985 }
1986 }
1987 p.notifyId = notifyId;
1988 if (notifyId == -1) {
1989 const int index = int(cdef->nonClassSignalList.indexOf(p.notify));
1990 if (index == -1) {
1991 cdef->nonClassSignalList << p.notify;
1992 p.notifyId = int(-1 - cdef->nonClassSignalList.size());
1993 } else {
1994 p.notifyId = int(-2 - index);
1995 }
1996 }
1997 }
1998 }
1999}
2000
2002{
2003 QJsonObject cls;
2004 cls["className"_L1] = QString::fromUtf8(classname.constData());
2005 cls["qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
2006
2007 QJsonArray classInfos;
2008 for (const auto &info: std::as_const(classInfoList)) {
2009 QJsonObject infoJson;
2010 infoJson["name"_L1] = QString::fromUtf8(info.name);
2011 infoJson["value"_L1] = QString::fromUtf8(info.value);
2012 classInfos.append(infoJson);
2013 }
2014
2015 if (classInfos.size())
2016 cls["classInfos"_L1] = classInfos;
2017
2018 const auto appendFunctions = [&cls](const QString &type, const QList<FunctionDef> &funcs) {
2019 QJsonArray jsonFuncs;
2020
2021 for (const FunctionDef &fdef: funcs)
2022 jsonFuncs.append(fdef.toJson());
2023
2024 if (!jsonFuncs.isEmpty())
2025 cls[type] = jsonFuncs;
2026 };
2027
2028 appendFunctions("signals"_L1, signalList);
2029 appendFunctions("slots"_L1, slotList);
2030 appendFunctions("constructors"_L1, constructorList);
2031 appendFunctions("methods"_L1, methodList);
2032
2034
2035 for (const PropertyDef &propDef: std::as_const(propertyList))
2036 props.append(propDef.toJson());
2037
2038 if (!props.isEmpty())
2039 cls["properties"_L1] = props;
2040
2041 if (hasQObject)
2042 cls["object"_L1] = true;
2043 if (hasQGadget)
2044 cls["gadget"_L1] = true;
2045 if (hasQNamespace)
2046 cls["namespace"_L1] = true;
2047
2048 QJsonArray superClasses;
2049
2050 for (const auto &super: std::as_const(superclassList)) {
2051 QJsonObject superCls;
2052 superCls["name"_L1] = QString::fromUtf8(super.classname);
2053 if (super.classname != super.qualified)
2054 superCls["fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
2055 FunctionDef::accessToJson(&superCls, super.access);
2056 superClasses.append(superCls);
2057 }
2058
2059 if (!superClasses.isEmpty())
2060 cls["superClasses"_L1] = superClasses;
2061
2062 QJsonArray enums;
2063 for (const EnumDef &enumDef: std::as_const(enumList))
2064 enums.append(enumDef.toJson(*this));
2065 if (!enums.isEmpty())
2066 cls["enums"_L1] = enums;
2067
2068 QJsonArray ifaces;
2069 for (const QList<Interface> &ifaceList : interfaceList) {
2070 QJsonArray jsonList;
2071 for (const Interface &iface: ifaceList) {
2072 QJsonObject ifaceJson;
2073 ifaceJson["id"_L1] = QString::fromUtf8(iface.interfaceId);
2074 ifaceJson["className"_L1] = QString::fromUtf8(iface.className);
2075 jsonList.append(ifaceJson);
2076 }
2077 ifaces.append(jsonList);
2078 }
2079 if (!ifaces.isEmpty())
2080 cls["interfaces"_L1] = ifaces;
2081
2082 return cls;
2083}
2084
2086{
2087 QJsonObject fdef;
2088 fdef["name"_L1] = QString::fromUtf8(name);
2089 if (!tag.isEmpty())
2090 fdef["tag"_L1] = QString::fromUtf8(tag);
2091 fdef["returnType"_L1] = QString::fromUtf8(normalizedType);
2092
2094 for (const ArgumentDef &arg: arguments)
2095 args.append(arg.toJson());
2096
2097 if (!args.isEmpty())
2098 fdef["arguments"_L1] = args;
2099
2100 accessToJson(&fdef, access);
2101
2102 if (revision > 0)
2103 fdef["revision"_L1] = revision;
2104
2105 if (wasCloned)
2106 fdef["isCloned"_L1] = true;
2107
2108 return fdef;
2109}
2110
2112{
2113 switch (acs) {
2114 case Private: (*obj)["access"_L1] = "private"_L1; break;
2115 case Public: (*obj)["access"_L1] = "public"_L1; break;
2116 case Protected: (*obj)["access"_L1] = "protected"_L1; break;
2117 }
2118}
2119
2121{
2123 arg["type"_L1] = QString::fromUtf8(normalizedType);
2124 if (!name.isEmpty())
2125 arg["name"_L1] = QString::fromUtf8(name);
2126 return arg;
2127}
2128
2130{
2131 QJsonObject prop;
2132 prop["name"_L1] = QString::fromUtf8(name);
2133 prop["type"_L1] = QString::fromUtf8(type);
2134
2135 const auto jsonify = [&prop](const char *str, const QByteArray &member) {
2136 if (!member.isEmpty())
2138 };
2139
2140 jsonify("member", member);
2141 jsonify("read", read);
2142 jsonify("write", write);
2143 jsonify("bindable", bind);
2144 jsonify("reset", reset);
2145 jsonify("notify", notify);
2146 jsonify("privateClass", inPrivateClass);
2147
2148 const auto jsonifyBoolOrString = [&prop](const char *str, const QByteArray &boolOrString) {
2150 if (boolOrString == "true")
2151 value = true;
2152 else if (boolOrString == "false")
2153 value = false;
2154 else
2155 value = QString::fromUtf8(boolOrString); // function name to query at run-time
2156 prop[QLatin1StringView(str)] = value;
2157 };
2158
2159 jsonifyBoolOrString("designable", designable);
2160 jsonifyBoolOrString("scriptable", scriptable);
2161 jsonifyBoolOrString("stored", stored);
2162 jsonifyBoolOrString("user", user);
2163
2164 prop["constant"_L1] = constant;
2165 prop["final"_L1] = final;
2166 prop["required"_L1] = required;
2167 prop["index"_L1] = relativeIndex;
2168 if (revision > 0)
2169 prop["revision"_L1] = revision;
2170
2171 return prop;
2172}
2173
2175{
2176 QJsonObject def;
2177 def["name"_L1] = QString::fromUtf8(name);
2178 if (!enumName.isEmpty())
2179 def["alias"_L1] = QString::fromUtf8(enumName);
2180 if (!type.isEmpty())
2181 def["type"_L1] = QString::fromUtf8(type);
2182 def["isFlag"_L1] = cdef.enumDeclarations.value(name);
2183 def["isClass"_L1] = isEnumClass;
2184
2185 QJsonArray valueArr;
2186 for (const QByteArray &value: values)
2187 valueArr.append(QString::fromUtf8(value));
2188 if (!valueArr.isEmpty())
2189 def["values"_L1] = valueArr;
2190
2191 return def;
2192}
2193
2195{
2196 if (name == cdef->classname) {
2197 // The name of the enclosing namespace is the same as the enum class name
2198 if (cdef->qualified.contains("::")) {
2199 // QTBUG-112996, fully qualify by using cdef->qualified to disambiguate enum
2200 // class name and enclosing namespace, e.g.:
2201 // namespace A { namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) } }
2202 return cdef->qualified % "::" % name;
2203 } else {
2204 // Just "B"; otherwise the compiler complains about the type "B::B" inside
2205 // "B::staticMetaObject" in the generated code; e.g.:
2206 // namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) }
2207 return name;
2208 }
2209 }
2210 return cdef->classname % "::" % name;
2211}
2212
void checkSuperClasses(ClassDef *def)
Definition moc.cpp:1868
void parse()
Definition moc.cpp:662
bool parseEnum(EnumDef *def)
Definition moc.cpp:239
void parseProperty(ClassDef *def, PropertyMode mode)
Definition moc.cpp:1495
QByteArray lexemUntil(Token)
Definition moc.cpp:1768
EncounteredQmlMacro parseClassInfo(BaseDef *def)
Definition moc.cpp:1639
bool until(Token)
Definition moc.cpp:1788
QList< QByteArray > includeFiles
Definition moc.h:222
bool requireCompleteTypes
Definition moc.h:220
QHash< QByteArray, QByteArray > knownQObjectClasses
Definition moc.h:227
void createPropertyDef(PropertyDef &def, int propertyIndex, PropertyMode mode)
Definition moc.cpp:1320
bool parseClassHead(ClassDef *def)
Definition moc.cpp:38
void parsePrivateProperty(ClassDef *def, PropertyMode mode)
Definition moc.cpp:1587
QByteArray includePath
Definition moc.h:221
QByteArray filename
Definition moc.h:216
void parseFlag(BaseDef *def)
Definition moc.cpp:1615
void parseSignals(ClassDef *def)
Definition moc.cpp:1276
void parseDeclareMetatype()
Definition moc.cpp:1728
void parsePropertyAttributes(PropertyDef &propDef)
Definition moc.cpp:1358
void parseInterfaces(ClassDef *def)
Definition moc.cpp:1672
bool testFunctionRevision(FunctionDef *def)
Definition moc.cpp:407
bool testFunctionAttribute(FunctionDef *def)
Definition moc.cpp:335
void prependNamespaces(BaseDef &def, const QList< NamespaceDef > &namespaceList) const
Definition moc.cpp:616
QHash< QByteArray, QByteArray > knownGadgets
Definition moc.h:228
QList< QByteArray > metaTypes
Definition moc.h:225
bool parseFunction(FunctionDef *def, bool inMacro=false)
Definition moc.cpp:419
QByteArray parsePropertyAccessor()
Definition moc.cpp:1569
QMap< QString, QJsonArray > metaArgs
Definition moc.h:229
bool testForFunctionModifiers(FunctionDef *def)
Definition moc.cpp:521
const QByteArray & toFullyQualified(const QByteArray &name) const noexcept
Definition moc.cpp:29
void parseSlots(ClassDef *def, FunctionDef::Access access)
Definition moc.cpp:1234
void parseDeclareInterface()
Definition moc.cpp:1705
void checkListSizes(const ClassDef &def)
Definition moc.cpp:626
QTypeRevision parseRevision()
Definition moc.cpp:376
void parseMocInclude()
Definition moc.cpp:1737
QList< QString > parsedPluginMetadataFiles
Definition moc.h:230
bool skipCxxAttributes()
Definition moc.cpp:367
PropertyMode
Definition moc.h:210
@ Anonymous
Definition moc.h:210
@ Named
Definition moc.h:210
bool mustIncludeQPluginH
Definition moc.h:219
bool parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
Definition moc.cpp:529
void checkProperties(ClassDef *cdef)
Definition moc.cpp:1926
Type parseType()
Definition moc.cpp:124
void parseFunctionArguments(FunctionDef *def)
Definition moc.cpp:294
void parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
Definition moc.cpp:1747
bool inClass(const ClassDef *def) const
Definition moc.h:236
void parsePluginData(ClassDef *def)
Definition moc.cpp:1505
void generate(FILE *out, FILE *jsonOutput)
Definition moc.cpp:1135
QMap< QByteArray, QByteArray > interface2IdMap
Definition moc.h:224
bool noInclude
Definition moc.h:218
EncounteredQmlMacro
Definition moc.h:265
bool inNamespace(const NamespaceDef *def) const
Definition moc.h:240
QList< ClassDef > classList
Definition moc.h:223
void parseEnumOrFlag(BaseDef *def, bool isFlag)
Definition moc.cpp:1600
QList< IncludePath > includes
Definition parser.h:30
Token peek()
Definition parser.h:36
Token next()
Definition parser.h:35
Token token()
Definition parser.h:43
const Symbol & symbolAt(qsizetype idx)
Definition parser.h:47
void warning(const char *=nullptr)
Definition parser.cpp:78
bool hasNext() const
Definition parser.h:34
qsizetype index
Definition parser.h:19
void prev()
Definition parser.h:40
bool test(Token)
Definition parser.h:59
Token lookup(int k=1)
Definition parser.h:68
const Symbol & symbol()
Definition parser.h:46
QByteArray lexem()
Definition parser.h:44
Symbols symbols
Definition parser.h:18
std::stack< QByteArray, QByteArrayList > currentFilenames
Definition parser.h:32
QByteArray unquotedLexem()
Definition parser.h:45
\inmodule QtCore
constexpr QByteArrayView last(qsizetype n) const
constexpr const_reverse_iterator crbegin() const noexcept
constexpr const_reverse_iterator crend() const noexcept
constexpr const_pointer constData() const noexcept
\inmodule QtCore
Definition qbytearray.h:57
bool endsWith(char c) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:227
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just after the last byte in the ...
Definition qbytearray.h:450
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first byte in the byte-ar...
Definition qbytearray.h:446
QByteArray & prepend(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:280
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
QByteArray left(qsizetype n) const &
Definition qbytearray.h:169
void chop(qsizetype n)
Removes n bytes from the end of the byte array.
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
Definition qbytearray.h:600
bool contains(char c) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:660
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
QByteArray & remove(qsizetype index, qsizetype len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
QByteArray mid(qsizetype index, qsizetype len=-1) const &
QDir dir() const
Returns a QDir object representing the path of the parent directory of the file system entry that thi...
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
bool isEmpty() const
Returns true if the object is empty.
qsizetype size() const
Returns the number of values stored in the array.
void append(const QJsonValue &value)
Inserts value at the end of the array.
\inmodule QtCore\reentrant
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
Parses json as a UTF-8 encoded JSON document, and creates a QJsonDocument from it.
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
\inmodule QtCore\reentrant
Definition qjsonvalue.h:25
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const T & constLast() const noexcept
Definition qlist.h:650
void push_back(parameter_type t)
Definition qlist.h:675
iterator end()
Definition qlist.h:626
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
T value(qsizetype i) const
Definition qlist.h:664
qsizetype removeIf(Predicate pred)
Definition qlist.h:604
iterator begin()
Definition qlist.h:625
const T & constFirst() const noexcept
Definition qlist.h:647
void removeLast() noexcept
Definition qlist.h:815
const_iterator cend() const noexcept
Definition qlist.h:631
void append(parameter_type t)
Definition qlist.h:458
const_iterator cbegin() const noexcept
Definition qlist.h:630
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
bool contains(const Key &key) const
Definition qmap.h:341
bool isEmpty() const
Definition qmap.h:269
qsizetype size() const
Definition qset.h:50
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
iterator insert(const T &value)
Definition qset.h:155
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
Produces a QTypeRevision from the given majorVersion and minorVersion, both of which need to be a val...
static constexpr bool isValidSegment(Integer segment)
Returns true if the given number can be used as either major or minor version in a QTypeRevision.
static constexpr QTypeRevision fromMinorVersion(Minor minorVersion)
Produces a QTypeRevision from the given minorVersion with an invalid major version.
constexpr Integer toEncodedVersion() const
Transforms the revision into an integer value, encoding the minor version into the least significant ...
static VulkanServerBufferGlFunctions * funcs
QString str
[2]
QSet< QString >::iterator it
static bool any_arg_contains(const QList< FunctionDef > &functions, const QByteArray &pattern)
Definition moc.cpp:1079
#define STREAM_1ARG_TEMPLATE(TEMPLATENAME)
static QByteArrayList requiredQtContainers(const QList< ClassDef > &classes)
Definition moc.cpp:1104
static QByteArray normalizeType(const QByteArray &ba)
Definition moc.cpp:24
IncludeState
Definition moc.cpp:233
static QByteArrayList make_candidates()
Definition moc.cpp:1090
#define STREAM_SMART_POINTER(SMART_POINTER)
static bool any_type_contains(const QList< PropertyDef > &properties, const QByteArray &pattern)
Definition moc.cpp:1070
void handleDefaultArguments(QList< FunctionDef > *functionList, FunctionDef &function)
Definition moc.cpp:604
Combined button and popup list for selecting options.
@ mocOutputRevision
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
static const QCssKnownValue properties[NumProperties - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static bool is_ident_char(char s)
const char * typeName
#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F)
Definition qmetatype.h:242
#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F)
Definition qmetatype.h:231
GLint GLfloat GLfloat GLfloat v2
GLsizei const GLfloat * v
[13]
GLenum mode
GLuint index
[2]
GLuint GLuint end
GLfloat GLfloat f
GLenum type
GLenum access
GLenum target
GLenum GLuint GLsizei const GLenum * props
GLuint name
GLfloat n
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLubyte * pattern
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
const char * SCOPE
QRandomGenerator generator(sseq)
QByteArray ba
[0]
QFile file
[0]
QTextStream out(stdout)
[7]
QHostInfo info
[0]
QJSValueList args
QByteArray normalizedType
Definition moc.h:58
QJsonObject toJson() const
Definition moc.cpp:2120
Definition moc.h:147
qsizetype end
Definition moc.h:155
qsizetype begin
Definition moc.h:154
QMap< QByteArray, QByteArray > flagAliases
Definition moc.h:153
QByteArray qualified
Definition moc.h:149
QByteArray classname
Definition moc.h:148
QMap< QByteArray, bool > enumDeclarations
Definition moc.h:151
QList< ClassInfoDef > classInfoList
Definition moc.h:150
QList< EnumDef > enumList
Definition moc.h:152
bool hasQObject
Definition moc.h:191
QList< QList< Interface > > interfaceList
Definition moc.h:176
QList< FunctionDef > publicList
Definition moc.h:186
QList< FunctionDef > methodList
Definition moc.h:186
QList< PropertyDef > propertyList
Definition moc.h:188
QList< FunctionDef > constructorList
Definition moc.h:185
bool hasQGadget
Definition moc.h:192
QList< SuperClass > superclassList
Definition moc.h:166
bool requireCompleteMethodTypes
Definition moc.h:194
bool hasQNamespace
Definition moc.h:193
QList< FunctionDef > slotList
Definition moc.h:186
QList< FunctionDef > signalList
Definition moc.h:186
int revisionedMethods
Definition moc.h:189
struct ClassDef::PluginData pluginData
QJsonObject toJson() const
Definition moc.cpp:2001
QList< QByteArray > nonClassSignalList
Definition moc.h:187
Definition moc.h:42
bool isEnumClass
Definition moc.h:47
QByteArray enumName
Definition moc.h:44
QByteArray qualifiedType(const ClassDef *cdef) const
Definition moc.cpp:2194
QJsonObject toJson(const ClassDef &cdef) const
Definition moc.cpp:2174
QList< QByteArray > values
Definition moc.h:46
QByteArray name
Definition moc.h:43
QByteArray type
Definition moc.h:45
bool isVirtual
Definition moc.h:80
bool isScriptable
Definition moc.h:89
bool wasCloned
Definition moc.h:83
QByteArray normalizedType
Definition moc.h:70
bool isCompat
Definition moc.h:87
QJsonObject toJson() const
Definition moc.cpp:2085
bool inlineCode
Definition moc.h:82
Type type
Definition moc.h:68
bool isRawSlot
Definition moc.h:96
static void accessToJson(QJsonObject *obj, Access acs)
Definition moc.cpp:2111
Access access
Definition moc.h:76
bool isSignal
Definition moc.h:91
bool isSlot
Definition moc.h:90
bool isInvokable
Definition moc.h:88
QByteArray name
Definition moc.h:72
bool isConst
Definition moc.h:79
QList< ArgumentDef > arguments
Definition moc.h:69
int revision
Definition moc.h:77
bool isAbstract
Definition moc.h:95
bool isPrivateSignal
Definition moc.h:92
bool isDestructor
Definition moc.h:94
@ Public
Definition moc.h:75
@ Protected
Definition moc.h:75
@ Private
Definition moc.h:75
bool isConstructor
Definition moc.h:93
bool isStatic
Definition moc.h:81
QByteArray tag
Definition moc.h:71
bool doGenerate
Definition moc.h:203
bool hasQNamespace
Definition moc.h:202
QByteArray scriptable
Definition moc.h:114
QByteArray member
Definition moc.h:114
QByteArray notify
Definition moc.h:114
QByteArray write
Definition moc.h:114
QByteArray inPrivateClass
Definition moc.h:114
QJsonObject toJson() const
Definition moc.cpp:2129
bool constant
Definition moc.h:119
Specification
Definition moc.h:116
@ ReferenceSpec
Definition moc.h:116
@ ValueSpec
Definition moc.h:116
@ PointerSpec
Definition moc.h:116
QByteArray user
Definition moc.h:114
QByteArray read
Definition moc.h:114
int revision
Definition moc.h:118
QByteArray bind
Definition moc.h:114
int relativeIndex
Definition moc.h:122
QByteArray designable
Definition moc.h:114
bool required
Definition moc.h:121
QByteArray stored
Definition moc.h:114
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
QByteArray classname
Definition moc.h:159
Token token
Definition symbols.h:59
QByteArray lexem() const
Definition symbols.h:60
QByteArray unquotedLexem() const
Definition symbols.h:61
Definition moc.h:23
Token firstToken
Definition moc.h:35
QByteArray rawName
Definition moc.h:32
uint isScoped
Definition moc.h:34
QByteArray name
Definition moc.h:29
ReferenceType referenceType
Definition moc.h:36
@ Q_META_TOKEN_END
Definition token.h:242
@ Q_META_TOKEN_BEGIN
Definition token.h:241