PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/tools/moc/moc.cpp

https://bitbucket.org/ottoshmidt/qtbase
C++ | 1572 lines | 1456 code | 55 blank | 61 comment | 297 complexity | 7b19a296634827c9429e83582fee973b MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, CC0-1.0, LGPL-3.0, CC-BY-SA-4.0, GPL-3.0, LGPL-2.1

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

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

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