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