PageRenderTime 49ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/qt-everywhere-opensource-src-4.7.1/src/tools/moc/moc.cpp

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