PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtbase/src/tools/moc/moc.cpp

https://code.google.com/
C++ | 1607 lines | 1489 code | 55 blank | 63 comment | 288 complexity | 34a79a903013928eece6fef91fdf21f2 MD5 | raw file
Possible License(s): LGPL-3.0, CC-BY-SA-4.0, MIT, AGPL-3.0, BSD-3-Clause, LGPL-2.1, CC0-1.0, GPL-2.0, LGPL-2.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the tools applications of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "moc.h"
  42. #include "generator.h"
  43. #include "qdatetime.h"
  44. #include "utils.h"
  45. #include "outputrevision.h"
  46. #include <QtCore/qfile.h>
  47. #include <QtCore/qfileinfo.h>
  48. #include <QtCore/qdir.h>
  49. // for normalizeTypeInternal
  50. #include <private/qmetaobject_moc_p.h>
  51. QT_BEGIN_NAMESPACE
  52. // only moc needs this function
  53. static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false)
  54. {
  55. const char *s = ba.constData();
  56. int len = ba.size();
  57. char stackbuf[64];
  58. char *buf = (len >= 64 ? new char[len + 1] : stackbuf);
  59. char *d = buf;
  60. char last = 0;
  61. while(*s && is_space(*s))
  62. s++;
  63. while (*s) {
  64. while (*s && !is_space(*s))
  65. last = *d++ = *s++;
  66. while (*s && is_space(*s))
  67. s++;
  68. if (*s && ((is_ident_char(*s) && is_ident_char(last))
  69. || ((*s == ':') && (last == '<')))) {
  70. last = *d++ = ' ';
  71. }
  72. }
  73. *d = '\0';
  74. QByteArray result = normalizeTypeInternal(buf, d, fixScope);
  75. if (buf != stackbuf)
  76. delete [] buf;
  77. return result;
  78. }
  79. bool Moc::parseClassHead(ClassDef *def)
  80. {
  81. // figure out whether this is a class declaration, or only a
  82. // forward or variable declaration.
  83. int i = 0;
  84. Token token;
  85. do {
  86. token = lookup(i++);
  87. if (token == COLON || token == LBRACE)
  88. break;
  89. if (token == SEMIC || token == RANGLE)
  90. return false;
  91. } while (token);
  92. if (!test(IDENTIFIER)) // typedef struct { ... }
  93. return false;
  94. QByteArray name = lexem();
  95. // support "class IDENT name" and "class IDENT(IDENT) name"
  96. // also support "class IDENT name (final|sealed|Q_DECL_FINAL)"
  97. if (test(LPAREN)) {
  98. until(RPAREN);
  99. if (!test(IDENTIFIER))
  100. return false;
  101. name = lexem();
  102. } else if (test(IDENTIFIER)) {
  103. const QByteArray lex = lexem();
  104. if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
  105. name = lex;
  106. }
  107. def->qualified += name;
  108. while (test(SCOPE)) {
  109. def->qualified += lexem();
  110. if (test(IDENTIFIER)) {
  111. name = lexem();
  112. def->qualified += name;
  113. }
  114. }
  115. def->classname = name;
  116. if (test(IDENTIFIER)) {
  117. const QByteArray lex = lexem();
  118. if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
  119. return false;
  120. }
  121. if (test(COLON)) {
  122. do {
  123. test(VIRTUAL);
  124. FunctionDef::Access access = FunctionDef::Public;
  125. if (test(PRIVATE))
  126. access = FunctionDef::Private;
  127. else if (test(PROTECTED))
  128. access = FunctionDef::Protected;
  129. else
  130. test(PUBLIC);
  131. test(VIRTUAL);
  132. const QByteArray type = parseType().name;
  133. // ignore the 'class Foo : BAR(Baz)' case
  134. if (test(LPAREN)) {
  135. until(RPAREN);
  136. } else {
  137. def->superclassList += qMakePair(type, access);
  138. }
  139. } while (test(COMMA));
  140. }
  141. if (!test(LBRACE))
  142. return false;
  143. def->begin = index - 1;
  144. bool foundRBrace = until(RBRACE);
  145. def->end = index;
  146. index = def->begin + 1;
  147. return foundRBrace;
  148. }
  149. Type Moc::parseType()
  150. {
  151. Type type;
  152. bool hasSignedOrUnsigned = false;
  153. bool isVoid = false;
  154. type.firstToken = lookup();
  155. for (;;) {
  156. switch (next()) {
  157. case SIGNED:
  158. case UNSIGNED:
  159. hasSignedOrUnsigned = true;
  160. // fall through
  161. case CONST:
  162. case VOLATILE:
  163. type.name += lexem();
  164. type.name += ' ';
  165. if (lookup(0) == VOLATILE)
  166. type.isVolatile = true;
  167. continue;
  168. case Q_MOC_COMPAT_TOKEN:
  169. case Q_INVOKABLE_TOKEN:
  170. case Q_SCRIPTABLE_TOKEN:
  171. case Q_SIGNALS_TOKEN:
  172. case Q_SLOTS_TOKEN:
  173. case Q_SIGNAL_TOKEN:
  174. case Q_SLOT_TOKEN:
  175. type.name += lexem();
  176. return type;
  177. default:
  178. prev();
  179. break;
  180. }
  181. break;
  182. }
  183. test(ENUM) || test(CLASS) || test(STRUCT);
  184. for(;;) {
  185. switch (next()) {
  186. case IDENTIFIER:
  187. // void mySlot(unsigned myArg)
  188. if (hasSignedOrUnsigned) {
  189. prev();
  190. break;
  191. }
  192. case CHAR:
  193. case SHORT:
  194. case INT:
  195. case LONG:
  196. type.name += lexem();
  197. // preserve '[unsigned] long long', 'short int', 'long int', 'long double'
  198. if (test(LONG) || test(INT) || test(DOUBLE)) {
  199. type.name += ' ';
  200. prev();
  201. continue;
  202. }
  203. break;
  204. case FLOAT:
  205. case DOUBLE:
  206. case VOID:
  207. case BOOL:
  208. type.name += lexem();
  209. isVoid |= (lookup(0) == VOID);
  210. break;
  211. default:
  212. prev();
  213. ;
  214. }
  215. if (test(LANGLE)) {
  216. if (type.name.isEmpty()) {
  217. // '<' cannot start a type
  218. return type;
  219. }
  220. type.name += lexemUntil(RANGLE);
  221. }
  222. if (test(SCOPE)) {
  223. type.name += lexem();
  224. type.isScoped = true;
  225. } else {
  226. break;
  227. }
  228. }
  229. while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
  230. || test(STAR) || test(AND) || test(ANDAND)) {
  231. type.name += ' ';
  232. type.name += lexem();
  233. if (lookup(0) == AND)
  234. type.referenceType = Type::Reference;
  235. else if (lookup(0) == ANDAND)
  236. type.referenceType = Type::RValueReference;
  237. else if (lookup(0) == STAR)
  238. type.referenceType = Type::Pointer;
  239. }
  240. type.rawName = type.name;
  241. // transform stupid things like 'const void' or 'void const' into 'void'
  242. if (isVoid && type.referenceType == Type::NoReference) {
  243. type.name = "void";
  244. }
  245. return type;
  246. }
  247. bool Moc::parseEnum(EnumDef *def)
  248. {
  249. bool isTypdefEnum = false; // typedef enum { ... } Foo;
  250. if (test(CLASS))
  251. def->isEnumClass = true;
  252. if (test(IDENTIFIER)) {
  253. def->name = lexem();
  254. } else {
  255. if (lookup(-1) != TYPEDEF)
  256. return false; // anonymous enum
  257. isTypdefEnum = true;
  258. }
  259. if (test(COLON)) { // C++11 strongly typed enum
  260. // enum Foo : unsigned long { ... };
  261. parseType(); //ignore the result
  262. }
  263. if (!test(LBRACE))
  264. return false;
  265. do {
  266. if (lookup() == RBRACE) // accept trailing comma
  267. break;
  268. next(IDENTIFIER);
  269. def->values += lexem();
  270. } while (test(EQ) ? until(COMMA) : test(COMMA));
  271. next(RBRACE);
  272. if (isTypdefEnum) {
  273. if (!test(IDENTIFIER))
  274. return false;
  275. def->name = lexem();
  276. }
  277. return true;
  278. }
  279. void Moc::parseFunctionArguments(FunctionDef *def)
  280. {
  281. Q_UNUSED(def);
  282. while (hasNext()) {
  283. ArgumentDef arg;
  284. arg.type = parseType();
  285. if (arg.type.name == "void")
  286. break;
  287. if (test(IDENTIFIER))
  288. arg.name = lexem();
  289. while (test(LBRACK)) {
  290. arg.rightType += lexemUntil(RBRACK);
  291. }
  292. if (test(CONST) || test(VOLATILE)) {
  293. arg.rightType += ' ';
  294. arg.rightType += lexem();
  295. }
  296. arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType));
  297. arg.typeNameForCast = normalizeType(QByteArray(noRef(arg.type.name) + "(*)" + arg.rightType));
  298. if (test(EQ))
  299. arg.isDefault = true;
  300. def->arguments += arg;
  301. if (!until(COMMA))
  302. break;
  303. }
  304. if (!def->arguments.isEmpty()
  305. && def->arguments.last().normalizedType == "QPrivateSignal") {
  306. def->arguments.removeLast();
  307. def->isPrivateSignal = true;
  308. }
  309. }
  310. bool Moc::testFunctionAttribute(FunctionDef *def)
  311. {
  312. if (index < symbols.size() && testFunctionAttribute(symbols.at(index).token, def)) {
  313. ++index;
  314. return true;
  315. }
  316. return false;
  317. }
  318. bool Moc::testFunctionAttribute(Token tok, FunctionDef *def)
  319. {
  320. switch (tok) {
  321. case Q_MOC_COMPAT_TOKEN:
  322. def->isCompat = true;
  323. return true;
  324. case Q_INVOKABLE_TOKEN:
  325. def->isInvokable = true;
  326. return true;
  327. case Q_SIGNAL_TOKEN:
  328. def->isSignal = true;
  329. return true;
  330. case Q_SLOT_TOKEN:
  331. def->isSlot = true;
  332. return true;
  333. case Q_SCRIPTABLE_TOKEN:
  334. def->isInvokable = def->isScriptable = true;
  335. return true;
  336. default: break;
  337. }
  338. return false;
  339. }
  340. bool Moc::testFunctionRevision(FunctionDef *def)
  341. {
  342. if (test(Q_REVISION_TOKEN)) {
  343. next(LPAREN);
  344. QByteArray revision = lexemUntil(RPAREN);
  345. revision.remove(0, 1);
  346. revision.chop(1);
  347. bool ok = false;
  348. def->revision = revision.toInt(&ok);
  349. if (!ok || def->revision < 0)
  350. error("Invalid revision");
  351. return true;
  352. }
  353. return false;
  354. }
  355. // returns false if the function should be ignored
  356. bool Moc::parseFunction(FunctionDef *def, bool inMacro)
  357. {
  358. def->isVirtual = false;
  359. def->isStatic = false;
  360. //skip modifiers and attributes
  361. while (test(INLINE) || (test(STATIC) && (def->isStatic = true)) ||
  362. (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
  363. || testFunctionAttribute(def) || testFunctionRevision(def)) {}
  364. bool templateFunction = (lookup() == TEMPLATE);
  365. def->type = parseType();
  366. if (def->type.name.isEmpty()) {
  367. if (templateFunction)
  368. error("Template function as signal or slot");
  369. else
  370. error();
  371. }
  372. bool scopedFunctionName = false;
  373. if (test(LPAREN)) {
  374. def->name = def->type.name;
  375. scopedFunctionName = def->type.isScoped;
  376. def->type = Type("int");
  377. } else {
  378. Type tempType = parseType();;
  379. while (!tempType.name.isEmpty() && lookup() != LPAREN) {
  380. if (testFunctionAttribute(def->type.firstToken, def))
  381. ; // fine
  382. else if (def->type.firstToken == Q_SIGNALS_TOKEN)
  383. error();
  384. else if (def->type.firstToken == Q_SLOTS_TOKEN)
  385. error();
  386. else {
  387. if (!def->tag.isEmpty())
  388. def->tag += ' ';
  389. def->tag += def->type.name;
  390. }
  391. def->type = tempType;
  392. tempType = parseType();
  393. }
  394. next(LPAREN, "Not a signal or slot declaration");
  395. def->name = tempType.name;
  396. scopedFunctionName = tempType.isScoped;
  397. }
  398. // we don't support references as return types, it's too dangerous
  399. if (def->type.referenceType == Type::Reference) {
  400. QByteArray rawName = def->type.rawName;
  401. def->type = Type("void");
  402. def->type.rawName = rawName;
  403. }
  404. def->normalizedType = normalizeType(def->type.name);
  405. if (!test(RPAREN)) {
  406. parseFunctionArguments(def);
  407. next(RPAREN);
  408. }
  409. // support optional macros with compiler specific options
  410. while (test(IDENTIFIER))
  411. ;
  412. def->isConst = test(CONST);
  413. while (test(IDENTIFIER))
  414. ;
  415. if (inMacro) {
  416. next(RPAREN);
  417. prev();
  418. } else {
  419. if (test(THROW)) {
  420. next(LPAREN);
  421. until(RPAREN);
  422. }
  423. if (test(SEMIC))
  424. ;
  425. else if ((def->inlineCode = test(LBRACE)))
  426. until(RBRACE);
  427. else if ((def->isAbstract = test(EQ)))
  428. until(SEMIC);
  429. else
  430. error();
  431. }
  432. if (scopedFunctionName) {
  433. QByteArray msg("Function declaration ");
  434. msg += def->name;
  435. msg += " contains extra qualification. Ignoring as signal or slot.";
  436. warning(msg.constData());
  437. return false;
  438. }
  439. return true;
  440. }
  441. // like parseFunction, but never aborts with an error
  442. bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
  443. {
  444. def->isVirtual = false;
  445. def->isStatic = false;
  446. //skip modifiers and attributes
  447. while (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true)) ||
  448. (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
  449. || testFunctionAttribute(def) || testFunctionRevision(def)) {}
  450. bool tilde = test(TILDE);
  451. def->type = parseType();
  452. if (def->type.name.isEmpty())
  453. return false;
  454. bool scopedFunctionName = false;
  455. if (test(LPAREN)) {
  456. def->name = def->type.name;
  457. scopedFunctionName = def->type.isScoped;
  458. if (def->name == cdef->classname) {
  459. def->isDestructor = tilde;
  460. def->isConstructor = !tilde;
  461. def->type = Type();
  462. } else {
  463. def->type = Type("int");
  464. }
  465. } else {
  466. Type tempType = parseType();;
  467. while (!tempType.name.isEmpty() && lookup() != LPAREN) {
  468. if (testFunctionAttribute(def->type.firstToken, def))
  469. ; // fine
  470. else if (def->type.name == "Q_SIGNAL")
  471. def->isSignal = true;
  472. else if (def->type.name == "Q_SLOT")
  473. def->isSlot = true;
  474. else {
  475. if (!def->tag.isEmpty())
  476. def->tag += ' ';
  477. def->tag += def->type.name;
  478. }
  479. def->type = tempType;
  480. tempType = parseType();
  481. }
  482. if (!test(LPAREN))
  483. return false;
  484. def->name = tempType.name;
  485. scopedFunctionName = tempType.isScoped;
  486. }
  487. // we don't support references as return types, it's too dangerous
  488. if (def->type.referenceType == Type::Reference) {
  489. QByteArray rawName = def->type.rawName;
  490. def->type = Type("void");
  491. def->type.rawName = rawName;
  492. }
  493. def->normalizedType = normalizeType(def->type.name);
  494. if (!test(RPAREN)) {
  495. parseFunctionArguments(def);
  496. if (!test(RPAREN))
  497. return false;
  498. }
  499. def->isConst = test(CONST);
  500. if (scopedFunctionName
  501. && (def->isSignal || def->isSlot || def->isInvokable)) {
  502. QByteArray msg("parsemaybe: Function declaration ");
  503. msg += def->name;
  504. msg += " contains extra qualification. Ignoring as signal or slot.";
  505. warning(msg.constData());
  506. return false;
  507. }
  508. return true;
  509. }
  510. void Moc::parse()
  511. {
  512. QList<NamespaceDef> namespaceList;
  513. bool templateClass = false;
  514. while (hasNext()) {
  515. Token t = next();
  516. switch (t) {
  517. case NAMESPACE: {
  518. int rewind = index;
  519. if (test(IDENTIFIER)) {
  520. if (test(EQ)) {
  521. // namespace Foo = Bar::Baz;
  522. until(SEMIC);
  523. } else if (!test(SEMIC)) {
  524. NamespaceDef def;
  525. def.name = lexem();
  526. next(LBRACE);
  527. def.begin = index - 1;
  528. until(RBRACE);
  529. def.end = index;
  530. index = def.begin + 1;
  531. namespaceList += def;
  532. index = rewind;
  533. }
  534. }
  535. break;
  536. }
  537. case SEMIC:
  538. case RBRACE:
  539. templateClass = false;
  540. break;
  541. case TEMPLATE:
  542. templateClass = true;
  543. break;
  544. case MOC_INCLUDE_BEGIN:
  545. currentFilenames.push(symbol().unquotedLexem());
  546. break;
  547. case MOC_INCLUDE_END:
  548. currentFilenames.pop();
  549. break;
  550. case Q_DECLARE_INTERFACE_TOKEN:
  551. parseDeclareInterface();
  552. break;
  553. case Q_DECLARE_METATYPE_TOKEN:
  554. parseDeclareMetatype();
  555. break;
  556. case USING:
  557. if (test(NAMESPACE)) {
  558. while (test(SCOPE) || test(IDENTIFIER))
  559. ;
  560. next(SEMIC);
  561. }
  562. break;
  563. case CLASS:
  564. case STRUCT: {
  565. if (currentFilenames.size() <= 1)
  566. break;
  567. ClassDef def;
  568. if (!parseClassHead(&def))
  569. continue;
  570. while (inClass(&def) && hasNext()) {
  571. switch (next()) {
  572. case Q_OBJECT_TOKEN:
  573. def.hasQObject = true;
  574. break;
  575. case Q_GADGET_TOKEN:
  576. def.hasQGadget = true;
  577. break;
  578. default: break;
  579. }
  580. }
  581. if (!def.hasQObject && !def.hasQGadget)
  582. continue;
  583. for (int i = namespaceList.size() - 1; i >= 0; --i)
  584. if (inNamespace(&namespaceList.at(i)))
  585. def.qualified.prepend(namespaceList.at(i).name + "::");
  586. QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
  587. classHash.insert(def.classname, def.qualified);
  588. classHash.insert(def.qualified, def.qualified);
  589. continue; }
  590. default: break;
  591. }
  592. if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
  593. continue;
  594. ClassDef def;
  595. if (parseClassHead(&def)) {
  596. FunctionDef::Access access = FunctionDef::Private;
  597. for (int i = namespaceList.size() - 1; i >= 0; --i)
  598. if (inNamespace(&namespaceList.at(i)))
  599. def.qualified.prepend(namespaceList.at(i).name + "::");
  600. while (inClass(&def) && hasNext()) {
  601. switch ((t = next())) {
  602. case PRIVATE:
  603. access = FunctionDef::Private;
  604. if (test(Q_SIGNALS_TOKEN))
  605. error("Signals cannot have access specifier");
  606. break;
  607. case PROTECTED:
  608. access = FunctionDef::Protected;
  609. if (test(Q_SIGNALS_TOKEN))
  610. error("Signals cannot have access specifier");
  611. break;
  612. case PUBLIC:
  613. access = FunctionDef::Public;
  614. if (test(Q_SIGNALS_TOKEN))
  615. error("Signals cannot have access specifier");
  616. break;
  617. case CLASS: {
  618. ClassDef nestedDef;
  619. if (parseClassHead(&nestedDef)) {
  620. while (inClass(&nestedDef) && inClass(&def)) {
  621. t = next();
  622. if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
  623. error("Meta object features not supported for nested classes");
  624. }
  625. }
  626. } break;
  627. case Q_SIGNALS_TOKEN:
  628. parseSignals(&def);
  629. break;
  630. case Q_SLOTS_TOKEN:
  631. switch (lookup(-1)) {
  632. case PUBLIC:
  633. case PROTECTED:
  634. case PRIVATE:
  635. parseSlots(&def, access);
  636. break;
  637. default:
  638. error("Missing access specifier for slots");
  639. }
  640. break;
  641. case Q_OBJECT_TOKEN:
  642. def.hasQObject = true;
  643. if (templateClass)
  644. error("Template classes not supported by Q_OBJECT");
  645. if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
  646. error("Class contains Q_OBJECT macro but does not inherit from QObject");
  647. break;
  648. case Q_GADGET_TOKEN:
  649. def.hasQGadget = true;
  650. if (templateClass)
  651. error("Template classes not supported by Q_GADGET");
  652. break;
  653. case Q_PROPERTY_TOKEN:
  654. parseProperty(&def);
  655. break;
  656. case Q_PLUGIN_METADATA_TOKEN:
  657. parsePluginData(&def);
  658. break;
  659. case Q_ENUMS_TOKEN:
  660. parseEnumOrFlag(&def, false);
  661. break;
  662. case Q_FLAGS_TOKEN:
  663. parseEnumOrFlag(&def, true);
  664. break;
  665. case Q_DECLARE_FLAGS_TOKEN:
  666. parseFlag(&def);
  667. break;
  668. case Q_CLASSINFO_TOKEN:
  669. parseClassInfo(&def);
  670. break;
  671. case Q_INTERFACES_TOKEN:
  672. parseInterfaces(&def);
  673. break;
  674. case Q_PRIVATE_SLOT_TOKEN:
  675. parseSlotInPrivate(&def, access);
  676. break;
  677. case Q_PRIVATE_PROPERTY_TOKEN:
  678. parsePrivateProperty(&def);
  679. break;
  680. case ENUM: {
  681. EnumDef enumDef;
  682. if (parseEnum(&enumDef))
  683. def.enumList += enumDef;
  684. } break;
  685. case SEMIC:
  686. case COLON:
  687. break;
  688. default:
  689. FunctionDef funcDef;
  690. funcDef.access = access;
  691. int rewind = index--;
  692. if (parseMaybeFunction(&def, &funcDef)) {
  693. if (funcDef.isConstructor) {
  694. if ((access == FunctionDef::Public) && funcDef.isInvokable) {
  695. def.constructorList += funcDef;
  696. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  697. funcDef.wasCloned = true;
  698. funcDef.arguments.removeLast();
  699. def.constructorList += funcDef;
  700. }
  701. }
  702. } else if (funcDef.isDestructor) {
  703. // don't care about destructors
  704. } else {
  705. if (access == FunctionDef::Public)
  706. def.publicList += funcDef;
  707. if (funcDef.isSlot) {
  708. def.slotList += funcDef;
  709. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  710. funcDef.wasCloned = true;
  711. funcDef.arguments.removeLast();
  712. def.slotList += funcDef;
  713. }
  714. if (funcDef.revision > 0)
  715. ++def.revisionedMethods;
  716. } else if (funcDef.isSignal) {
  717. def.signalList += funcDef;
  718. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  719. funcDef.wasCloned = true;
  720. funcDef.arguments.removeLast();
  721. def.signalList += funcDef;
  722. }
  723. if (funcDef.revision > 0)
  724. ++def.revisionedMethods;
  725. } else if (funcDef.isInvokable) {
  726. def.methodList += funcDef;
  727. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  728. funcDef.wasCloned = true;
  729. funcDef.arguments.removeLast();
  730. def.methodList += funcDef;
  731. }
  732. if (funcDef.revision > 0)
  733. ++def.revisionedMethods;
  734. }
  735. }
  736. } else {
  737. index = rewind;
  738. }
  739. }
  740. }
  741. next(RBRACE);
  742. if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()
  743. && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
  744. continue; // no meta object code required
  745. if (!def.hasQObject && !def.hasQGadget)
  746. error("Class declarations lacks Q_OBJECT macro.");
  747. // Add meta tags to the plugin meta data:
  748. if (!def.pluginData.iid.isEmpty())
  749. def.pluginData.metaArgs = metaArgs;
  750. checkSuperClasses(&def);
  751. checkProperties(&def);
  752. classList += def;
  753. QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
  754. classHash.insert(def.classname, def.qualified);
  755. classHash.insert(def.qualified, def.qualified);
  756. }
  757. }
  758. }
  759. static void findRequiredContainers(ClassDef *cdef, QSet<QByteArray> *requiredQtContainers)
  760. {
  761. static const QVector<QByteArray> candidates = QVector<QByteArray>()
  762. #define STREAM_SMART_POINTER(SMART_POINTER) << #SMART_POINTER
  763. QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(STREAM_SMART_POINTER)
  764. #undef STREAM_SMART_POINTER
  765. #define STREAM_1ARG_TEMPLATE(TEMPLATENAME) << #TEMPLATENAME
  766. QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(STREAM_1ARG_TEMPLATE)
  767. #undef STREAM_1ARG_TEMPLATE
  768. ;
  769. for (int i = 0; i < cdef->propertyList.count(); ++i) {
  770. const PropertyDef &p = cdef->propertyList.at(i);
  771. foreach (const QByteArray candidate, candidates) {
  772. if (p.type.contains(candidate + "<"))
  773. requiredQtContainers->insert(candidate);
  774. }
  775. }
  776. QList<FunctionDef> allFunctions = cdef->slotList + cdef->signalList + cdef->methodList;
  777. for (int i = 0; i < allFunctions.count(); ++i) {
  778. const FunctionDef &f = allFunctions.at(i);
  779. foreach (const ArgumentDef &arg, f.arguments) {
  780. foreach (const QByteArray candidate, candidates) {
  781. if (arg.normalizedType.contains(candidate + "<"))
  782. requiredQtContainers->insert(candidate);
  783. }
  784. }
  785. }
  786. }
  787. void Moc::generate(FILE *out)
  788. {
  789. QByteArray fn = filename;
  790. int i = filename.length()-1;
  791. while (i>0 && filename[i-1] != '/' && filename[i-1] != '\\')
  792. --i; // skip path
  793. if (i >= 0)
  794. fn = filename.mid(i);
  795. fprintf(out, "/****************************************************************************\n"
  796. "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
  797. fprintf(out, "** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
  798. fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
  799. "*****************************************************************************/\n\n");
  800. if (!noInclude) {
  801. if (includePath.size() && !includePath.endsWith('/'))
  802. includePath += '/';
  803. for (int i = 0; i < includeFiles.size(); ++i) {
  804. QByteArray inc = includeFiles.at(i);
  805. if (inc[0] != '<' && inc[0] != '"') {
  806. if (includePath.size() && includePath != "./")
  807. inc.prepend(includePath);
  808. inc = '\"' + inc + '\"';
  809. }
  810. fprintf(out, "#include %s\n", inc.constData());
  811. }
  812. }
  813. if (classList.size() && classList.first().classname == "Qt")
  814. fprintf(out, "#include <QtCore/qobject.h>\n");
  815. fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
  816. fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
  817. if (mustIncludeQPluginH)
  818. fprintf(out, "#include <QtCore/qplugin.h>\n");
  819. QSet<QByteArray> requiredQtContainers;
  820. for (i = 0; i < classList.size(); ++i) {
  821. findRequiredContainers(&classList[i], &requiredQtContainers);
  822. }
  823. // after finding the containers, we sort them into a list to avoid
  824. // non-deterministic behavior which may cause rebuilds unnecessarily.
  825. QList<QByteArray> requiredContainerList = requiredQtContainers.toList();
  826. std::sort(requiredContainerList.begin(), requiredContainerList.end());
  827. foreach (const QByteArray &qtContainer, requiredContainerList) {
  828. fprintf(out, "#include <QtCore/%s>\n", qtContainer.constData());
  829. }
  830. fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
  831. "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
  832. fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
  833. fprintf(out, "#error \"This file was generated using the moc from %s."
  834. " It\"\n#error \"cannot be used with the include files from"
  835. " this version of Qt.\"\n#error \"(The moc has changed too"
  836. " much.)\"\n", QT_VERSION_STR);
  837. fprintf(out, "#endif\n\n");
  838. fprintf(out, "QT_BEGIN_MOC_NAMESPACE\n");
  839. for (i = 0; i < classList.size(); ++i) {
  840. Generator generator(&classList[i], metaTypes, knownQObjectClasses, knownGadgets, out);
  841. generator.generateCode();
  842. }
  843. fprintf(out, "QT_END_MOC_NAMESPACE\n");
  844. }
  845. void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
  846. {
  847. int defaultRevision = -1;
  848. if (test(Q_REVISION_TOKEN)) {
  849. next(LPAREN);
  850. QByteArray revision = lexemUntil(RPAREN);
  851. revision.remove(0, 1);
  852. revision.chop(1);
  853. bool ok = false;
  854. defaultRevision = revision.toInt(&ok);
  855. if (!ok || defaultRevision < 0)
  856. error("Invalid revision");
  857. }
  858. next(COLON);
  859. while (inClass(def) && hasNext()) {
  860. switch (next()) {
  861. case PUBLIC:
  862. case PROTECTED:
  863. case PRIVATE:
  864. case Q_SIGNALS_TOKEN:
  865. case Q_SLOTS_TOKEN:
  866. prev();
  867. return;
  868. case SEMIC:
  869. continue;
  870. case FRIEND:
  871. until(SEMIC);
  872. continue;
  873. case USING:
  874. error("'using' directive not supported in 'slots' section");
  875. default:
  876. prev();
  877. }
  878. FunctionDef funcDef;
  879. funcDef.access = access;
  880. if (!parseFunction(&funcDef))
  881. continue;
  882. if (funcDef.revision > 0) {
  883. ++def->revisionedMethods;
  884. } else if (defaultRevision != -1) {
  885. funcDef.revision = defaultRevision;
  886. ++def->revisionedMethods;
  887. }
  888. def->slotList += funcDef;
  889. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  890. funcDef.wasCloned = true;
  891. funcDef.arguments.removeLast();
  892. def->slotList += funcDef;
  893. }
  894. }
  895. }
  896. void Moc::parseSignals(ClassDef *def)
  897. {
  898. int defaultRevision = -1;
  899. if (test(Q_REVISION_TOKEN)) {
  900. next(LPAREN);
  901. QByteArray revision = lexemUntil(RPAREN);
  902. revision.remove(0, 1);
  903. revision.chop(1);
  904. bool ok = false;
  905. defaultRevision = revision.toInt(&ok);
  906. if (!ok || defaultRevision < 0)
  907. error("Invalid revision");
  908. }
  909. next(COLON);
  910. while (inClass(def) && hasNext()) {
  911. switch (next()) {
  912. case PUBLIC:
  913. case PROTECTED:
  914. case PRIVATE:
  915. case Q_SIGNALS_TOKEN:
  916. case Q_SLOTS_TOKEN:
  917. prev();
  918. return;
  919. case SEMIC:
  920. continue;
  921. case FRIEND:
  922. until(SEMIC);
  923. continue;
  924. case USING:
  925. error("'using' directive not supported in 'signals' section");
  926. default:
  927. prev();
  928. }
  929. FunctionDef funcDef;
  930. funcDef.access = FunctionDef::Public;
  931. parseFunction(&funcDef);
  932. if (funcDef.isVirtual)
  933. warning("Signals cannot be declared virtual");
  934. if (funcDef.inlineCode)
  935. error("Not a signal declaration");
  936. if (funcDef.revision > 0) {
  937. ++def->revisionedMethods;
  938. } else if (defaultRevision != -1) {
  939. funcDef.revision = defaultRevision;
  940. ++def->revisionedMethods;
  941. }
  942. def->signalList += funcDef;
  943. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  944. funcDef.wasCloned = true;
  945. funcDef.arguments.removeLast();
  946. def->signalList += funcDef;
  947. }
  948. }
  949. }
  950. void Moc::createPropertyDef(PropertyDef &propDef)
  951. {
  952. QByteArray type = parseType().name;
  953. if (type.isEmpty())
  954. error();
  955. propDef.designable = propDef.scriptable = propDef.stored = "true";
  956. propDef.user = "false";
  957. /*
  958. The Q_PROPERTY construct cannot contain any commas, since
  959. commas separate macro arguments. We therefore expect users
  960. to type "QMap" instead of "QMap<QString, QVariant>". For
  961. coherence, we also expect the same for
  962. QValueList<QVariant>, the other template class supported by
  963. QVariant.
  964. */
  965. type = normalizeType(type);
  966. if (type == "QMap")
  967. type = "QMap<QString,QVariant>";
  968. else if (type == "QValueList")
  969. type = "QValueList<QVariant>";
  970. else if (type == "LongLong")
  971. type = "qlonglong";
  972. else if (type == "ULongLong")
  973. type = "qulonglong";
  974. propDef.type = type;
  975. next();
  976. propDef.name = lexem();
  977. while (test(IDENTIFIER)) {
  978. QByteArray l = lexem();
  979. if (l[0] == 'C' && l == "CONSTANT") {
  980. propDef.constant = true;
  981. continue;
  982. } else if(l[0] == 'F' && l == "FINAL") {
  983. propDef.final = true;
  984. continue;
  985. }
  986. QByteArray v, v2;
  987. if (test(LPAREN)) {
  988. v = lexemUntil(RPAREN);
  989. } else if (test(INTEGER_LITERAL)) {
  990. v = lexem();
  991. if (l != "REVISION")
  992. error(1);
  993. } else {
  994. next(IDENTIFIER);
  995. v = lexem();
  996. if (test(LPAREN))
  997. v2 = lexemUntil(RPAREN);
  998. else if (v != "true" && v != "false")
  999. v2 = "()";
  1000. }
  1001. switch (l[0]) {
  1002. case 'M':
  1003. if (l == "MEMBER")
  1004. propDef.member = v;
  1005. else
  1006. error(2);
  1007. break;
  1008. case 'R':
  1009. if (l == "READ")
  1010. propDef.read = v;
  1011. else if (l == "RESET")
  1012. propDef.reset = v + v2;
  1013. else if (l == "REVISION") {
  1014. bool ok = false;
  1015. propDef.revision = v.toInt(&ok);
  1016. if (!ok || propDef.revision < 0)
  1017. error(1);
  1018. } else
  1019. error(2);
  1020. break;
  1021. case 'S':
  1022. if (l == "SCRIPTABLE")
  1023. propDef.scriptable = v + v2;
  1024. else if (l == "STORED")
  1025. propDef.stored = v + v2;
  1026. else
  1027. error(2);
  1028. break;
  1029. case 'W': if (l != "WRITE") error(2);
  1030. propDef.write = v;
  1031. break;
  1032. case 'D': if (l != "DESIGNABLE") error(2);
  1033. propDef.designable = v + v2;
  1034. break;
  1035. case 'E': if (l != "EDITABLE") error(2);
  1036. propDef.editable = v + v2;
  1037. break;
  1038. case 'N': if (l != "NOTIFY") error(2);
  1039. propDef.notify = v;
  1040. break;
  1041. case 'U': if (l != "USER") error(2);
  1042. propDef.user = v + v2;
  1043. break;
  1044. default:
  1045. error(2);
  1046. }
  1047. }
  1048. if (propDef.read.isNull() && propDef.member.isNull()) {
  1049. QByteArray msg;
  1050. msg += "Property declaration ";
  1051. msg += propDef.name;
  1052. msg += " has no READ accessor function or associated MEMBER variable. The property will be invalid.";
  1053. warning(msg.constData());
  1054. }
  1055. if (propDef.constant && !propDef.write.isNull()) {
  1056. QByteArray msg;
  1057. msg += "Property declaration ";
  1058. msg += propDef.name;
  1059. msg += " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
  1060. propDef.constant = false;
  1061. warning(msg.constData());
  1062. }
  1063. if (propDef.constant && !propDef.notify.isNull()) {
  1064. QByteArray msg;
  1065. msg += "Property declaration ";
  1066. msg += propDef.name;
  1067. msg += " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
  1068. propDef.constant = false;
  1069. warning(msg.constData());
  1070. }
  1071. }
  1072. void Moc::parseProperty(ClassDef *def)
  1073. {
  1074. next(LPAREN);
  1075. PropertyDef propDef;
  1076. createPropertyDef(propDef);
  1077. next(RPAREN);
  1078. if(!propDef.notify.isEmpty())
  1079. def->notifyableProperties++;
  1080. if (propDef.revision > 0)
  1081. ++def->revisionedProperties;
  1082. def->propertyList += propDef;
  1083. }
  1084. void Moc::parsePluginData(ClassDef *def)
  1085. {
  1086. next(LPAREN);
  1087. QByteArray metaData;
  1088. while (test(IDENTIFIER)) {
  1089. QByteArray l = lexem();
  1090. if (l == "IID") {
  1091. next(STRING_LITERAL);
  1092. def->pluginData.iid = unquotedLexem();
  1093. } else if (l == "FILE") {
  1094. next(STRING_LITERAL);
  1095. QByteArray metaDataFile = unquotedLexem();
  1096. QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top().constData())).dir(), QString::fromLocal8Bit(metaDataFile.constData()));
  1097. for (int j = 0; j < includes.size() && !fi.exists(); ++j) {
  1098. const IncludePath &p = includes.at(j);
  1099. if (p.isFrameworkPath)
  1100. continue;
  1101. fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(metaDataFile.constData()));
  1102. // try again, maybe there's a file later in the include paths with the same name
  1103. if (fi.isDir()) {
  1104. fi = QFileInfo();
  1105. continue;
  1106. }
  1107. }
  1108. if (!fi.exists()) {
  1109. QByteArray msg;
  1110. msg += "Plugin Metadata file ";
  1111. msg += lexem();
  1112. msg += " does not exist. Declaration will be ignored";
  1113. error(msg.constData());
  1114. return;
  1115. }
  1116. QFile file(fi.canonicalFilePath());
  1117. file.open(QFile::ReadOnly);
  1118. metaData = file.readAll();
  1119. }
  1120. }
  1121. if (!metaData.isEmpty()) {
  1122. def->pluginData.metaData = QJsonDocument::fromJson(metaData);
  1123. if (!def->pluginData.metaData.isObject()) {
  1124. QByteArray msg;
  1125. msg += "Plugin Metadata file ";
  1126. msg += lexem();
  1127. msg += " does not contain a valid JSON object. Declaration will be ignored";
  1128. warning(msg.constData());
  1129. def->pluginData.iid = QByteArray();
  1130. return;
  1131. }
  1132. }
  1133. mustIncludeQPluginH = true;
  1134. next(RPAREN);
  1135. }
  1136. void Moc::parsePrivateProperty(ClassDef *def)
  1137. {
  1138. next(LPAREN);
  1139. PropertyDef propDef;
  1140. next(IDENTIFIER);
  1141. propDef.inPrivateClass = lexem();
  1142. while (test(SCOPE)) {
  1143. propDef.inPrivateClass += lexem();
  1144. next(IDENTIFIER);
  1145. propDef.inPrivateClass += lexem();
  1146. }
  1147. // also allow void functions
  1148. if (test(LPAREN)) {
  1149. next(RPAREN);
  1150. propDef.inPrivateClass += "()";
  1151. }
  1152. next(COMMA);
  1153. createPropertyDef(propDef);
  1154. if(!propDef.notify.isEmpty())
  1155. def->notifyableProperties++;
  1156. if (propDef.revision > 0)
  1157. ++def->revisionedProperties;
  1158. def->propertyList += propDef;
  1159. }
  1160. void Moc::parseEnumOrFlag(ClassDef *def, bool isFlag)
  1161. {
  1162. next(LPAREN);
  1163. QByteArray identifier;
  1164. while (test(IDENTIFIER)) {
  1165. identifier = lexem();
  1166. while (test(SCOPE) && test(IDENTIFIER)) {
  1167. identifier += "::";
  1168. identifier += lexem();
  1169. }
  1170. def->enumDeclarations[identifier] = isFlag;
  1171. }
  1172. next(RPAREN);
  1173. }
  1174. void Moc::parseFlag(ClassDef *def)
  1175. {
  1176. next(LPAREN);
  1177. QByteArray flagName, enumName;
  1178. while (test(IDENTIFIER)) {
  1179. flagName = lexem();
  1180. while (test(SCOPE) && test(IDENTIFIER)) {
  1181. flagName += "::";
  1182. flagName += lexem();
  1183. }
  1184. }
  1185. next(COMMA);
  1186. while (test(IDENTIFIER)) {
  1187. enumName = lexem();
  1188. while (test(SCOPE) && test(IDENTIFIER)) {
  1189. enumName += "::";
  1190. enumName += lexem();
  1191. }
  1192. }
  1193. def->flagAliases.insert(enumName, flagName);
  1194. next(RPAREN);
  1195. }
  1196. void Moc::parseClassInfo(ClassDef *def)
  1197. {
  1198. next(LPAREN);
  1199. ClassInfoDef infoDef;
  1200. next(STRING_LITERAL);
  1201. infoDef.name = symbol().unquotedLexem();
  1202. next(COMMA);
  1203. if (test(STRING_LITERAL)) {
  1204. infoDef.value = symbol().unquotedLexem();
  1205. } else {
  1206. // support Q_CLASSINFO("help", QT_TR_NOOP("blah"))
  1207. next(IDENTIFIER);
  1208. next(LPAREN);
  1209. next(STRING_LITERAL);
  1210. infoDef.value = symbol().unquotedLexem();
  1211. next(RPAREN);
  1212. }
  1213. next(RPAREN);
  1214. def->classInfoList += infoDef;
  1215. }
  1216. void Moc::parseInterfaces(ClassDef *def)
  1217. {
  1218. next(LPAREN);
  1219. while (test(IDENTIFIER)) {
  1220. QList<ClassDef::Interface> iface;
  1221. iface += ClassDef::Interface(lexem());
  1222. while (test(SCOPE)) {
  1223. iface.last().className += lexem();
  1224. next(IDENTIFIER);
  1225. iface.last().className += lexem();
  1226. }
  1227. while (test(COLON)) {
  1228. next(IDENTIFIER);
  1229. iface += ClassDef::Interface(lexem());
  1230. while (test(SCOPE)) {
  1231. iface.last().className += lexem();
  1232. next(IDENTIFIER);
  1233. iface.last().className += lexem();
  1234. }
  1235. }
  1236. // resolve from classnames to interface ids
  1237. for (int i = 0; i < iface.count(); ++i) {
  1238. const QByteArray iid = interface2IdMap.value(iface.at(i).className);
  1239. if (iid.isEmpty())
  1240. error("Undefined interface");
  1241. iface[i].interfaceId = iid;
  1242. }
  1243. def->interfaceList += iface;
  1244. }
  1245. next(RPAREN);
  1246. }
  1247. void Moc::parseDeclareInterface()
  1248. {
  1249. next(LPAREN);
  1250. QByteArray interface;
  1251. next(IDENTIFIER);
  1252. interface += lexem();
  1253. while (test(SCOPE)) {
  1254. interface += lexem();
  1255. next(IDENTIFIER);
  1256. interface += lexem();
  1257. }
  1258. next(COMMA);
  1259. QByteArray iid;
  1260. if (test(STRING_LITERAL)) {
  1261. iid = lexem();
  1262. } else {
  1263. next(IDENTIFIER);
  1264. iid = lexem();
  1265. }
  1266. interface2IdMap.insert(interface, iid);
  1267. next(RPAREN);
  1268. }
  1269. void Moc::parseDeclareMetatype()
  1270. {
  1271. next(LPAREN);
  1272. QByteArray typeName = lexemUntil(RPAREN);
  1273. typeName.remove(0, 1);
  1274. typeName.chop(1);
  1275. metaTypes.append(typeName);
  1276. }
  1277. void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
  1278. {
  1279. next(LPAREN);
  1280. FunctionDef funcDef;
  1281. next(IDENTIFIER);
  1282. funcDef.inPrivateClass = lexem();
  1283. // also allow void functions
  1284. if (test(LPAREN)) {
  1285. next(RPAREN);
  1286. funcDef.inPrivateClass += "()";
  1287. }
  1288. next(COMMA);
  1289. funcDef.access = access;
  1290. parseFunction(&funcDef, true);
  1291. def->slotList += funcDef;
  1292. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  1293. funcDef.wasCloned = true;
  1294. funcDef.arguments.removeLast();
  1295. def->slotList += funcDef;
  1296. }
  1297. if (funcDef.revision > 0)
  1298. ++def->revisionedMethods;
  1299. }
  1300. QByteArray Moc::lexemUntil(Token target)
  1301. {
  1302. int from = index;
  1303. until(target);
  1304. QByteArray s;
  1305. while (from <= index) {
  1306. QByteArray n = symbols.at(from++-1).lexem();
  1307. if (s.size() && n.size()) {
  1308. char prev = s.at(s.size()-1);
  1309. char next = n.at(0);
  1310. if ((is_ident_char(prev) && is_ident_char(next))
  1311. || (prev == '<' && next == ':')
  1312. || (prev == '>' && next == '>'))
  1313. s += ' ';
  1314. }
  1315. s += n;
  1316. }
  1317. return s;
  1318. }
  1319. bool Moc::until(Token target) {
  1320. int braceCount = 0;
  1321. int brackCount = 0;
  1322. int parenCount = 0;
  1323. int angleCount = 0;
  1324. if (index) {
  1325. switch(symbols.at(index-1).token) {
  1326. case LBRACE: ++braceCount; break;
  1327. case LBRACK: ++brackCount; break;
  1328. case LPAREN: ++parenCount; break;
  1329. case LANGLE: ++angleCount; break;
  1330. default: break;
  1331. }
  1332. }
  1333. //when searching commas within the default argument, we should take care of template depth (anglecount)
  1334. // unfortunatelly, we do not have enough semantic information to know if '<' is the operator< or
  1335. // the beginning of a template type. so we just use heuristics.
  1336. int possible = -1;
  1337. while (index < symbols.size()) {
  1338. Token t = symbols.at(index++).token;
  1339. switch (t) {
  1340. case LBRACE: ++braceCount; break;
  1341. case RBRACE: --braceCount; break;
  1342. case LBRACK: ++brackCount; break;
  1343. case RBRACK: --brackCount; break;
  1344. case LPAREN: ++parenCount; break;
  1345. case RPAREN: --parenCount; break;
  1346. case LANGLE:
  1347. if (parenCount == 0 && braceCount == 0 && parenCount == 0)
  1348. ++angleCount;
  1349. break;
  1350. case RANGLE:
  1351. if (parenCount == 0 && braceCount == 0)
  1352. --angleCount;
  1353. break;
  1354. case GTGT:
  1355. if (parenCount == 0 && braceCount == 0) {
  1356. angleCount -= 2;
  1357. t = RANGLE;
  1358. }
  1359. break;
  1360. default: break;
  1361. }
  1362. if (t == target
  1363. && braceCount <= 0
  1364. && brackCount <= 0
  1365. && parenCount <= 0
  1366. && (target != RANGLE || angleCount <= 0)) {
  1367. if (target != COMMA || angleCount <= 0)
  1368. return true;
  1369. possible = index;
  1370. }
  1371. if (target == COMMA && t == EQ && possible != -1) {
  1372. index = possible;
  1373. return true;
  1374. }
  1375. if (braceCount < 0 || brackCount < 0 || parenCount < 0
  1376. || (target == RANGLE && angleCount < 0)) {
  1377. --index;
  1378. break;
  1379. }
  1380. if (braceCount <= 0 && t == SEMIC) {
  1381. // Abort on semicolon. Allow recovering bad template parsing (QTBUG-31218)
  1382. break;
  1383. }
  1384. }
  1385. if(target == COMMA && angleCount != 0 && possible != -1) {
  1386. index = possible;
  1387. return true;
  1388. }
  1389. return false;
  1390. }
  1391. void Moc::checkSuperClasses(ClassDef *def)
  1392. {
  1393. const QByteArray firstSuperclass = def->superclassList.value(0).first;
  1394. if (!knownQObjectClasses.contains(firstSuperclass)) {
  1395. // enable once we /require/ include paths
  1396. #if 0
  1397. QByteArray msg;
  1398. msg += "Class ";
  1399. msg += def->className;
  1400. msg += " contains the Q_OBJECT macro and inherits from ";
  1401. msg += def->superclassList.value(0);
  1402. msg += " but that is not a known QObject subclass. You may get compilation errors.";
  1403. warning(msg.constData());
  1404. #endif
  1405. return;
  1406. }
  1407. for (int i = 1; i < def->superclassList.count(); ++i) {
  1408. const QByteArray superClass = def->superclassList.at(i).first;
  1409. if (knownQObjectClasses.contains(superClass)) {
  1410. QByteArray msg;
  1411. msg += "Class ";
  1412. msg += def->classname;
  1413. msg += " inherits from two QObject subclasses ";
  1414. msg += firstSuperclass;
  1415. msg += " and ";
  1416. msg += superClass;
  1417. msg += ". This is not supported!";
  1418. warning(msg.constData());
  1419. }
  1420. if (interface2IdMap.contains(superClass)) {
  1421. bool registeredInterface = false;
  1422. for (int i = 0; i < def->interfaceList.count(); ++i)
  1423. if (def->interfaceList.at(i).first().className == superClass) {

Large files files are truncated, but you can click here to view the full file