PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ExtMoc/moc.cpp

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