8#include <QtCore/qglobal.h>
9#include <QtCore/qstringlist.h>
11#include <private/qqmljsast_p.h>
12#include <private/qqmljsengine_p.h>
14using namespace Qt::StringLiterals;
18QmlMarkupVisitor::QmlMarkupVisitor(
const QString &source,
19 const QList<QQmlJS::SourceLocation> &pragmas,
20 QQmlJS::Engine *engine)
22 this->m_source = source;
23 this->m_engine = engine;
31 const QList<QQmlJS::SourceLocation> comments = engine->comments();
32 while (i < comments.size() && j < pragmas.size()) {
33 if (comments[i].offset < pragmas[j].offset) {
34 m_extraTypes.append(Comment);
35 m_extraLocations.append(comments[i]);
38 m_extraTypes.append(Pragma);
39 m_extraLocations.append(comments[j]);
44 while (i < comments.size()) {
45 m_extraTypes.append(Comment);
46 m_extraLocations.append(comments[i]);
50 while (j < pragmas.size()) {
51 m_extraTypes.append(Pragma);
52 m_extraLocations.append(pragmas[j]);
59 if (
int(m_cursor) < m_source.size())
60 addExtra(m_cursor, m_source.size());
67 return m_hasRecursionDepthError;
72 if (m_extraIndex >= m_extraLocations.size()) {
73 QString extra = m_source.mid(start, finish - start);
74 if (extra.trimmed().isEmpty())
77 m_output += Utilities::protect(extra);
83 while (m_extraIndex < m_extraLocations.size()) {
84 if (m_extraTypes[m_extraIndex] == Comment) {
85 if (m_extraLocations[m_extraIndex].offset - 2 >= start)
88 if (m_extraLocations[m_extraIndex].offset >= start)
95 while (i < finish && m_extraIndex < m_extraLocations.size()) {
96 quint32 j = m_extraLocations[m_extraIndex].offset - 2;
97 if (i <= j && j < finish) {
99 m_output += Utilities::protect(m_source.mid(i, j - i));
101 quint32 l = m_extraLocations[m_extraIndex].length;
102 if (m_extraTypes[m_extraIndex] == Comment) {
103 if (m_source.mid(j, 2) ==
"/*"_L1)
107 m_output +=
"<@comment>"_L1;
108 m_output += Utilities::protect(m_source.mid(j, l));
109 m_output +=
"</@comment>"_L1;
111 m_output += Utilities::protect(m_source.mid(j, l));
119 QString extra = m_source.mid(i, finish - i);
120 if (extra.trimmed().isEmpty())
123 m_output += Utilities::protect(extra);
128void QmlMarkupVisitor::addMarkedUpToken(
const QQmlJS::SourceLocation &location,
129 const QString &tagName,
130 const QHash<QString, QString> &attributes)
132 if (!location.isValid())
135 if (m_cursor < location.offset)
136 addExtra(m_cursor, location.offset);
137 else if (m_cursor > location.offset)
140 m_output +=
"<@%1"_L1.arg(tagName);
141 for (
const auto &key : attributes)
142 m_output +=
" %1=\"%2\""_L1.arg(key, attributes[key]);
143 m_output +=
">%2</@%3>"_L1.arg(Utilities::protect(sourceText(location)), tagName);
144 m_cursor += location.length;
149 return m_source.mid(location.offset, location.length);
153
154
155
156
157
158
159
160
161std::optional<QQmlJS::SourceLocation>
162QmlMarkupVisitor::getFullyQualifiedLocation(QQmlJS::AST::UiQualifiedId *id) {
163 if (!id || !id->identifierToken.isValid())
166 auto location = id->identifierToken;
168 for (
auto current = id->next; current; current = current->next) {
169 if (!current->identifierToken.isValid())
172 const auto currentEnd = current->identifierToken.offset + current->identifierToken.length;
173 location.length = currentEnd - location.offset;
180
181
182
183
184
185QQmlJS::SourceLocation
188 if (
auto fullLocation = getFullyQualifiedLocation(id))
189 return fullLocation.value();
190 return id->identifierToken;
194 QQmlJS::SourceLocation last)
196 if (!first.isValid())
199 quint32 start = first.begin();
204 finish = first.end();
206 if (m_cursor < start)
207 addExtra(m_cursor, start);
208 else if (m_cursor > start)
211 QString text = m_source.mid(start, finish - start);
212 m_output += Utilities::protect(text);
218 addVerbatim(uiimport->importToken);
219 if (!uiimport->importUri)
220 addMarkedUpToken(uiimport->fileNameToken,
"headerfile"_L1);
226 if (uiimport->version)
227 addVerbatim(uiimport->version->firstSourceLocation(),
228 uiimport->version->lastSourceLocation());
229 addVerbatim(uiimport->asToken);
230 addMarkedUpToken(uiimport->importIdToken,
"headerfile"_L1);
231 addVerbatim(uiimport->semicolonToken);
236 if (member->type == QQmlJS::AST::UiPublicMember::Property) {
237 addVerbatim(member->defaultToken());
238 addVerbatim(member->readonlyToken());
239 addVerbatim(member->propertyToken());
240 addVerbatim(member->typeModifierToken);
241 addMarkedUpToken(member->typeToken,
"type"_L1);
242 addMarkedUpToken(member->identifierToken,
"name"_L1);
243 addVerbatim(member->colonToken);
245 QQmlJS::AST::Node::accept(member->binding,
this);
246 else if (member->statement)
247 QQmlJS::AST::Node::accept(member->statement,
this);
249 addVerbatim(member->propertyToken());
250 addVerbatim(member->typeModifierToken);
251 addMarkedUpToken(member->typeToken,
"type"_L1);
253 QQmlJS::AST::Node::accept(member->parameters,
this);
255 addVerbatim(member->semicolonToken);
261 addVerbatim(initializer->lbraceToken, initializer->lbraceToken);
267 addVerbatim(initializer->rbraceToken, initializer->rbraceToken);
272 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
273 addVerbatim(binding->colonToken);
274 if (
auto fullLocation = getFullyQualifiedLocation(binding->qualifiedTypeNameId))
275 addMarkedUpToken(fullLocation.value(),
"type"_L1);
277 QQmlJS::AST::Node::accept(binding->qualifiedTypeNameId,
this);
279 QQmlJS::AST::Node::accept(binding->initializer,
this);
285 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
286 addVerbatim(binding->colonToken);
287 QQmlJS::AST::Node::accept(binding->statement,
this);
293 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
294 addVerbatim(binding->colonToken);
295 addVerbatim(binding->lbracketToken);
296 QQmlJS::AST::Node::accept(binding->members,
this);
297 addVerbatim(binding->rbracketToken);
303 for (QQmlJS::AST::UiArrayMemberList *it = list; it; it = it->next) {
304 QQmlJS::AST::Node::accept(it->member,
this);
312 addMarkedUpToken(getLocationForMarkup(id),
"name"_L1);
318 addVerbatim(expression->thisToken);
324 addMarkedUpToken(identifier->identifierToken,
"name"_L1);
330 addMarkedUpToken(null->nullToken,
"number"_L1);
336 addMarkedUpToken(literal->trueToken,
"number"_L1);
342 addMarkedUpToken(literal->falseToken,
"number"_L1);
348 addMarkedUpToken(literal->literalToken,
"number"_L1);
354 addMarkedUpToken(literal->literalToken,
"string"_L1);
360 addVerbatim(literal->literalToken);
366 addVerbatim(literal->lbracketToken);
367 QQmlJS::AST::Node::accept(literal->elements,
this);
368 addVerbatim(literal->rbracketToken);
374 addVerbatim(literal->lbraceToken);
380 addVerbatim(literal->rbraceToken);
385 for (QQmlJS::AST::PatternElementList *it = list; it; it = it->next) {
386 QQmlJS::AST::Node::accept(it->element,
this);
389 QQmlJS::AST::Node::accept(list->elision,
this);
395 addVerbatim(elision->commaToken, elision->commaToken);
401 QQmlJS::AST::Node::accept(list->name,
this);
402 addVerbatim(list->colonToken, list->colonToken);
403 QQmlJS::AST::Node::accept(list->initializer,
this);
410 QQmlJS::AST::Node::accept(expression->base,
this);
411 addVerbatim(expression->lbracketToken);
412 QQmlJS::AST::Node::accept(expression->expression,
this);
413 addVerbatim(expression->rbracketToken);
419 QQmlJS::AST::Node::accept(expression->base,
this);
420 addVerbatim(expression->dotToken);
421 addMarkedUpToken(expression->identifierToken,
"name"_L1);
427 addVerbatim(expression->newToken);
428 QQmlJS::AST::Node::accept(expression->base,
this);
429 addVerbatim(expression->lparenToken);
430 QQmlJS::AST::Node::accept(expression->arguments,
this);
431 addVerbatim(expression->rparenToken);
437 addVerbatim(expression->newToken);
443 addVerbatim(list->commaToken, list->commaToken);
449 addVerbatim(expression->incrementToken);
455 addVerbatim(expression->decrementToken);
461 addVerbatim(expression->deleteToken);
467 addVerbatim(expression->voidToken);
473 addVerbatim(expression->typeofToken);
479 addVerbatim(expression->incrementToken);
485 addVerbatim(expression->decrementToken);
491 addVerbatim(expression->plusToken);
497 addVerbatim(expression->minusToken);
503 addVerbatim(expression->tildeToken);
509 addVerbatim(expression->notToken);
515 QQmlJS::AST::Node::accept(expression->left,
this);
516 addMarkedUpToken(expression->operatorToken,
"op"_L1);
517 QQmlJS::AST::Node::accept(expression->right,
this);
523 QQmlJS::AST::Node::accept(expression->expression,
this);
524 addVerbatim(expression->questionToken);
525 QQmlJS::AST::Node::accept(expression->ok,
this);
526 addVerbatim(expression->colonToken);
527 QQmlJS::AST::Node::accept(expression->ko,
this);
533 QQmlJS::AST::Node::accept(expression->left,
this);
534 addVerbatim(expression->commaToken);
535 QQmlJS::AST::Node::accept(expression->right,
this);
541 addVerbatim(block->lbraceToken);
547 addVerbatim(block->rbraceToken);
552 addVerbatim(statement->declarationKindToken);
553 QQmlJS::AST::Node::accept(statement->declarations,
this);
560 for (QQmlJS::AST::VariableDeclarationList *it = list; it; it = it->next) {
561 QQmlJS::AST::Node::accept(it->declaration,
this);
562 addVerbatim(it->commaToken);
569 addVerbatim(statement->semicolonToken);
575 QQmlJS::AST::Node::accept(statement->expression,
this);
576 addVerbatim(statement->semicolonToken);
582 addMarkedUpToken(statement->ifToken,
"keyword"_L1);
583 addVerbatim(statement->lparenToken);
584 QQmlJS::AST::Node::accept(statement->expression,
this);
585 addVerbatim(statement->rparenToken);
586 QQmlJS::AST::Node::accept(statement->ok,
this);
588 addMarkedUpToken(statement->elseToken,
"keyword"_L1);
589 QQmlJS::AST::Node::accept(statement->ko,
this);
596 addMarkedUpToken(statement->doToken,
"keyword"_L1);
597 QQmlJS::AST::Node::accept(statement->statement,
this);
598 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
599 addVerbatim(statement->lparenToken);
600 QQmlJS::AST::Node::accept(statement->expression,
this);
601 addVerbatim(statement->rparenToken);
602 addVerbatim(statement->semicolonToken);
608 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
609 addVerbatim(statement->lparenToken);
610 QQmlJS::AST::Node::accept(statement->expression,
this);
611 addVerbatim(statement->rparenToken);
612 QQmlJS::AST::Node::accept(statement->statement,
this);
618 addMarkedUpToken(statement->forToken,
"keyword"_L1);
619 addVerbatim(statement->lparenToken);
620 QQmlJS::AST::Node::accept(statement->initialiser,
this);
621 addVerbatim(statement->firstSemicolonToken);
622 QQmlJS::AST::Node::accept(statement->condition,
this);
623 addVerbatim(statement->secondSemicolonToken);
624 QQmlJS::AST::Node::accept(statement->expression,
this);
625 addVerbatim(statement->rparenToken);
626 QQmlJS::AST::Node::accept(statement->statement,
this);
632 addMarkedUpToken(statement->forToken,
"keyword"_L1);
633 addVerbatim(statement->lparenToken);
634 QQmlJS::AST::Node::accept(statement->lhs,
this);
635 addVerbatim(statement->inOfToken);
636 QQmlJS::AST::Node::accept(statement->expression,
this);
637 addVerbatim(statement->rparenToken);
638 QQmlJS::AST::Node::accept(statement->statement,
this);
644 addMarkedUpToken(statement->continueToken,
"keyword"_L1);
645 addMarkedUpToken(statement->identifierToken,
"name"_L1);
646 addVerbatim(statement->semicolonToken);
652 addMarkedUpToken(statement->breakToken,
"keyword"_L1);
653 addMarkedUpToken(statement->identifierToken,
"name"_L1);
654 addVerbatim(statement->semicolonToken);
660 addMarkedUpToken(statement->returnToken,
"keyword"_L1);
661 QQmlJS::AST::Node::accept(statement->expression,
this);
662 addVerbatim(statement->semicolonToken);
668 addMarkedUpToken(statement->withToken,
"keyword"_L1);
669 addVerbatim(statement->lparenToken);
670 QQmlJS::AST::Node::accept(statement->expression,
this);
671 addVerbatim(statement->rparenToken);
672 QQmlJS::AST::Node::accept(statement->statement,
this);
678 addVerbatim(block->lbraceToken);
684 addVerbatim(block->rbraceToken, block->rbraceToken);
689 addMarkedUpToken(statement->switchToken,
"keyword"_L1);
690 addVerbatim(statement->lparenToken);
691 QQmlJS::AST::Node::accept(statement->expression,
this);
692 addVerbatim(statement->rparenToken);
693 QQmlJS::AST::Node::accept(statement->block,
this);
699 addMarkedUpToken(clause->caseToken,
"keyword"_L1);
700 QQmlJS::AST::Node::accept(clause->expression,
this);
701 addVerbatim(clause->colonToken);
702 QQmlJS::AST::Node::accept(clause->statements,
this);
708 addMarkedUpToken(clause->defaultToken,
"keyword"_L1);
709 addVerbatim(clause->colonToken, clause->colonToken);
715 addMarkedUpToken(statement->identifierToken,
"name"_L1);
716 addVerbatim(statement->colonToken);
717 QQmlJS::AST::Node::accept(statement->statement,
this);
723 addMarkedUpToken(statement->throwToken,
"keyword"_L1);
724 QQmlJS::AST::Node::accept(statement->expression,
this);
725 addVerbatim(statement->semicolonToken);
731 addMarkedUpToken(c->catchToken,
"keyword"_L1);
732 addVerbatim(c->lparenToken);
733 addMarkedUpToken(c->identifierToken,
"name"_L1);
734 addVerbatim(c->rparenToken);
740 addMarkedUpToken(f->finallyToken,
"keyword"_L1);
741 QQmlJS::AST::Node::accept(f->statement,
this);
747 addMarkedUpToken(statement->tryToken,
"keyword"_L1);
748 QQmlJS::AST::Node::accept(statement->statement,
this);
749 QQmlJS::AST::Node::accept(statement->catchExpression,
this);
750 QQmlJS::AST::Node::accept(statement->finallyExpression,
this);
756 addMarkedUpToken(expression->functionToken,
"keyword"_L1);
757 addMarkedUpToken(expression->identifierToken,
"name"_L1);
758 addVerbatim(expression->lparenToken);
759 QQmlJS::AST::Node::accept(expression->formals,
this);
760 addVerbatim(expression->rparenToken);
761 addVerbatim(expression->lbraceToken);
762 QQmlJS::AST::Node::accept(expression->body,
this);
763 addVerbatim(expression->rbraceToken);
769 addMarkedUpToken(declaration->functionToken,
"keyword"_L1);
770 addMarkedUpToken(declaration->identifierToken,
"name"_L1);
771 addVerbatim(declaration->lparenToken);
772 QQmlJS::AST::Node::accept(declaration->formals,
this);
773 addVerbatim(declaration->rparenToken);
774 addVerbatim(declaration->lbraceToken);
775 QQmlJS::AST::Node::accept(declaration->body,
this);
776 addVerbatim(declaration->rbraceToken);
782 QQmlJS::AST::Node::accept(list->element,
this);
788 addVerbatim(statement->debuggerToken);
789 addVerbatim(statement->semicolonToken);
797 if (
auto fullLocation = getFullyQualifiedLocation(definition->qualifiedTypeNameId))
798 addMarkedUpToken(fullLocation.value(),
"type"_L1);
800 QQmlJS::AST::Node::accept(definition->qualifiedTypeNameId,
this);
802 QQmlJS::AST::Node::accept(definition->initializer,
this);
808 m_hasRecursionDepthError =
true;
void throwRecursionDepthError() final
void endVisit(QQmlJS::AST::UiImport *) override
bool visit(QQmlJS::AST::UiImport *) override