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

/src/qt/qtbase/src/tools/qdoc/qmlvisitor.cpp

https://gitlab.com/x33n/phantomjs
C++ | 693 lines | 517 code | 45 blank | 131 comment | 196 complexity | 0a38db254616ef001be88710801cc144 MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the tools applications of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include <qfileinfo.h>
  42. #include <qstringlist.h>
  43. #include <qglobal.h>
  44. #include "qqmljsast_p.h"
  45. #include "qqmljsastfwd_p.h"
  46. #include "qqmljsengine_p.h"
  47. #include <qdebug.h>
  48. #include "node.h"
  49. #include "codeparser.h"
  50. #include "qmlvisitor.h"
  51. #include "qdocdatabase.h"
  52. QT_BEGIN_NAMESPACE
  53. #define COMMAND_DEPRECATED Doc::alias(QLatin1String("deprecated"))
  54. #define COMMAND_INGROUP Doc::alias(QLatin1String("ingroup"))
  55. #define COMMAND_INTERNAL Doc::alias(QLatin1String("internal"))
  56. #define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete"))
  57. #define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords"))
  58. #define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary"))
  59. #define COMMAND_SINCE Doc::alias(QLatin1String("since"))
  60. #define COMMAND_WRAPPER Doc::alias(QLatin1String("wrapper"))
  61. #define COMMAND_QMLABSTRACT Doc::alias(QLatin1String("qmlabstract"))
  62. #define COMMAND_QMLCLASS Doc::alias(QLatin1String("qmlclass"))
  63. #define COMMAND_QMLTYPE Doc::alias(QLatin1String("qmltype"))
  64. #define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule"))
  65. #define COMMAND_QMLPROPERTY Doc::alias(QLatin1String("qmlproperty"))
  66. #define COMMAND_QMLPROPERTYGROUP Doc::alias(QLatin1String("qmlpropertygroup"))
  67. #define COMMAND_QMLATTACHEDPROPERTY Doc::alias(QLatin1String("qmlattachedproperty"))
  68. #define COMMAND_QMLINHERITS Doc::alias(QLatin1String("inherits"))
  69. #define COMMAND_QMLINSTANTIATES Doc::alias(QLatin1String("instantiates"))
  70. #define COMMAND_INQMLMODULE Doc::alias(QLatin1String("inqmlmodule"))
  71. #define COMMAND_QMLSIGNAL Doc::alias(QLatin1String("qmlsignal"))
  72. #define COMMAND_QMLATTACHEDSIGNAL Doc::alias(QLatin1String("qmlattachedsignal"))
  73. #define COMMAND_QMLMETHOD Doc::alias(QLatin1String("qmlmethod"))
  74. #define COMMAND_QMLATTACHEDMETHOD Doc::alias(QLatin1String("qmlattachedmethod"))
  75. #define COMMAND_QMLDEFAULT Doc::alias(QLatin1String("default"))
  76. #define COMMAND_QMLREADONLY Doc::alias(QLatin1String("readonly"))
  77. #define COMMAND_QMLBASICTYPE Doc::alias(QLatin1String("qmlbasictype"))
  78. /*!
  79. The constructor stores all the parameters in local data members.
  80. */
  81. QmlDocVisitor::QmlDocVisitor(const QString &filePath,
  82. const QString &code,
  83. QQmlJS::Engine *engine,
  84. const QSet<QString> &commands,
  85. const QSet<QString> &topics)
  86. : nestingLevel(0)
  87. {
  88. lastEndOffset = 0;
  89. this->filePath_ = filePath;
  90. this->name = QFileInfo(filePath).baseName();
  91. document = code;
  92. this->engine = engine;
  93. this->commands_ = commands;
  94. this->topics_ = topics;
  95. current = QDocDatabase::qdocDB()->treeRoot();
  96. }
  97. /*!
  98. The destructor does nothing.
  99. */
  100. QmlDocVisitor::~QmlDocVisitor()
  101. {
  102. // nothing.
  103. }
  104. /*!
  105. Returns the location of the nearest comment above the \a offset.
  106. */
  107. QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) const
  108. {
  109. QListIterator<QQmlJS::AST::SourceLocation> it(engine->comments());
  110. it.toBack();
  111. while (it.hasPrevious()) {
  112. QQmlJS::AST::SourceLocation loc = it.previous();
  113. if (loc.begin() <= lastEndOffset) {
  114. // Return if we reach the end of the preceding structure.
  115. break;
  116. }
  117. else if (usedComments.contains(loc.begin())) {
  118. // Return if we encounter a previously used comment.
  119. break;
  120. }
  121. else if (loc.begin() > lastEndOffset && loc.end() < offset) {
  122. // Only examine multiline comments in order to avoid snippet markers.
  123. if (document.at(loc.offset - 1) == QLatin1Char('*')) {
  124. QString comment = document.mid(loc.offset, loc.length);
  125. if (comment.startsWith(QLatin1Char('!')) || comment.startsWith(QLatin1Char('*'))) {
  126. return loc;
  127. }
  128. }
  129. }
  130. }
  131. return QQmlJS::AST::SourceLocation();
  132. }
  133. #if 0
  134. ArgList args;
  135. QSet<QString>::iterator i = metacommands.begin();
  136. while (i != metacommands.end()) {
  137. if (topics_.contains(*i)) {
  138. topic = *i;
  139. break;
  140. }
  141. ++i;
  142. }
  143. if (!topic.isEmpty()) {
  144. args = doc.metaCommandArgs(topic);
  145. if ((topic == COMMAND_QMLCLASS) || (topic == COMMAND_QMLTYPE)) {
  146. // do nothing.
  147. }
  148. else if (topic == COMMAND_QMLPROPERTY) {
  149. if (node->type() == Node::QmlProperty) {
  150. QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
  151. qpn->setReadOnly(0);
  152. if (qpn->dataType() == "alias") {
  153. QStringList part = args[0].first.split(QLatin1Char(' '));
  154. qpn->setDataType(part[0]);
  155. }
  156. }
  157. }
  158. else if (topic == COMMAND_QMLPROPERTYGROUP) {
  159. // zzz ?
  160. }
  161. else if (topic == COMMAND_QMLMODULE) {
  162. }
  163. else if (topic == COMMAND_QMLATTACHEDPROPERTY) {
  164. if (node->type() == Node::QmlProperty) {
  165. QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
  166. qpn->setReadOnly(0);
  167. }
  168. }
  169. else if (topic == COMMAND_QMLSIGNAL) {
  170. }
  171. else if (topic == COMMAND_QMLATTACHEDSIGNAL) {
  172. }
  173. else if (topic == COMMAND_QMLMETHOD) {
  174. }
  175. else if (topic == COMMAND_QMLATTACHEDMETHOD) {
  176. }
  177. else if (topic == COMMAND_QMLBASICTYPE) {
  178. }
  179. }
  180. if (node->type() == Node::QmlProperty) {
  181. QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
  182. for (int i=0; i<topicsUsed.size(); ++i) {
  183. if (topicsUsed.at(i).topic == "qmlproperty") {
  184. /*
  185. A \qmlproperty command would be used in a QML file
  186. to document the underlying property for a property
  187. alias.
  188. */
  189. QmlPropArgs qpa;
  190. if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) {
  191. QmlPropertyNode* n = parent->hasQmlPropertyNode(qpa.name_);
  192. if (n == 0)
  193. n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false);
  194. n->setLocation(doc.location());
  195. n->setReadOnly(qpn->isReadOnly());
  196. if (qpn->isDefault())
  197. n->setDefault();
  198. }
  199. else
  200. qDebug() << " FAILED TO PARSE QML PROPERTY:"
  201. << topicsUsed.at(i).topic << topicsUsed.at(i).args;
  202. }
  203. }
  204. }
  205. #endif
  206. /*!
  207. Finds the nearest unused qdoc comment above the QML entity
  208. represented by the \a node and processes the qdoc commands
  209. in that comment. The processed documentation is stored in
  210. the \a node.
  211. If a qdoc comment is found for \a location, true is returned.
  212. If a comment is not found there, false is returned.
  213. */
  214. bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Node* node)
  215. {
  216. QQmlJS::AST::SourceLocation loc = precedingComment(location.begin());
  217. if (loc.isValid()) {
  218. QString source = document.mid(loc.offset, loc.length);
  219. Location start(filePath_);
  220. start.setLineNo(loc.startLine);
  221. start.setColumnNo(loc.startColumn);
  222. Location finish(filePath_);
  223. finish.setLineNo(loc.startLine);
  224. finish.setColumnNo(loc.startColumn);
  225. Doc doc(start, finish, source.mid(1), commands_, topics_);
  226. const TopicList& topicsUsed = doc.topicsUsed();
  227. NodeList nodes;
  228. Node* nodePassedIn = node;
  229. InnerNode* parent = nodePassedIn->parent();
  230. node->setDoc(doc);
  231. nodes.append(node);
  232. if (topicsUsed.size() > 0) {
  233. for (int i=0; i<topicsUsed.size(); ++i) {
  234. if (topicsUsed.at(i).topic == QString("qmlpropertygroup")) {
  235. qDebug() << "PROPERTY GROUP COMMAND SEEN:" << topicsUsed.at(i).args << filePath_;
  236. break;
  237. }
  238. }
  239. for (int i=0; i<topicsUsed.size(); ++i) {
  240. QString topic = topicsUsed.at(i).topic;
  241. QString args = topicsUsed.at(i).args;
  242. if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY)) {
  243. QmlPropArgs qpa;
  244. if (splitQmlPropertyArg(doc, args, qpa)) {
  245. if (qpa.name_ == nodePassedIn->name()) {
  246. if (nodePassedIn->isAlias())
  247. nodePassedIn->setDataType(qpa.type_);
  248. }
  249. else {
  250. bool isAttached = (topic == COMMAND_QMLATTACHEDPROPERTY);
  251. QmlPropertyNode* n = parent->hasQmlProperty(qpa.name_);
  252. if (n == 0)
  253. n = new QmlPropertyNode(parent, qpa.name_, qpa.type_, isAttached);
  254. n->setLocation(doc.location());
  255. n->setDoc(doc);
  256. n->setReadOnly(nodePassedIn->isReadOnly());
  257. if (nodePassedIn->isDefault())
  258. n->setDefault();
  259. if (isAttached)
  260. n->setReadOnly(0);
  261. nodes.append(n);
  262. }
  263. }
  264. else
  265. qDebug() << " FAILED TO PARSE QML PROPERTY:" << topic << args;
  266. }
  267. }
  268. }
  269. for (int i=0; i<nodes.size(); ++i)
  270. applyMetacommands(loc, nodes.at(i), doc);
  271. usedComments.insert(loc.offset);
  272. if (doc.isEmpty()) {
  273. return false;
  274. }
  275. return true;
  276. }
  277. Location codeLoc(filePath_);
  278. codeLoc.setLineNo(location.startLine);
  279. node->setLocation(codeLoc);
  280. return false;
  281. }
  282. /*!
  283. A QML property argument has the form...
  284. <type> <component>::<name>
  285. <type> <QML-module>::<component>::<name>
  286. This function splits the argument into one of those
  287. two forms. The three part form is the old form, which
  288. was used before the creation of QtQuick 2 and Qt
  289. Components. A <QML-module> is the QML equivalent of a
  290. C++ namespace. So this function splits \a arg on "::"
  291. and stores the parts in the \e {type}, \e {module},
  292. \e {component}, and \a {name}, fields of \a qpa. If it
  293. is successful, it returns \c true. If not enough parts
  294. are found, a qdoc warning is emitted and false is
  295. returned.
  296. */
  297. bool QmlDocVisitor::splitQmlPropertyArg(const Doc& doc,
  298. const QString& arg,
  299. QmlPropArgs& qpa)
  300. {
  301. qpa.clear();
  302. QStringList blankSplit = arg.split(QLatin1Char(' '));
  303. if (blankSplit.size() > 1) {
  304. qpa.type_ = blankSplit[0];
  305. QStringList colonSplit(blankSplit[1].split("::"));
  306. if (colonSplit.size() == 3) {
  307. qpa.module_ = colonSplit[0];
  308. qpa.component_ = colonSplit[1];
  309. qpa.name_ = colonSplit[2];
  310. return true;
  311. }
  312. else if (colonSplit.size() == 2) {
  313. qpa.component_ = colonSplit[0];
  314. qpa.name_ = colonSplit[1];
  315. return true;
  316. }
  317. else if (colonSplit.size() == 1) {
  318. qpa.name_ = colonSplit[0];
  319. return true;
  320. }
  321. QString msg = "Unrecognizable QML module/component qualifier for " + arg;
  322. doc.location().warning(tr(msg.toLatin1().data()));
  323. }
  324. else {
  325. QString msg = "Missing property type for " + arg;
  326. doc.location().warning(tr(msg.toLatin1().data()));
  327. }
  328. return false;
  329. }
  330. /*!
  331. Applies the metacommands found in the comment.
  332. */
  333. void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
  334. Node* node,
  335. Doc& doc)
  336. {
  337. QDocDatabase* qdb = QDocDatabase::qdocDB();
  338. QSet<QString> metacommands = doc.metaCommandsUsed();
  339. if (metacommands.count() > 0) {
  340. metacommands.subtract(topics_);
  341. QSet<QString>::iterator i = metacommands.begin();
  342. while (i != metacommands.end()) {
  343. QString command = *i;
  344. ArgList args = doc.metaCommandArgs(command);
  345. if (command == COMMAND_QMLABSTRACT) {
  346. if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
  347. node->setAbstract(true);
  348. }
  349. }
  350. else if (command == COMMAND_DEPRECATED) {
  351. node->setStatus(Node::Obsolete);
  352. }
  353. else if (command == COMMAND_INQMLMODULE) {
  354. qdb->addToQmlModule(args[0].first,node);
  355. }
  356. else if (command == COMMAND_QMLINHERITS) {
  357. if (node->name() == args[0].first)
  358. doc.location().warning(tr("%1 tries to inherit itself").arg(args[0].first));
  359. else if (node->subType() == Node::QmlClass) {
  360. QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
  361. qmlClass->setQmlBaseName(args[0].first);
  362. QmlClassNode::addInheritedBy(args[0].first,node);
  363. }
  364. }
  365. else if (command == COMMAND_QMLDEFAULT) {
  366. if (node->type() == Node::QmlProperty) {
  367. QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
  368. qpn->setDefault();
  369. }
  370. }
  371. else if (command == COMMAND_QMLREADONLY) {
  372. if (node->type() == Node::QmlProperty) {
  373. QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
  374. qpn->setReadOnly(1);
  375. }
  376. }
  377. else if ((command == COMMAND_INGROUP) && !args.isEmpty()) {
  378. ArgList::ConstIterator argsIter = args.constBegin();
  379. while (argsIter != args.constEnd()) {
  380. QDocDatabase::qdocDB()->addToGroup(argsIter->first, node);
  381. ++argsIter;
  382. }
  383. }
  384. else if (command == COMMAND_INTERNAL) {
  385. node->setStatus(Node::Internal);
  386. }
  387. else if (command == COMMAND_OBSOLETE) {
  388. if (node->status() != Node::Compat)
  389. node->setStatus(Node::Obsolete);
  390. }
  391. else if (command == COMMAND_PAGEKEYWORDS) {
  392. // Not done yet. Do we need this?
  393. }
  394. else if (command == COMMAND_PRELIMINARY) {
  395. node->setStatus(Node::Preliminary);
  396. }
  397. else if (command == COMMAND_SINCE) {
  398. QString arg = args[0].first; //.join(' ');
  399. node->setSince(arg);
  400. }
  401. else if (command == COMMAND_WRAPPER) {
  402. node->setWrapper();
  403. }
  404. else {
  405. doc.location().warning(tr("The \\%1 command is ignored in QML files").arg(command));
  406. }
  407. ++i;
  408. }
  409. }
  410. }
  411. /*!
  412. Reconstruct the qualified \a id using dot notation
  413. and return the fully qualified string.
  414. */
  415. QString QmlDocVisitor::getFullyQualifiedId(QQmlJS::AST::UiQualifiedId *id)
  416. {
  417. QString result;
  418. if (id) {
  419. result = id->name.toString();
  420. id = id->next;
  421. while (id != 0) {
  422. result += QChar('.') + id->name.toString();
  423. id = id->next;
  424. }
  425. }
  426. return result;
  427. }
  428. /*!
  429. Begin the visit of the object \a definition, recording it in the
  430. qdoc database. Increment the object nesting level, which is used
  431. to test whether we are at the public API level. The public level
  432. is level 1.
  433. */
  434. bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
  435. {
  436. QString type = getFullyQualifiedId(definition->qualifiedTypeNameId);
  437. nestingLevel++;
  438. if (current->type() == Node::Namespace) {
  439. QmlClassNode *component = new QmlClassNode(current, name);
  440. component->setTitle(name);
  441. component->setImportList(importList);
  442. importList.clear();
  443. if (applyDocumentation(definition->firstSourceLocation(), component)) {
  444. QmlClassNode::addInheritedBy(type, component);
  445. component->setQmlBaseName(type);
  446. }
  447. current = component;
  448. }
  449. return true;
  450. }
  451. /*!
  452. End the visit of the object \a definition. In particular,
  453. decrement the object nesting level, which is used to test
  454. whether we are at the public API level. The public API
  455. level is level 1. It won't decrement below 0.
  456. */
  457. void QmlDocVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *definition)
  458. {
  459. if (nestingLevel > 0) {
  460. --nestingLevel;
  461. }
  462. lastEndOffset = definition->lastSourceLocation().end();
  463. }
  464. bool QmlDocVisitor::visit(QQmlJS::AST::UiImport *import)
  465. {
  466. QString name = document.mid(import->fileNameToken.offset, import->fileNameToken.length);
  467. if (name[0] == '\"')
  468. name = name.mid(1, name.length()-2);
  469. QString version = document.mid(import->versionToken.offset, import->versionToken.length);
  470. QString importId = document.mid(import->importIdToken.offset, import->importIdToken.length);
  471. QString importUri = getFullyQualifiedId(import->importUri);
  472. QString reconstructed = importUri + QString(" ") + version;
  473. importList.append(ImportRec(name, version, importId, importUri));
  474. return true;
  475. }
  476. void QmlDocVisitor::endVisit(QQmlJS::AST::UiImport *definition)
  477. {
  478. lastEndOffset = definition->lastSourceLocation().end();
  479. }
  480. bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectBinding *)
  481. {
  482. ++nestingLevel;
  483. return true;
  484. }
  485. void QmlDocVisitor::endVisit(QQmlJS::AST::UiObjectBinding *)
  486. {
  487. --nestingLevel;
  488. }
  489. bool QmlDocVisitor::visit(QQmlJS::AST::UiArrayBinding *)
  490. {
  491. return true;
  492. }
  493. void QmlDocVisitor::endVisit(QQmlJS::AST::UiArrayBinding *)
  494. {
  495. }
  496. /*!
  497. Visits the public \a member declaration, which can be a
  498. signal or a property. It is a custom signal or property.
  499. Only visit the \a member if the nestingLevel is 1.
  500. */
  501. bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
  502. {
  503. if (nestingLevel > 1) {
  504. return true;
  505. }
  506. switch (member->type) {
  507. case QQmlJS::AST::UiPublicMember::Signal:
  508. {
  509. if (current->type() == Node::Document) {
  510. QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
  511. if (qmlClass) {
  512. QString name = member->name.toString();
  513. FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false);
  514. QList<Parameter> parameters;
  515. for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
  516. if (!it->type.isEmpty() && !it->name.isEmpty())
  517. parameters.append(Parameter(it->type.toString(), QString(), it->name.toString()));
  518. }
  519. qmlSignal->setParameters(parameters);
  520. applyDocumentation(member->firstSourceLocation(), qmlSignal);
  521. }
  522. }
  523. break;
  524. }
  525. case QQmlJS::AST::UiPublicMember::Property:
  526. {
  527. QString type = member->memberType.toString();
  528. QString name = member->name.toString();
  529. if (current->type() == Node::Document) {
  530. QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
  531. if (qmlClass) {
  532. QString name = member->name.toString();
  533. QmlPropertyNode* qmlPropNode = qmlClass->hasQmlProperty(name);
  534. if (qmlPropNode == 0)
  535. qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false);
  536. qmlPropNode->setReadOnly(member->isReadonlyMember);
  537. if (member->isDefaultMember)
  538. qmlPropNode->setDefault();
  539. applyDocumentation(member->firstSourceLocation(), qmlPropNode);
  540. }
  541. }
  542. break;
  543. }
  544. default:
  545. return false;
  546. }
  547. return true;
  548. }
  549. /*!
  550. End the visit of the \a member.
  551. */
  552. void QmlDocVisitor::endVisit(QQmlJS::AST::UiPublicMember* member)
  553. {
  554. lastEndOffset = member->lastSourceLocation().end();
  555. }
  556. bool QmlDocVisitor::visit(QQmlJS::AST::IdentifierPropertyName *)
  557. {
  558. return true;
  559. }
  560. /*!
  561. Begin the visit of the function declaration \a fd, but only
  562. if the nesting level is 1.
  563. */
  564. bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
  565. {
  566. if (nestingLevel > 1) {
  567. return true;
  568. }
  569. if (current->type() == Node::Document) {
  570. QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
  571. if (qmlClass) {
  572. QString name = fd->name.toString();
  573. FunctionNode* qmlMethod = new FunctionNode(Node::QmlMethod, current, name, false);
  574. int overloads = 0;
  575. NodeList::ConstIterator overloadIterator = current->childNodes().constBegin();
  576. while (overloadIterator != current->childNodes().constEnd()) {
  577. if ((*overloadIterator)->name() == name)
  578. overloads++;
  579. overloadIterator++;
  580. }
  581. if (overloads > 1)
  582. qmlMethod->setOverload(true);
  583. QList<Parameter> parameters;
  584. QQmlJS::AST::FormalParameterList* formals = fd->formals;
  585. if (formals) {
  586. QQmlJS::AST::FormalParameterList* fpl = formals;
  587. do {
  588. parameters.append(Parameter(QString(), QString(), fpl->name.toString()));
  589. fpl = fpl->next;
  590. } while (fpl && fpl != formals);
  591. qmlMethod->setParameters(parameters);
  592. }
  593. applyDocumentation(fd->firstSourceLocation(), qmlMethod);
  594. }
  595. }
  596. return true;
  597. }
  598. /*!
  599. End the visit of the function declaration, \a fd.
  600. */
  601. void QmlDocVisitor::endVisit(QQmlJS::AST::FunctionDeclaration* fd)
  602. {
  603. lastEndOffset = fd->lastSourceLocation().end();
  604. }
  605. /*!
  606. Begin the visit of the signal handler declaration \a sb, but only
  607. if the nesting level is 1.
  608. This visit is now deprecated. It has been decided to document
  609. public signals. If a signal handler must be discussed in the
  610. documentation, that discussion must take place in the comment
  611. for the signal.
  612. */
  613. bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding* )
  614. {
  615. #if 0
  616. if (nestingLevel > 1) {
  617. return true;
  618. }
  619. if (current->type() == Node::Document) {
  620. QString handler = sb->qualifiedId->name.toString();
  621. if (handler.length() > 2 && handler.startsWith("on") && handler.at(2).isUpper()) {
  622. QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
  623. if (qmlClass) {
  624. FunctionNode* qmlSH = new FunctionNode(Node::QmlSignalHandler,current,handler,false);
  625. applyDocumentation(sb->firstSourceLocation(), qmlSH);
  626. }
  627. }
  628. }
  629. #endif
  630. return true;
  631. }
  632. void QmlDocVisitor::endVisit(QQmlJS::AST::UiScriptBinding* sb)
  633. {
  634. lastEndOffset = sb->lastSourceLocation().end();
  635. }
  636. bool QmlDocVisitor::visit(QQmlJS::AST::UiQualifiedId* )
  637. {
  638. return true;
  639. }
  640. void QmlDocVisitor::endVisit(QQmlJS::AST::UiQualifiedId* )
  641. {
  642. // nothing.
  643. }
  644. QT_END_NAMESPACE