Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmlvisitor.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qmlvisitor.h"
5
6#include "aggregate.h"
7#include "codechunk.h"
8#include "codeparser.h"
9#include "functionnode.h"
10#include "node.h"
11#include "qdocdatabase.h"
13#include "tokenizer.h"
14#include "utilities.h"
15
16#include <QtCore/qdebug.h>
17#include <QtCore/qfileinfo.h>
18#include <QtCore/qglobal.h>
19
20#include <private/qqmljsast_p.h>
21#include <private/qqmljsengine_p.h>
22
24
25using namespace Qt::StringLiterals;
26
27/*!
28 The constructor stores all the parameters in local data members.
29 */
30QmlDocVisitor::QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine,
31 const QSet<QString> &commands, const QSet<QString> &topics)
33{
34 m_lastEndOffset = 0;
35 this->m_filePath = filePath;
36 this->m_name = QFileInfo(filePath).baseName();
37 m_document = code;
38 this->m_engine = engine;
39 this->m_commands = commands;
40 this->m_topics = topics;
42}
43
44/*!
45 Returns the location of the nearest comment above the \a offset.
46 */
47QQmlJS::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) const
48{
49 const auto comments = m_engine->comments();
50 for (auto it = comments.rbegin(); it != comments.rend(); ++it) {
51 QQmlJS::SourceLocation loc = *it;
52
53 if (loc.begin() <= m_lastEndOffset) {
54 // Return if we reach the end of the preceding structure.
55 break;
56 } else if (m_usedComments.contains(loc.begin())) {
57 // Return if we encounter a previously used comment.
58 break;
59 } else if (loc.begin() > m_lastEndOffset && loc.end() < offset) {
60 // Only examine multiline comments in order to avoid snippet markers.
61 if (m_document.at(loc.offset - 1) == QLatin1Char('*')) {
62 QString comment = m_document.mid(loc.offset, loc.length);
63 if (comment.startsWith(QLatin1Char('!')) || comment.startsWith(QLatin1Char('*'))) {
64 return loc;
65 }
66 }
67 }
68 }
69
70 return QQmlJS::SourceLocation();
71}
72
74{
75public:
76 QmlSignatureParser(FunctionNode *func, const QString &signature, const Location &loc);
77 void readToken() { tok_ = tokenizer_->getToken(); }
78 QString lexeme() { return tokenizer_->lexeme(); }
79 QString previousLexeme() { return tokenizer_->previousLexeme(); }
80
81 bool match(int target);
82 bool matchTypeAndName(CodeChunk *type, QString *var);
85
86private:
87 QString signature_;
88 QStringList names_;
89 Tokenizer *tokenizer_;
90 int tok_;
91 FunctionNode *func_;
92 const Location &location_;
93};
94
95/*!
96 Finds the nearest unused qdoc comment above the QML entity
97 represented by a \a node and processes the qdoc commands
98 in that comment. The processed documentation is stored in
99 \a node.
100
101 If \a node is a \c nullptr and there is a valid comment block,
102 the QML module identifier (\inqmlmodule argument) is used
103 for searching an existing QML type node. If an existing node
104 is not found, constructs a new QmlTypeNode instance.
105
106 Returns a pointer to the QmlTypeNode instance if one was
107 found or constructed. Otherwise, returns a pointer to the \a
108 node that was passed as an argument.
109 */
110Node *QmlDocVisitor::applyDocumentation(QQmlJS::SourceLocation location, Node *node)
111{
112 QQmlJS::SourceLocation loc = precedingComment(location.begin());
113 Location comment_loc(m_filePath);
114
115 // No preceding comment; construct a new QML type if
116 // needed.
117 if (!loc.isValid()) {
118 if (!node)
119 node = new QmlTypeNode(m_current, m_name, Node::QmlType);
120 comment_loc.setLineNo(location.startLine);
121 node->setLocation(comment_loc);
122 return node;
123 }
124
125 QString source = m_document.mid(loc.offset + 1, loc.length - 1);
126 comment_loc.setLineNo(loc.startLine);
127 comment_loc.setColumnNo(loc.startColumn);
128
129 Doc doc(comment_loc, comment_loc, source, m_commands, m_topics);
130 const TopicList &topicsUsed = doc.topicsUsed();
131 NodeList nodes;
132 if (!node) {
133 QString qmid;
134 if (auto args = doc.metaCommandArgs(COMMAND_INQMLMODULE); !args.isEmpty())
135 qmid = args.first().first;
136 node = QDocDatabase::qdocDB()->findQmlTypeInPrimaryTree(qmid, m_name);
137 if (!node) {
138 node = new QmlTypeNode(m_current, m_name, Node::QmlType);
139 node->setLocation(comment_loc);
140 }
141 }
142
143 auto *parent{node->parent()};
144 node->setDoc(doc);
145 nodes.append(node);
146 if (!topicsUsed.empty()) {
147 for (int i = 0; i < topicsUsed.size(); ++i) {
148 QString topic = topicsUsed.at(i).m_topic;
149 QString args = topicsUsed.at(i).m_args;
150 if (topic.endsWith(QLatin1String("property"))) {
151 auto *qmlProperty = static_cast<QmlPropertyNode *>(node);
152 QmlPropArgs qpa;
153 if (splitQmlPropertyArg(doc, args, qpa)) {
154 if (qpa.m_name == node->name()) {
155 if (qmlProperty->isAlias())
156 qmlProperty->setDataType(qpa.m_type);
157 } else {
158 bool isAttached = topic.contains(QLatin1String("attached"));
159 QmlPropertyNode *n = parent->hasQmlProperty(qpa.m_name, isAttached);
160 if (n == nullptr)
161 n = new QmlPropertyNode(parent, qpa.m_name, qpa.m_type, isAttached);
163 n->setDoc(doc);
164 // Use the const-overload of QmlPropertyNode::isReadOnly() as there's
165 // no associated C++ property to resolve the read-only status from
166 n->markReadOnly(const_cast<const QmlPropertyNode *>(qmlProperty)->isReadOnly()
167 && !isAttached);
168 if (qmlProperty->isDefault())
170 nodes.append(n);
171 }
172 } else
173 qCDebug(lcQdoc) << "Failed to parse QML property:" << topic << args;
174 } else if (topic.endsWith(QLatin1String("method")) || topic == COMMAND_QMLSIGNAL) {
175 if (node->isFunction()) {
176 auto *fn = static_cast<FunctionNode *>(node);
177 QmlSignatureParser qsp(fn, args, doc.location());
178 }
179 }
180 }
181 }
182 for (const auto &node : nodes)
183 applyMetacommands(loc, node, doc);
184
185 m_usedComments.insert(loc.offset);
186 return node;
187}
188
189QmlSignatureParser::QmlSignatureParser(FunctionNode *func, const QString &signature,
190 const Location &loc)
191 : signature_(signature), func_(func), location_(loc)
192{
193 QByteArray latin1 = signature.toLatin1();
194 Tokenizer stringTokenizer(location_, latin1);
195 stringTokenizer.setParsingFnOrMacro(true);
196 tokenizer_ = &stringTokenizer;
199}
200
201/*!
202 If the current token matches \a target, read the next
203 token and return true. Otherwise, don't read the next
204 token, and return false.
205 */
206bool QmlSignatureParser::match(int target)
207{
208 if (tok_ == target) {
210 return true;
211 }
212 return false;
213}
214
215/*!
216 Parse a QML data type into \a type and an optional
217 variable name into \a var.
218 */
219bool QmlSignatureParser::matchTypeAndName(CodeChunk *type, QString *var)
220{
221 /*
222 This code is really hard to follow... sorry. The loop is there to match
223 Alpha::Beta::Gamma::...::Omega.
224 */
225 for (;;) {
226 bool virgin = true;
227
228 if (tok_ != Tok_Ident) {
230 || match(Tok_int64)) {
231 type->append(previousLexeme());
232 virgin = false;
233 }
234 }
235
236 if (virgin) {
237 if (match(Tok_Ident)) {
238 type->append(previousLexeme());
241 type->append(previousLexeme());
242 else
243 return false;
245 type->append(previousLexeme());
246 }
247
249 type->append(previousLexeme());
250 else
251 break;
252 }
253
254 while (match(Tok_Ampersand) || match(Tok_Aster) || match(Tok_const) || match(Tok_Caret))
255 type->append(previousLexeme());
256
257 /*
258 The usual case: Look for an optional identifier, then for
259 some array brackets.
260 */
261 type->appendHotspot();
262
263 if ((var != nullptr) && match(Tok_Ident))
264 *var = previousLexeme();
265
266 if (tok_ == Tok_LeftBracket) {
267 int bracketDepth0 = tokenizer_->bracketDepth();
268 while ((tokenizer_->bracketDepth() >= bracketDepth0 && tok_ != Tok_Eoi)
269 || tok_ == Tok_RightBracket) {
270 type->append(lexeme());
272 }
273 }
274 return true;
275}
276
278{
279 QString name;
280 CodeChunk type;
281 CodeChunk defaultValue;
282
283 bool result = matchTypeAndName(&type, &name);
284 if (name.isEmpty()) {
285 name = type.toString();
286 type.clear();
287 }
288
289 if (!result)
290 return false;
291 if (match(Tok_Equal)) {
292 int parenDepth0 = tokenizer_->parenDepth();
293 while (tokenizer_->parenDepth() >= parenDepth0
294 && (tok_ != Tok_Comma || tokenizer_->parenDepth() > parenDepth0)
295 && tok_ != Tok_Eoi) {
296 defaultValue.append(lexeme());
298 }
299 }
300 func_->parameters().append(type.toString(), name, defaultValue.toString());
301 return true;
302}
303
305{
306 CodeChunk returnType;
307
308 qsizetype firstBlank = signature_.indexOf(QChar(' '));
309 qsizetype leftParen = signature_.indexOf(QChar('('));
310 if ((firstBlank > 0) && (leftParen - firstBlank) > 1) {
311 if (!matchTypeAndName(&returnType, nullptr))
312 return false;
313 }
314
315 while (match(Tok_Ident)) {
316 names_.append(previousLexeme());
318 previousLexeme();
319 names_.pop_back();
320 break;
321 }
322 }
323
324 if (tok_ != Tok_LeftParen)
325 return false;
326 /*
327 Parsing the parameters should be moved into class Parameters,
328 but it can wait. mws 14/12/2018
329 */
331
332 func_->setLocation(location_);
333 func_->setReturnType(returnType.toString());
334
335 if (tok_ != Tok_RightParen) {
337 do {
338 if (!matchParameter())
339 return false;
340 } while (match(Tok_Comma));
341 }
343 return false;
344 return true;
345}
346
347/*!
348 A QML property argument has the form...
349
350 <type> <component>::<name>
351 <type> <QML-module>::<component>::<name>
352
353 This function splits the argument into one of those
354 two forms. The three part form is the old form, which
355 was used before the creation of QtQuick 2 and Qt
356 Components. A <QML-module> is the QML equivalent of a
357 C++ namespace. So this function splits \a arg on "::"
358 and stores the parts in the \e {type}, \e {module},
359 \e {component}, and \a {name}, fields of \a qpa. If it
360 is successful, it returns \c true. If not enough parts
361 are found, a qdoc warning is emitted and false is
362 returned.
363 */
364bool QmlDocVisitor::splitQmlPropertyArg(const Doc &doc, const QString &arg, QmlPropArgs &qpa)
365{
366 qpa.clear();
367 QStringList blankSplit = arg.split(QLatin1Char(' '));
368 if (blankSplit.size() > 1) {
369 qpa.m_type = blankSplit[0];
370 QStringList colonSplit(blankSplit[1].split("::"));
371 if (colonSplit.size() == 3) {
372 qpa.m_module = colonSplit[0];
373 qpa.m_component = colonSplit[1];
374 qpa.m_name = colonSplit[2];
375 return true;
376 } else if (colonSplit.size() == 2) {
377 qpa.m_component = colonSplit[0];
378 qpa.m_name = colonSplit[1];
379 return true;
380 } else if (colonSplit.size() == 1) {
381 qpa.m_name = colonSplit[0];
382 return true;
383 }
384 doc.location().warning(
385 QStringLiteral("Unrecognizable QML module/component qualifier for %1.").arg(arg));
386 } else {
387 doc.location().warning(QStringLiteral("Missing property type for %1.").arg(arg));
388 }
389 return false;
390}
391
392/*!
393 Applies the metacommands found in the comment.
394 */
395void QmlDocVisitor::applyMetacommands(QQmlJS::SourceLocation, Node *node, Doc &doc)
396{
398 QSet<QString> metacommands = doc.metaCommandsUsed();
399 if (metacommands.size() > 0) {
400 metacommands.subtract(m_topics);
401 for (const auto &command : std::as_const(metacommands)) {
402 const ArgList args = doc.metaCommandArgs(command);
403 if ((command == COMMAND_QMLABSTRACT) || (command == COMMAND_ABSTRACT)) {
404 if (node->isQmlType()) {
405 node->setAbstract(true);
406 }
407 } else if (command == COMMAND_DEPRECATED) {
408 node->setDeprecated(args[0].second);
409 } else if (command == COMMAND_INQMLMODULE) {
410 qdb->addToQmlModule(args[0].first, node);
411 } else if (command == COMMAND_QMLINHERITS) {
412 if (node->name() == args[0].first)
413 doc.location().warning(
414 QStringLiteral("%1 tries to inherit itself").arg(args[0].first));
415 else if (node->isQmlType()) {
416 auto *qmlType = static_cast<QmlTypeNode *>(node);
417 qmlType->setQmlBaseName(args[0].first);
418 }
419 } else if (command == COMMAND_DEFAULT) {
420 if (!node->isQmlProperty()) {
421 doc.location().warning(QStringLiteral("Ignored '\\%1', applies only to '\\%2'")
422 .arg(command, COMMAND_QMLPROPERTY));
423 } else if (args.isEmpty() || args[0].first.isEmpty()) {
424 doc.location().warning(QStringLiteral("Expected an argument for '\\%1' (maybe you meant '\\%2'?)")
425 .arg(command, COMMAND_QMLDEFAULT));
426 } else {
427 static_cast<QmlPropertyNode *>(node)->setDefaultValue(args[0].first);
428 }
429 } else if (command == COMMAND_QMLDEFAULT) {
430 node->markDefault();
431 } else if (command == COMMAND_QMLENUMERATORSFROM) {
432 if (!node->isQmlProperty()) {
433 doc.location().warning("Ignored '\\%1', applies only to '\\%2'"_L1
434 .arg(command, COMMAND_QMLPROPERTY));
435 } else if (!static_cast<QmlPropertyNode*>(node)->setEnumNode(args[0].first, args[0].second)) {
436 doc.location().warning("Failed to find C++ enumeration '%2' passed to \\%1"_L1
437 .arg(command, args[0].first), "Use \\value commands instead"_L1);
438 }
439 } else if (command == COMMAND_QMLREADONLY) {
440 node->markReadOnly(1);
441 } else if (command == COMMAND_QMLREQUIRED) {
442 if (node->isQmlProperty())
443 static_cast<QmlPropertyNode *>(node)->setRequired();
444 } else if ((command == COMMAND_INGROUP) && !args.isEmpty()) {
445 for (const auto &argument : args)
446 QDocDatabase::qdocDB()->addToGroup(argument.first, node);
447 } else if (command == COMMAND_INTERNAL) {
448 node->setStatus(Node::Internal);
449 } else if (command == COMMAND_OBSOLETE) {
450 node->setStatus(Node::Deprecated);
451 } else if (command == COMMAND_PRELIMINARY) {
452 node->setStatus(Node::Preliminary);
453 } else if (command == COMMAND_SINCE) {
454 QString arg = args[0].first; //.join(' ');
455 node->setSince(arg);
456 } else if (command == COMMAND_WRAPPER) {
457 node->setWrapper();
458 } else {
459 doc.location().warning(
460 QStringLiteral("The \\%1 command is ignored in QML files").arg(command));
461 }
462 }
463 }
464}
465
466/*!
467 Reconstruct the qualified \a id using dot notation
468 and return the fully qualified string.
469 */
470QString QmlDocVisitor::getFullyQualifiedId(QQmlJS::AST::UiQualifiedId *id)
471{
472 QString result;
473 if (id) {
474 result = id->name.toString();
475 id = id->next;
476 while (id != nullptr) {
477 result += QChar('.') + id->name.toString();
478 id = id->next;
479 }
480 }
481 return result;
482}
483
484/*!
485 Begin the visit of the object \a definition, recording it in the
486 qdoc database. Increment the object nesting level, which is used
487 to test whether we are at the public API level. The public level
488 is level 1.
489
490 Defers the construction of a QmlTypeNode instance to
491 applyDocumentation(), by passing \c nullptr as the second
492 argument.
493 */
494bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
495{
496 QString type = getFullyQualifiedId(definition->qualifiedTypeNameId);
497 m_nestingLevel++;
498 if (m_current->isNamespace()) {
499 auto component = applyDocumentation(definition->firstSourceLocation(), nullptr);
500 Q_ASSERT(component);
501 auto *qmlTypeNode = static_cast<QmlTypeNode *>(component);
502 if (!component->doc().isEmpty())
503 qmlTypeNode->setQmlBaseName(type);
504 qmlTypeNode->setTitle(m_name);
505 qmlTypeNode->setImportList(m_importList);
506 m_importList.clear();
507 m_current = qmlTypeNode;
508 }
509
510 return true;
511}
512
513/*!
514 End the visit of the object \a definition. In particular,
515 decrement the object nesting level, which is used to test
516 whether we are at the public API level. The public API
517 level is level 1. It won't decrement below 0.
518 */
519void QmlDocVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *definition)
520{
521 if (m_nestingLevel > 0) {
522 --m_nestingLevel;
523 }
524 m_lastEndOffset = definition->lastSourceLocation().end();
525}
526
527bool QmlDocVisitor::visit(QQmlJS::AST::UiImport *import)
528{
529 QString name = m_document.mid(import->fileNameToken.offset, import->fileNameToken.length);
530 if (name[0] == '\"')
531 name = name.mid(1, name.size() - 2);
532 QString version;
533 if (import->version) {
534 const auto start = import->version->firstSourceLocation().begin();
535 const auto end = import->version->lastSourceLocation().end();
536 version = m_document.mid(start, end - start);
537 }
538 QString importUri = getFullyQualifiedId(import->importUri);
539 m_importList.append(ImportRec(name, version, importUri));
540
541 return true;
542}
543
544void QmlDocVisitor::endVisit(QQmlJS::AST::UiImport *definition)
545{
546 m_lastEndOffset = definition->lastSourceLocation().end();
547}
548
549bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectBinding *)
550{
551 ++m_nestingLevel;
552 return true;
553}
554
555void QmlDocVisitor::endVisit(QQmlJS::AST::UiObjectBinding *)
556{
557 --m_nestingLevel;
558}
559
560bool QmlDocVisitor::visit(QQmlJS::AST::UiArrayBinding *)
561{
562 return true;
563}
564
565void QmlDocVisitor::endVisit(QQmlJS::AST::UiArrayBinding *) {}
566
567static QString qualifiedIdToString(QQmlJS::AST::UiQualifiedId *node)
568{
569 QString s;
570
571 for (QQmlJS::AST::UiQualifiedId *it = node; it; it = it->next) {
572 s.append(it->name);
573
574 if (it->next)
575 s.append(QLatin1Char('.'));
576 }
577
578 return s;
579}
580
581/*!
582 Visits the public \a member declaration, which can be a
583 signal or a property. It is a custom signal or property.
584 Only visit the \a member if the nestingLevel is 1.
585 */
586bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
587{
588 if (m_nestingLevel > 1) {
589 return true;
590 }
591 switch (member->type) {
592 case QQmlJS::AST::UiPublicMember::Signal: {
593 if (m_current->isQmlType()) {
594 auto *qmlType = static_cast<QmlTypeNode *>(m_current);
595 if (qmlType) {
597 QString name = member->name.toString();
598 auto *newSignal = new FunctionNode(metaness, m_current, name);
599 Parameters &parameters = newSignal->parameters();
600 for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
601 const QString type = it->type ? it->type->toString() : QString();
602 if (!type.isEmpty() && !it->name.isEmpty())
603 parameters.append(type, it->name.toString());
604 }
605 applyDocumentation(member->firstSourceLocation(), newSignal);
606 }
607 }
608 break;
609 }
610 case QQmlJS::AST::UiPublicMember::Property: {
611 QString type = qualifiedIdToString(member->memberType);
612 if (m_current->isQmlType()) {
613 auto *qmlType = static_cast<QmlTypeNode *>(m_current);
614 if (qmlType) {
615 QString name = member->name.toString();
616 QmlPropertyNode *qmlPropNode = qmlType->hasQmlProperty(name);
617 if (qmlPropNode == nullptr)
618 qmlPropNode = new QmlPropertyNode(qmlType, name, type, false);
619 qmlPropNode->markReadOnly(member->isReadonly());
620 if (member->isDefaultMember())
621 qmlPropNode->markDefault();
622 if (member->requiredToken().isValid())
623 qmlPropNode->setRequired();
624 applyDocumentation(member->firstSourceLocation(), qmlPropNode);
625 }
626 }
627 break;
628 }
629 default:
630 return false;
631 }
632
633 return true;
634}
635
636/*!
637 End the visit of the \a member.
638 */
639void QmlDocVisitor::endVisit(QQmlJS::AST::UiPublicMember *member)
640{
641 m_lastEndOffset = member->lastSourceLocation().end();
642}
643
644bool QmlDocVisitor::visit(QQmlJS::AST::IdentifierPropertyName *)
645{
646 return true;
647}
648
649/*!
650 Begin the visit of the function declaration \a fd, but only
651 if the nesting level is 1.
652 */
653bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration *fd)
654{
655 if (m_nestingLevel <= 1) {
657 if (!m_current->isQmlType())
658 return true;
659 QString name = fd->name.toString();
660 auto *method = new FunctionNode(metaness, m_current, name);
661 Parameters &parameters = method->parameters();
662 QQmlJS::AST::FormalParameterList *formals = fd->formals;
663 if (formals) {
664 QQmlJS::AST::FormalParameterList *fp = formals;
665 do {
666 QString defaultValue;
667 auto initializer = fp->element->initializer;
668 if (initializer) {
669 auto loc = initializer->firstSourceLocation();
670 defaultValue = m_document.mid(loc.begin(), loc.length);
671 }
672 parameters.append(QString(), fp->element->bindingIdentifier.toString(),
673 defaultValue);
674 fp = fp->next;
675 } while (fp && fp != formals);
676 }
677 applyDocumentation(fd->firstSourceLocation(), method);
678 }
679 return true;
680}
681
682/*!
683 End the visit of the function declaration, \a fd.
684 */
685void QmlDocVisitor::endVisit(QQmlJS::AST::FunctionDeclaration *fd)
686{
687 m_lastEndOffset = fd->lastSourceLocation().end();
688}
689
690/*!
691 Begin the visit of the signal handler declaration \a sb, but only
692 if the nesting level is 1.
693
694 This visit is now deprecated. It has been decided to document
695 public signals. If a signal handler must be discussed in the
696 documentation, that discussion must take place in the comment
697 for the signal.
698 */
699bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding *)
700{
701 return true;
702}
703
704void QmlDocVisitor::endVisit(QQmlJS::AST::UiScriptBinding *sb)
705{
706 m_lastEndOffset = sb->lastSourceLocation().end();
707}
708
709bool QmlDocVisitor::visit(QQmlJS::AST::UiQualifiedId *)
710{
711 return true;
712}
713
714void QmlDocVisitor::endVisit(QQmlJS::AST::UiQualifiedId *)
715{
716 // nothing.
717}
718
720{
721 hasRecursionDepthError = true;
722}
723
725{
726 return hasRecursionDepthError;
727}
728
729QT_END_NAMESPACE
Definition doc.h:31
const Location & location() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:90
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
Definition doc.cpp:238
This node is used to represent any kind of function being documented.
Parameters & parameters()
The Location class provides a way to mark a location in a file.
Definition location.h:15
void setColumnNo(int no)
Definition location.h:36
void setLineNo(int no)
Definition location.h:35
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:143
bool isFunction(Genus g=DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:135
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:155
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:244
void setLocation(const Location &t)
Sets the node's declaration location, its definition location, or both, depending on the suffix of th...
Definition node.cpp:886
void setDoc(const Doc &doc, bool replace=false)
Sets this Node's Doc to doc.
Definition node.cpp:546
LinkType
An unsigned char value that probably should be moved out of the Node base class.
Definition node.h:112
A class for parsing and managing a function parameter list.
Definition parameters.h:57
void clear()
Definition parameters.h:62
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
bool visit(QQmlJS::AST::UiImport *import) override
void throwRecursionDepthError() final
void endVisit(QQmlJS::AST::UiImport *definition) override
bool hasError() const
QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine, const QSet< QString > &commands, const QSet< QString > &topics)
The constructor stores all the parameters in local data members.
bool isDefault() const override
Returns true if the QML property node is marked as default.
void markReadOnly(bool flag) override
If this node is a QmlPropertyNode, then the property's read-only flag is set to flag.
void markDefault() override
If this node is a QmlPropertyNode, it is marked as the default property.
bool isReadOnly() const
Returns true if this QML property node is marked as a read-only property.
bool isAlias() const override
Returns true if this QML property is marked as an alias.
QString previousLexeme()
bool match(int target)
If the current token matches target, read the next token and return true.
QmlSignatureParser(FunctionNode *func, const QString &signature, const Location &loc)
bool matchTypeAndName(CodeChunk *type, QString *var)
Parse a QML data type into type and an optional variable name into var.
QString previousLexeme() const
int getToken()
int parenDepth() const
Definition tokenizer.h:94
QString lexeme() const
int bracketDepth() const
Definition tokenizer.h:95
void setParsingFnOrMacro(bool macro)
Definition tokenizer.h:88
#define COMMAND_QMLINHERITS
Definition codeparser.h:56
#define COMMAND_INTERNAL
Definition codeparser.h:34
#define COMMAND_QMLSIGNAL
Definition codeparser.h:65
#define COMMAND_OBSOLETE
Definition codeparser.h:42
#define COMMAND_DEPRECATED
Definition codeparser.h:21
#define COMMAND_PRELIMINARY
Definition codeparser.h:45
#define COMMAND_WRAPPER
Definition codeparser.h:84
#define COMMAND_QMLPROPERTY
Definition codeparser.h:61
#define COMMAND_QMLDEFAULT
Definition codeparser.h:54
#define COMMAND_SINCE
Definition codeparser.h:73
#define COMMAND_QMLABSTRACT
Definition codeparser.h:48
#define COMMAND_DEFAULT
Definition codeparser.h:20
#define COMMAND_QMLREADONLY
Definition codeparser.h:63
#define COMMAND_QMLENUMERATORSFROM
Definition codeparser.h:55
#define COMMAND_QMLREQUIRED
Definition codeparser.h:64
#define COMMAND_ABSTRACT
Definition codeparser.h:13
#define COMMAND_INQMLMODULE
Definition codeparser.h:33
#define COMMAND_INGROUP
Definition codeparser.h:29
Combined button and popup list for selecting options.
QList< Node * > NodeList
Definition node.h:41
static QString qualifiedIdToString(QQmlJS::AST::UiQualifiedId *node)
void clear()
Definition qmlvisitor.h:26
@ Tok_Eoi
Definition tokenizer.h:24
@ Tok_void
Definition tokenizer.h:62
@ Tok_int64
Definition tokenizer.h:64
@ Tok_unsigned
Definition tokenizer.h:61
@ Tok_RightParen
Definition tokenizer.h:29
@ Tok_char
Definition tokenizer.h:51
@ Tok_short
Definition tokenizer.h:58
@ Tok_Ellipsis
Definition tokenizer.h:39
@ Tok_Gulbrandsen
Definition tokenizer.h:40
@ Tok_Equal
Definition tokenizer.h:31
@ Tok_int
Definition tokenizer.h:55
@ Tok_long
Definition tokenizer.h:56
@ Tok_LeftBracket
Definition tokenizer.h:41
@ Tok_Comma
Definition tokenizer.h:38
@ Tok_Ident
Definition tokenizer.h:49
@ Tok_double
Definition tokenizer.h:54
@ Tok_LeftParen
Definition tokenizer.h:28
@ Tok_RightBracket
Definition tokenizer.h:42
@ Tok_signed
Definition tokenizer.h:59
QList< Topic > TopicList
Definition topic.h:25