PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/moc.cpp

https://bitbucket.org/ayufan/ayuine2c-moc
C++ | 1591 lines | 1474 code | 55 blank | 62 comment | 301 complexity | 99982f627d98ffee9702ad18bb8b2fad MD5 | raw file

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. Token token = next();
  575. if (token == Q_OBJECT_TOKEN) {
  576. def.hasQObject = true;
  577. break;
  578. }
  579. if (token == Q_VALUETYPE_TOKEN) {
  580. def.hasQObject = true;
  581. def.hasQGadget = true;
  582. break;
  583. }
  584. }
  585. if (!def.hasQObject)
  586. continue;
  587. for (int i = namespaceList.size() - 1; i >= 0; --i)
  588. if (inNamespace(&namespaceList.at(i)))
  589. def.qualified.prepend(namespaceList.at(i).name + "::");
  590. knownQObjectClasses.insert(def.classname);
  591. knownQObjectClasses.insert(def.qualified);
  592. continue; }
  593. default: break;
  594. }
  595. if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
  596. continue;
  597. ClassDef def;
  598. if (parseClassHead(&def)) {
  599. FunctionDef::Access access = FunctionDef::Private;
  600. for (int i = namespaceList.size() - 1; i >= 0; --i)
  601. if (inNamespace(&namespaceList.at(i)))
  602. def.qualified.prepend(namespaceList.at(i).name + "::");
  603. while (inClass(&def) && hasNext()) {
  604. switch ((t = next())) {
  605. case PRIVATE:
  606. access = FunctionDef::Private;
  607. if (test(Q_SIGNALS_TOKEN))
  608. error("Signals cannot have access specifier");
  609. break;
  610. case PROTECTED:
  611. access = FunctionDef::Protected;
  612. if (test(Q_SIGNALS_TOKEN))
  613. error("Signals cannot have access specifier");
  614. break;
  615. case PUBLIC:
  616. access = FunctionDef::Public;
  617. if (test(Q_SIGNALS_TOKEN))
  618. error("Signals cannot have access specifier");
  619. break;
  620. case CLASS: {
  621. ClassDef nestedDef;
  622. if (parseClassHead(&nestedDef)) {
  623. while (inClass(&nestedDef) && inClass(&def)) {
  624. t = next();
  625. if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
  626. error("Meta object features not supported for nested classes");
  627. }
  628. }
  629. } break;
  630. case Q_SIGNALS_TOKEN:
  631. parseSignals(&def);
  632. break;
  633. case Q_SLOTS_TOKEN:
  634. switch (lookup(-1)) {
  635. case PUBLIC:
  636. case PROTECTED:
  637. case PRIVATE:
  638. parseSlots(&def, access);
  639. break;
  640. default:
  641. error("Missing access specifier for slots");
  642. }
  643. break;
  644. case Q_OBJECT_TOKEN:
  645. def.hasQObject = true;
  646. if (templateClass)
  647. error("Template classes not supported by Q_OBJECT");
  648. if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
  649. error("Class contains Q_OBJECT macro but does not inherit from QObject");
  650. break;
  651. case Q_GADGET_TOKEN:
  652. #if 0
  653. def.hasQGadget = true;
  654. if (templateClass)
  655. error("Template classes not supported by Q_GADGET");
  656. break;
  657. #endif
  658. case Q_VALUETYPE_TOKEN:
  659. def.hasQGadget = true;
  660. def.hasQObject = true;
  661. if (templateClass)
  662. error("Template classes not supported by Q_GADGET");
  663. if (!def.superclassList.isEmpty())
  664. def.hasQObject = false;
  665. // error("Class contains Q_VALUETYPE macro but does inherit from superclass");
  666. break;
  667. case Q_PROPERTY_TOKEN:
  668. parseProperty(&def);
  669. break;
  670. case Q_PLUGIN_METADATA_TOKEN:
  671. parsePluginData(&def);
  672. break;
  673. case Q_ENUMS_TOKEN:
  674. parseEnumOrFlag(&def, false);
  675. break;
  676. case Q_FLAGS_TOKEN:
  677. parseEnumOrFlag(&def, true);
  678. break;
  679. case Q_DECLARE_FLAGS_TOKEN:
  680. parseFlag(&def);
  681. break;
  682. case Q_CLASSINFO_TOKEN:
  683. parseClassInfo(&def);
  684. break;
  685. case Q_INTERFACES_TOKEN:
  686. parseInterfaces(&def);
  687. break;
  688. case Q_PRIVATE_SLOT_TOKEN:
  689. parseSlotInPrivate(&def, access);
  690. break;
  691. case Q_PRIVATE_PROPERTY_TOKEN:
  692. parsePrivateProperty(&def);
  693. break;
  694. case ENUM: {
  695. EnumDef enumDef;
  696. if (parseEnum(&enumDef))
  697. def.enumList += enumDef;
  698. } break;
  699. case SEMIC:
  700. case COLON:
  701. break;
  702. default:
  703. FunctionDef funcDef;
  704. funcDef.access = access;
  705. int rewind = index--;
  706. if (parseMaybeFunction(&def, &funcDef)) {
  707. if (funcDef.isConstructor) {
  708. if ((access == FunctionDef::Public) && funcDef.isInvokable) {
  709. def.constructorList += funcDef;
  710. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  711. funcDef.wasCloned = true;
  712. funcDef.arguments.removeLast();
  713. def.constructorList += funcDef;
  714. }
  715. }
  716. } else if (funcDef.isDestructor) {
  717. // don't care about destructors
  718. } else {
  719. if (access == FunctionDef::Public)
  720. def.publicList += funcDef;
  721. if (funcDef.isSlot) {
  722. def.slotList += funcDef;
  723. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  724. funcDef.wasCloned = true;
  725. funcDef.arguments.removeLast();
  726. def.slotList += funcDef;
  727. }
  728. if (funcDef.revision > 0)
  729. ++def.revisionedMethods;
  730. } else if (funcDef.isSignal) {
  731. def.signalList += funcDef;
  732. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  733. funcDef.wasCloned = true;
  734. funcDef.arguments.removeLast();
  735. def.signalList += funcDef;
  736. }
  737. if (funcDef.revision > 0)
  738. ++def.revisionedMethods;
  739. } else if (funcDef.isInvokable) {
  740. def.methodList += funcDef;
  741. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  742. funcDef.wasCloned = true;
  743. funcDef.arguments.removeLast();
  744. def.methodList += funcDef;
  745. }
  746. if (funcDef.revision > 0)
  747. ++def.revisionedMethods;
  748. }
  749. }
  750. } else {
  751. index = rewind;
  752. }
  753. }
  754. }
  755. next(RBRACE);
  756. if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()
  757. && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
  758. continue; // no meta object code required
  759. if (!def.hasQObject && !def.hasQGadget)
  760. error("Class declarations lacks Q_OBJECT macro.");
  761. checkSuperClasses(&def);
  762. checkProperties(&def);
  763. classList += def;
  764. knownQObjectClasses.insert(def.classname);
  765. knownQObjectClasses.insert(def.qualified);
  766. }
  767. }
  768. }
  769. static void findRequiredContainers(ClassDef *cdef, QSet<QByteArray> *requiredQtContainers)
  770. {
  771. static const QVector<QByteArray> candidates = QVector<QByteArray>()
  772. #define STREAM_SMART_POINTER(SMART_POINTER) << #SMART_POINTER
  773. QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(STREAM_SMART_POINTER)
  774. #undef STREAM_SMART_POINTER
  775. #define STREAM_1ARG_TEMPLATE(TEMPLATENAME) << #TEMPLATENAME
  776. QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(STREAM_1ARG_TEMPLATE)
  777. #undef STREAM_1ARG_TEMPLATE
  778. ;
  779. for (int i = 0; i < cdef->propertyList.count(); ++i) {
  780. const PropertyDef &p = cdef->propertyList.at(i);
  781. foreach (const QByteArray candidate, candidates) {
  782. if (p.type.contains(candidate + "<"))
  783. requiredQtContainers->insert(candidate);
  784. }
  785. }
  786. QList<FunctionDef> allFunctions = cdef->slotList + cdef->signalList + cdef->methodList;
  787. for (int i = 0; i < allFunctions.count(); ++i) {
  788. const FunctionDef &f = allFunctions.at(i);
  789. foreach (const ArgumentDef &arg, f.arguments) {
  790. foreach (const QByteArray candidate, candidates) {
  791. if (arg.normalizedType.contains(candidate + "<"))
  792. requiredQtContainers->insert(candidate);
  793. }
  794. }
  795. }
  796. }
  797. void Moc::generate(FILE *out)
  798. {
  799. QDateTime dt = QDateTime::currentDateTime();
  800. QByteArray dstr = dt.toString().toLatin1();
  801. QByteArray fn = filename;
  802. int i = filename.length()-1;
  803. while (i>0 && filename[i-1] != '/' && filename[i-1] != '\\')
  804. --i; // skip path
  805. if (i >= 0)
  806. fn = filename.mid(i);
  807. fprintf(out, "/****************************************************************************\n"
  808. "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
  809. fprintf(out, "** Created: %s\n"
  810. "** by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , dstr.data(), mocOutputRevision, QT_VERSION_STR);
  811. fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
  812. "*****************************************************************************/\n\n");
  813. if (!noInclude) {
  814. if (includePath.size() && !includePath.endsWith('/'))
  815. includePath += '/';
  816. for (int i = 0; i < includeFiles.size(); ++i) {
  817. QByteArray inc = includeFiles.at(i);
  818. if (inc[0] != '<' && inc[0] != '"') {
  819. if (includePath.size() && includePath != "./")
  820. inc.prepend(includePath);
  821. inc = '\"' + inc + '\"';
  822. }
  823. fprintf(out, "#include %s\n", inc.constData());
  824. }
  825. }
  826. if (classList.size() && classList.first().classname == "Qt")
  827. fprintf(out, "#include <QtCore/qobject.h>\n");
  828. fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
  829. fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
  830. if (mustIncludeQPluginH)
  831. fprintf(out, "#include <QtCore/qplugin.h>\n");
  832. fprintf(out, "#include <Core/ClassInfo.hpp>\n");
  833. QSet<QByteArray> requiredQtContainers;
  834. for (i = 0; i < classList.size(); ++i) {
  835. findRequiredContainers(&classList[i], &requiredQtContainers);
  836. }
  837. foreach (const QByteArray &qtContainer, requiredQtContainers) {
  838. fprintf(out, "#include <QtCore/%s>\n", qtContainer.constData());
  839. }
  840. fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
  841. "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
  842. fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
  843. fprintf(out, "#error \"This file was generated using the moc from %s."
  844. " It\"\n#error \"cannot be used with the include files from"
  845. " this version of Qt.\"\n#error \"(The moc has changed too"
  846. " much.)\"\n", QT_VERSION_STR);
  847. fprintf(out, "#endif\n\n");
  848. fprintf(out, "QT_BEGIN_MOC_NAMESPACE\n");
  849. for (i = 0; i < classList.size(); ++i) {
  850. Generator generator(&classList[i], metaTypes, knownQObjectClasses, out);
  851. generator.generateCode();
  852. }
  853. fprintf(out, "QT_END_MOC_NAMESPACE\n");
  854. }
  855. void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
  856. {
  857. int defaultRevision = -1;
  858. if (test(Q_REVISION_TOKEN)) {
  859. next(LPAREN);
  860. QByteArray revision = lexemUntil(RPAREN);
  861. revision.remove(0, 1);
  862. revision.chop(1);
  863. bool ok = false;
  864. defaultRevision = revision.toInt(&ok);
  865. if (!ok || defaultRevision < 0)
  866. error("Invalid revision");
  867. }
  868. next(COLON);
  869. while (inClass(def) && hasNext()) {
  870. switch (next()) {
  871. case PUBLIC:
  872. case PROTECTED:
  873. case PRIVATE:
  874. case Q_SIGNALS_TOKEN:
  875. case Q_SLOTS_TOKEN:
  876. prev();
  877. return;
  878. case SEMIC:
  879. continue;
  880. case FRIEND:
  881. until(SEMIC);
  882. continue;
  883. case USING:
  884. error("'using' directive not supported in 'slots' section");
  885. default:
  886. prev();
  887. }
  888. FunctionDef funcDef;
  889. funcDef.access = access;
  890. if (!parseFunction(&funcDef))
  891. continue;
  892. if (funcDef.revision > 0) {
  893. ++def->revisionedMethods;
  894. } else if (defaultRevision != -1) {
  895. funcDef.revision = defaultRevision;
  896. ++def->revisionedMethods;
  897. }
  898. def->slotList += funcDef;
  899. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  900. funcDef.wasCloned = true;
  901. funcDef.arguments.removeLast();
  902. def->slotList += funcDef;
  903. }
  904. }
  905. }
  906. void Moc::parseSignals(ClassDef *def)
  907. {
  908. int defaultRevision = -1;
  909. if (test(Q_REVISION_TOKEN)) {
  910. next(LPAREN);
  911. QByteArray revision = lexemUntil(RPAREN);
  912. revision.remove(0, 1);
  913. revision.chop(1);
  914. bool ok = false;
  915. defaultRevision = revision.toInt(&ok);
  916. if (!ok || defaultRevision < 0)
  917. error("Invalid revision");
  918. }
  919. next(COLON);
  920. while (inClass(def) && hasNext()) {
  921. switch (next()) {
  922. case PUBLIC:
  923. case PROTECTED:
  924. case PRIVATE:
  925. case Q_SIGNALS_TOKEN:
  926. case Q_SLOTS_TOKEN:
  927. prev();
  928. return;
  929. case SEMIC:
  930. continue;
  931. case FRIEND:
  932. until(SEMIC);
  933. continue;
  934. case USING:
  935. error("'using' directive not supported in 'signals' section");
  936. default:
  937. prev();
  938. }
  939. FunctionDef funcDef;
  940. funcDef.access = FunctionDef::Protected;
  941. parseFunction(&funcDef);
  942. if (funcDef.isVirtual)
  943. warning("Signals cannot be declared virtual");
  944. if (funcDef.inlineCode)
  945. error("Not a signal declaration");
  946. if (funcDef.revision > 0) {
  947. ++def->revisionedMethods;
  948. } else if (defaultRevision != -1) {
  949. funcDef.revision = defaultRevision;
  950. ++def->revisionedMethods;
  951. }
  952. def->signalList += funcDef;
  953. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  954. funcDef.wasCloned = true;
  955. funcDef.arguments.removeLast();
  956. def->signalList += funcDef;
  957. }
  958. }
  959. }
  960. void Moc::createPropertyDef(PropertyDef &propDef)
  961. {
  962. QByteArray type = parseType().name;
  963. if (type.isEmpty())
  964. error();
  965. propDef.designable = propDef.scriptable = propDef.stored = "true";
  966. propDef.user = "false";
  967. /*
  968. The Q_PROPERTY construct cannot contain any commas, since
  969. commas separate macro arguments. We therefore expect users
  970. to type "QMap" instead of "QMap<QString, QVariant>". For
  971. coherence, we also expect the same for
  972. QValueList<QVariant>, the other template class supported by
  973. QVariant.
  974. */
  975. type = normalizeType(type);
  976. if (type == "QMap")
  977. type = "QMap<QString,QVariant>";
  978. else if (type == "QValueList")
  979. type = "QValueList<QVariant>";
  980. else if (type == "LongLong")
  981. type = "qlonglong";
  982. else if (type == "ULongLong")
  983. type = "qulonglong";
  984. propDef.type = type;
  985. next();
  986. propDef.name = lexem();
  987. while (test(IDENTIFIER)) {
  988. QByteArray l = lexem();
  989. if (l[0] == 'C' && l == "CONSTANT") {
  990. propDef.constant = true;
  991. continue;
  992. } else if(l[0] == 'F' && l == "FINAL") {
  993. propDef.final = true;
  994. continue;
  995. }
  996. QByteArray v, v2;
  997. if (test(LPAREN)) {
  998. v = lexemUntil(RPAREN);
  999. } else if (test(INTEGER_LITERAL)) {
  1000. v = lexem();
  1001. if (l != "REVISION")
  1002. error(1);
  1003. } else {
  1004. next(IDENTIFIER);
  1005. v = lexem();
  1006. if (test(LPAREN))
  1007. v2 = lexemUntil(RPAREN);
  1008. else if (v != "true" && v != "false")
  1009. v2 = "()";
  1010. }
  1011. switch (l[0]) {
  1012. case 'R':
  1013. if (l == "READ")
  1014. propDef.read = v;
  1015. else if (l == "RESET")
  1016. propDef.reset = v + v2;
  1017. else if (l == "REVISION") {
  1018. bool ok = false;
  1019. propDef.revision = v.toInt(&ok);
  1020. if (!ok || propDef.revision < 0)
  1021. error(1);
  1022. } else
  1023. error(2);
  1024. break;
  1025. case 'S':
  1026. if (l == "SCRIPTABLE")
  1027. propDef.scriptable = v + v2;
  1028. else if (l == "STORED")
  1029. propDef.stored = v + v2;
  1030. else
  1031. error(2);
  1032. break;
  1033. case 'W': if (l != "WRITE") error(2);
  1034. propDef.write = v;
  1035. break;
  1036. case 'D': if (l != "DESIGNABLE") error(2);
  1037. propDef.designable = v + v2;
  1038. break;
  1039. case 'E': if (l != "EDITABLE") error(2);
  1040. propDef.editable = v + v2;
  1041. break;
  1042. case 'N': if (l != "NOTIFY") error(2);
  1043. propDef.notify = v;
  1044. break;
  1045. case 'U': if (l != "USER") error(2);
  1046. propDef.user = v + v2;
  1047. break;
  1048. default:
  1049. error(2);
  1050. }
  1051. }
  1052. if (propDef.read.isNull()) {
  1053. QByteArray msg;
  1054. msg += "Property declaration ";
  1055. msg += propDef.name;
  1056. msg += " has no READ accessor function. The property will be invalid.";
  1057. warning(msg.constData());
  1058. }
  1059. if (propDef.constant && !propDef.write.isNull()) {
  1060. QByteArray msg;
  1061. msg += "Property declaration ";
  1062. msg += propDef.name;
  1063. msg += " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
  1064. propDef.constant = false;
  1065. warning(msg.constData());
  1066. }
  1067. if (propDef.constant && !propDef.notify.isNull()) {
  1068. QByteArray msg;
  1069. msg += "Property declaration ";
  1070. msg += propDef.name;
  1071. msg += " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
  1072. propDef.constant = false;
  1073. warning(msg.constData());
  1074. }
  1075. }
  1076. void Moc::parseProperty(ClassDef *def)
  1077. {
  1078. next(LPAREN);
  1079. PropertyDef propDef;
  1080. createPropertyDef(propDef);
  1081. next(RPAREN);
  1082. if(!propDef.notify.isEmpty())
  1083. def->notifyableProperties++;
  1084. if (propDef.revision > 0)
  1085. ++def->revisionedProperties;
  1086. def->propertyList += propDef;
  1087. }
  1088. void Moc::parsePluginData(ClassDef *def)
  1089. {
  1090. next(LPAREN);
  1091. QByteArray metaData;
  1092. while (test(IDENTIFIER)) {
  1093. QByteArray l = lexem();
  1094. if (l == "IID") {
  1095. next(STRING_LITERAL);
  1096. def->pluginData.iid = unquotedLexem();
  1097. } else if (l == "FILE") {
  1098. next(STRING_LITERAL);
  1099. QByteArray metaDataFile = unquotedLexem();
  1100. QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top().constData())).dir(), QString::fromLocal8Bit(metaDataFile.constData()));
  1101. for (int j = 0; j < includes.size() && !fi.exists(); ++j) {
  1102. const IncludePath &p = includes.at(j);
  1103. if (p.isFrameworkPath)
  1104. continue;
  1105. fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(metaDataFile.constData()));
  1106. // try again, maybe there's a file later in the include paths with the same name
  1107. if (fi.isDir()) {
  1108. fi = QFileInfo();
  1109. continue;
  1110. }
  1111. }
  1112. if (!fi.exists()) {
  1113. QByteArray msg;
  1114. msg += "Plugin Metadata file ";
  1115. msg += lexem();
  1116. msg += " does not exist. Declaration will be ignored";
  1117. error(msg.constData());
  1118. return;
  1119. }
  1120. QFile file(fi.canonicalFilePath());
  1121. file.open(QFile::ReadOnly);
  1122. metaData = file.readAll();
  1123. }
  1124. }
  1125. if (!metaData.isEmpty()) {
  1126. def->pluginData.metaData = QJsonDocument::fromJson(metaData);
  1127. if (!def->pluginData.metaData.isObject()) {
  1128. QByteArray msg;
  1129. msg += "Plugin Metadata file ";
  1130. msg += lexem();
  1131. msg += " does not contain a valid JSON object. Declaration will be ignored";
  1132. warning(msg.constData());
  1133. def->pluginData.iid = QByteArray();
  1134. return;
  1135. }
  1136. }
  1137. mustIncludeQPluginH = true;
  1138. next(RPAREN);
  1139. }
  1140. void Moc::parsePrivateProperty(ClassDef *def)
  1141. {
  1142. next(LPAREN);
  1143. PropertyDef propDef;
  1144. next(IDENTIFIER);
  1145. propDef.inPrivateClass = lexem();
  1146. while (test(SCOPE)) {
  1147. propDef.inPrivateClass += lexem();
  1148. next(IDENTIFIER);
  1149. propDef.inPrivateClass += lexem();
  1150. }
  1151. // also allow void functions
  1152. if (test(LPAREN)) {
  1153. next(RPAREN);
  1154. propDef.inPrivateClass += "()";
  1155. }
  1156. next(COMMA);
  1157. createPropertyDef(propDef);
  1158. if(!propDef.notify.isEmpty())
  1159. def->notifyableProperties++;
  1160. if (propDef.revision > 0)
  1161. ++def->revisionedProperties;
  1162. def->propertyList += propDef;
  1163. }
  1164. void Moc::parseEnumOrFlag(ClassDef *def, bool isFlag)
  1165. {
  1166. next(LPAREN);
  1167. QByteArray identifier;
  1168. while (test(IDENTIFIER)) {
  1169. identifier = lexem();
  1170. while (test(SCOPE) && test(IDENTIFIER)) {
  1171. identifier += "::";
  1172. identifier += lexem();
  1173. }
  1174. def->enumDeclarations[identifier] = isFlag;
  1175. }
  1176. next(RPAREN);
  1177. }
  1178. void Moc::parseFlag(ClassDef *def)
  1179. {
  1180. next(LPAREN);
  1181. QByteArray flagName, enumName;
  1182. while (test(IDENTIFIER)) {
  1183. flagName = lexem();
  1184. while (test(SCOPE) && test(IDENTIFIER)) {
  1185. flagName += "::";
  1186. flagName += lexem();
  1187. }
  1188. }
  1189. next(COMMA);
  1190. while (test(IDENTIFIER)) {
  1191. enumName = lexem();
  1192. while (test(SCOPE) && test(IDENTIFIER)) {
  1193. enumName += "::";
  1194. enumName += lexem();
  1195. }
  1196. }
  1197. def->flagAliases.insert(enumName, flagName);
  1198. next(RPAREN);
  1199. }
  1200. void Moc::parseClassInfo(ClassDef *def)
  1201. {
  1202. next(LPAREN);
  1203. ClassInfoDef infoDef;
  1204. next(STRING_LITERAL);
  1205. infoDef.name = symbol().unquotedLexem();
  1206. next(COMMA);
  1207. if (test(STRING_LITERAL)) {
  1208. infoDef.value = symbol().unquotedLexem();
  1209. } else {
  1210. // support Q_CLASSINFO("help", QT_TR_NOOP("blah"))
  1211. next(IDENTIFIER);
  1212. next(LPAREN);
  1213. next(STRING_LITERAL);
  1214. infoDef.value = symbol().unquotedLexem();
  1215. next(RPAREN);
  1216. }
  1217. next(RPAREN);
  1218. def->classInfoList += infoDef;
  1219. }
  1220. void Moc::parseInterfaces(ClassDef *def)
  1221. {
  1222. next(LPAREN);
  1223. while (test(IDENTIFIER)) {
  1224. QList<ClassDef::Interface> iface;
  1225. iface += ClassDef::Interface(lexem());
  1226. while (test(SCOPE)) {
  1227. iface.last().className += lexem();
  1228. next(IDENTIFIER);
  1229. iface.last().className += lexem();
  1230. }
  1231. while (test(COLON)) {
  1232. next(IDENTIFIER);
  1233. iface += ClassDef::Interface(lexem());
  1234. while (test(SCOPE)) {
  1235. iface.last().className += lexem();
  1236. next(IDENTIFIER);
  1237. iface.last().className += lexem();
  1238. }
  1239. }
  1240. // resolve from classnames to interface ids
  1241. for (int i = 0; i < iface.count(); ++i) {
  1242. const QByteArray iid = interface2IdMap.value(iface.at(i).className);
  1243. if (iid.isEmpty())
  1244. error("Undefined interface");
  1245. iface[i].interfaceId = iid;
  1246. }
  1247. def->interfaceList += iface;
  1248. }
  1249. next(RPAREN);
  1250. }
  1251. void Moc::parseDeclareInterface()
  1252. {
  1253. next(LPAREN);
  1254. QByteArray interface;
  1255. next(IDENTIFIER);
  1256. interface += lexem();
  1257. while (test(SCOPE)) {
  1258. interface += lexem();
  1259. next(IDENTIFIER);
  1260. interface += lexem();
  1261. }
  1262. next(COMMA);
  1263. QByteArray iid;
  1264. if (test(STRING_LITERAL)) {
  1265. iid = lexem();
  1266. } else {
  1267. next(IDENTIFIER);
  1268. iid = lexem();
  1269. }
  1270. interface2IdMap.insert(interface, iid);
  1271. next(RPAREN);
  1272. }
  1273. void Moc::parseDeclareMetatype()
  1274. {
  1275. next(LPAREN);
  1276. QByteArray typeName = lexemUntil(RPAREN);
  1277. typeName.remove(0, 1);
  1278. typeName.chop(1);
  1279. metaTypes.append(typeName);
  1280. }
  1281. void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
  1282. {
  1283. next(LPAREN);
  1284. FunctionDef funcDef;
  1285. next(IDENTIFIER);
  1286. funcDef.inPrivateClass = lexem();
  1287. // also allow void functions
  1288. if (test(LPAREN)) {
  1289. next(RPAREN);
  1290. funcDef.inPrivateClass += "()";
  1291. }
  1292. next(COMMA);
  1293. funcDef.access = access;
  1294. parseFunction(&funcDef, true);
  1295. def->slotList += funcDef;
  1296. while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
  1297. funcDef.wasCloned = true;
  1298. funcDef.arguments.removeLast();
  1299. def->slotList += funcDef;
  1300. }
  1301. if (funcDef.revision > 0)
  1302. ++def->revisionedMethods;
  1303. }
  1304. QByteArray Moc::lexemUntil(Token target)
  1305. {
  1306. int from = index;
  1307. until(target);
  1308. QByteArray s;
  1309. while (from <= index) {
  1310. QByteArray n = symbols.at(from++-1).lexem();
  1311. if (s.size() && n.size()
  1312. && is_ident_char(s.at(s.size()-1))
  1313. && is_ident_char(n.at(0)))
  1314. s += ' ';
  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: ++angleCount; break;
  1347. case RANGLE: --angleCount; break;
  1348. case GTGT: angleCount -= 2; t = RANGLE; break;
  1349. default: break;
  1350. }
  1351. if (t == target
  1352. && braceCount <= 0
  1353. && brackCount <= 0
  1354. && parenCount <= 0
  1355. && (target != RANGLE || angleCount <= 0)) {
  1356. if (target != COMMA || angleCount <= 0)
  1357. return true;
  1358. possible = index;
  1359. }
  1360. if (target == COMMA && t == EQ && possible != -1) {
  1361. index = possible;
  1362. return true;
  1363. }
  1364. if (braceCount < 0 || brackCount < 0 || parenCount < 0
  1365. || (target == RANGLE && angleCount < 0)) {
  1366. --index;
  1367. break;
  1368. }
  1369. }
  1370. if(target == COMMA && angleCount != 0 && possible != -1) {
  1371. index = possible;
  1372. return true;
  1373. }
  1374. return false;
  1375. }
  1376. void Moc::checkSuperClasses(ClassDef *def)
  1377. {
  1378. const QByteArray firstSuperclass = def->superclassList.value(0).first;
  1379. if (!knownQObjectClasses.contains(firstSuperclass)) {
  1380. // enable once we /require/ include paths
  1381. #if 0
  1382. QByteArray msg;
  1383. msg += "Class ";
  1384. msg += def->className;
  1385. msg += " contains the Q_OBJECT macro and inherits from ";
  1386. msg += def->superclassList.value(0);
  1387. msg += " but that is not a known QObject subclass. You may get compilation errors.";
  1388. warning(msg.constData());
  1389. #endif
  1390. return;
  1391. }
  1392. for (int i = 1; i < def->superclassList.count(); ++i) {
  1393. const QByteArray superClass = def->superclassList.at(i).first;
  1394. if (knownQObjectClasses.contains(superClass)) {
  1395. QByteArray msg;
  1396. msg += "Class ";
  1397. msg += def->classname;
  1398. msg += " inherits from two QObject subclasses ";
  1399. msg += firstSuperclass;
  1400. msg += " and ";
  1401. msg += superClass;
  1402. msg += ". This is not supported!";
  1403. warning(msg.constData());
  1404. }
  1405. if (interface2IdMap.contains(superClass)) {
  1406. bool registeredInterface = false;
  1407. for (int i = 0; i < def->interfaceList.count(); ++i)
  1408. if (def->interfaceList.at(i).first().className == superClass) {
  1409. registeredInterface = true;
  1410. break;
  1411. }
  1412. if (!registeredInterface) {
  1413. QByteArray msg;
  1414. msg += "Class ";
  1415. msg += def->classname;
  1416. msg += " implements the interface ";
  1417. msg += superClass;
  1418. msg += " but does not list it in Q_INTERFACES. qobject_cast to ";
  1419. msg += superClass;
  1420. msg += " will not work!";
  1421. warning(msg.constData());
  1422. }
  1423. }
  1424. }
  1425. }
  1426. void Moc::checkProperties

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