6#include <QtCore/qglobal.h>
7#include <QtCore/qstringlist.h>
9#include <private/qqmljsast_p.h>
10#include <private/qqmljsengine_p.h>
12using namespace Qt::StringLiterals;
16QmlMarkupVisitor::QmlMarkupVisitor(
const QString &source,
17 const QList<QQmlJS::SourceLocation> &pragmas,
18 QQmlJS::Engine *engine)
20 this->m_source = source;
21 this->m_engine = engine;
29 const QList<QQmlJS::SourceLocation> comments = engine->comments();
30 while (i < comments.size() && j < pragmas.size()) {
31 if (comments[i].offset < pragmas[j].offset) {
32 m_extraTypes.append(Comment);
33 m_extraLocations.append(comments[i]);
36 m_extraTypes.append(Pragma);
37 m_extraLocations.append(comments[j]);
42 while (i < comments.size()) {
43 m_extraTypes.append(Comment);
44 m_extraLocations.append(comments[i]);
48 while (j < pragmas.size()) {
49 m_extraTypes.append(Pragma);
50 m_extraLocations.append(pragmas[j]);
57 if (
int(m_cursor) < m_source.size())
58 addExtra(m_cursor, m_source.size());
65 return m_hasRecursionDepthError;
70 if (m_extraIndex >= m_extraLocations.size()) {
71 QString extra = m_source.mid(start, finish - start);
72 if (extra.trimmed().isEmpty())
75 m_output += Utilities::protect(extra);
81 while (m_extraIndex < m_extraLocations.size()) {
82 if (m_extraTypes[m_extraIndex] == Comment) {
83 if (m_extraLocations[m_extraIndex].offset - 2 >= start)
86 if (m_extraLocations[m_extraIndex].offset >= start)
93 while (i < finish && m_extraIndex < m_extraLocations.size()) {
94 quint32 j = m_extraLocations[m_extraIndex].offset - 2;
95 if (i <= j && j < finish) {
97 m_output += Utilities::protect(m_source.mid(i, j - i));
99 quint32 l = m_extraLocations[m_extraIndex].length;
100 if (m_extraTypes[m_extraIndex] == Comment) {
101 if (m_source.mid(j, 2) ==
"/*"_L1)
105 m_output +=
"<@comment>"_L1;
106 m_output += Utilities::protect(m_source.mid(j, l));
107 m_output +=
"</@comment>"_L1;
109 m_output += Utilities::protect(m_source.mid(j, l));
117 QString extra = m_source.mid(i, finish - i);
118 if (extra.trimmed().isEmpty())
121 m_output += Utilities::protect(extra);
126void QmlMarkupVisitor::addMarkedUpToken(
const QQmlJS::SourceLocation &location,
127 const QString &tagName,
128 const QHash<QString, QString> &attributes)
130 if (!location.isValid())
133 if (m_cursor < location.offset)
134 addExtra(m_cursor, location.offset);
135 else if (m_cursor > location.offset)
138 m_output +=
"<@%1"_L1.arg(tagName);
139 for (
const auto &key : attributes)
140 m_output +=
" %1=\"%2\""_L1.arg(key, attributes[key]);
141 m_output +=
">%2</@%3>"_L1.arg(Utilities::protect(sourceText(location)), tagName);
142 m_cursor += location.length;
147 return m_source.mid(location.offset, location.length);
151
152
153
154
155
156
157
158
159std::optional<QQmlJS::SourceLocation>
160QmlMarkupVisitor::getFullyQualifiedLocation(QQmlJS::AST::UiQualifiedId *id) {
161 if (!id || !id->identifierToken.isValid())
164 auto location = id->identifierToken;
166 for (
auto current = id->next; current; current = current->next) {
167 if (!current->identifierToken.isValid())
170 const auto currentEnd = current->identifierToken.offset + current->identifierToken.length;
171 location.length = currentEnd - location.offset;
178
179
180
181
182
183QQmlJS::SourceLocation
186 if (
auto fullLocation = getFullyQualifiedLocation(id))
187 return fullLocation.value();
188 return id->identifierToken;
192 QQmlJS::SourceLocation last)
194 if (!first.isValid())
197 quint32 start = first.begin();
202 finish = first.end();
204 if (m_cursor < start)
205 addExtra(m_cursor, start);
206 else if (m_cursor > start)
209 QString text = m_source.mid(start, finish - start);
210 m_output += Utilities::protect(text);
216 addVerbatim(uiimport->importToken);
217 if (!uiimport->importUri)
218 addMarkedUpToken(uiimport->fileNameToken,
"headerfile"_L1);
224 if (uiimport->version)
225 addVerbatim(uiimport->version->firstSourceLocation(),
226 uiimport->version->lastSourceLocation());
227 addVerbatim(uiimport->asToken);
228 addMarkedUpToken(uiimport->importIdToken,
"headerfile"_L1);
229 addVerbatim(uiimport->semicolonToken);
234 if (member->type == QQmlJS::AST::UiPublicMember::Property) {
235 addVerbatim(member->defaultToken());
236 addVerbatim(member->readonlyToken());
237 addVerbatim(member->propertyToken());
238 addVerbatim(member->typeModifierToken);
239 addMarkedUpToken(member->typeToken,
"type"_L1);
240 addMarkedUpToken(member->identifierToken,
"name"_L1);
241 addVerbatim(member->colonToken);
243 QQmlJS::AST::Node::accept(member->binding,
this);
244 else if (member->statement)
245 QQmlJS::AST::Node::accept(member->statement,
this);
247 addVerbatim(member->propertyToken());
248 addVerbatim(member->typeModifierToken);
249 addMarkedUpToken(member->typeToken,
"type"_L1);
251 QQmlJS::AST::Node::accept(member->parameters,
this);
253 addVerbatim(member->semicolonToken);
259 addVerbatim(initializer->lbraceToken, initializer->lbraceToken);
265 addVerbatim(initializer->rbraceToken, initializer->rbraceToken);
270 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
271 addVerbatim(binding->colonToken);
272 if (
auto fullLocation = getFullyQualifiedLocation(binding->qualifiedTypeNameId))
273 addMarkedUpToken(fullLocation.value(),
"type"_L1);
275 QQmlJS::AST::Node::accept(binding->qualifiedTypeNameId,
this);
277 QQmlJS::AST::Node::accept(binding->initializer,
this);
283 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
284 addVerbatim(binding->colonToken);
285 QQmlJS::AST::Node::accept(binding->statement,
this);
291 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
292 addVerbatim(binding->colonToken);
293 addVerbatim(binding->lbracketToken);
294 QQmlJS::AST::Node::accept(binding->members,
this);
295 addVerbatim(binding->rbracketToken);
301 for (QQmlJS::AST::UiArrayMemberList *it = list; it; it = it->next) {
302 QQmlJS::AST::Node::accept(it->member,
this);
310 addMarkedUpToken(getLocationForMarkup(id),
"name"_L1);
316 addVerbatim(expression->thisToken);
322 addMarkedUpToken(identifier->identifierToken,
"name"_L1);
328 addMarkedUpToken(null->nullToken,
"number"_L1);
334 addMarkedUpToken(literal->trueToken,
"number"_L1);
340 addMarkedUpToken(literal->falseToken,
"number"_L1);
346 addMarkedUpToken(literal->literalToken,
"number"_L1);
352 addMarkedUpToken(literal->literalToken,
"string"_L1);
358 addVerbatim(literal->literalToken);
364 addVerbatim(literal->lbracketToken);
365 QQmlJS::AST::Node::accept(literal->elements,
this);
366 addVerbatim(literal->rbracketToken);
372 addVerbatim(literal->lbraceToken);
378 addVerbatim(literal->rbraceToken);
383 for (QQmlJS::AST::PatternElementList *it = list; it; it = it->next) {
384 QQmlJS::AST::Node::accept(it->element,
this);
387 QQmlJS::AST::Node::accept(list->elision,
this);
393 addVerbatim(elision->commaToken, elision->commaToken);
399 QQmlJS::AST::Node::accept(list->name,
this);
400 addVerbatim(list->colonToken, list->colonToken);
401 QQmlJS::AST::Node::accept(list->initializer,
this);
408 QQmlJS::AST::Node::accept(expression->base,
this);
409 addVerbatim(expression->lbracketToken);
410 QQmlJS::AST::Node::accept(expression->expression,
this);
411 addVerbatim(expression->rbracketToken);
417 QQmlJS::AST::Node::accept(expression->base,
this);
418 addVerbatim(expression->dotToken);
419 addMarkedUpToken(expression->identifierToken,
"name"_L1);
425 addVerbatim(expression->newToken);
426 QQmlJS::AST::Node::accept(expression->base,
this);
427 addVerbatim(expression->lparenToken);
428 QQmlJS::AST::Node::accept(expression->arguments,
this);
429 addVerbatim(expression->rparenToken);
435 addVerbatim(expression->newToken);
441 addVerbatim(list->commaToken, list->commaToken);
447 addVerbatim(expression->incrementToken);
453 addVerbatim(expression->decrementToken);
459 addVerbatim(expression->deleteToken);
465 addVerbatim(expression->voidToken);
471 addVerbatim(expression->typeofToken);
477 addVerbatim(expression->incrementToken);
483 addVerbatim(expression->decrementToken);
489 addVerbatim(expression->plusToken);
495 addVerbatim(expression->minusToken);
501 addVerbatim(expression->tildeToken);
507 addVerbatim(expression->notToken);
513 QQmlJS::AST::Node::accept(expression->left,
this);
514 addMarkedUpToken(expression->operatorToken,
"op"_L1);
515 QQmlJS::AST::Node::accept(expression->right,
this);
521 QQmlJS::AST::Node::accept(expression->expression,
this);
522 addVerbatim(expression->questionToken);
523 QQmlJS::AST::Node::accept(expression->ok,
this);
524 addVerbatim(expression->colonToken);
525 QQmlJS::AST::Node::accept(expression->ko,
this);
531 QQmlJS::AST::Node::accept(expression->left,
this);
532 addVerbatim(expression->commaToken);
533 QQmlJS::AST::Node::accept(expression->right,
this);
539 addVerbatim(block->lbraceToken);
545 addVerbatim(block->rbraceToken);
550 addVerbatim(statement->declarationKindToken);
551 QQmlJS::AST::Node::accept(statement->declarations,
this);
558 for (QQmlJS::AST::VariableDeclarationList *it = list; it; it = it->next) {
559 QQmlJS::AST::Node::accept(it->declaration,
this);
560 addVerbatim(it->commaToken);
567 addVerbatim(statement->semicolonToken);
573 QQmlJS::AST::Node::accept(statement->expression,
this);
574 addVerbatim(statement->semicolonToken);
580 addMarkedUpToken(statement->ifToken,
"keyword"_L1);
581 addVerbatim(statement->lparenToken);
582 QQmlJS::AST::Node::accept(statement->expression,
this);
583 addVerbatim(statement->rparenToken);
584 QQmlJS::AST::Node::accept(statement->ok,
this);
586 addMarkedUpToken(statement->elseToken,
"keyword"_L1);
587 QQmlJS::AST::Node::accept(statement->ko,
this);
594 addMarkedUpToken(statement->doToken,
"keyword"_L1);
595 QQmlJS::AST::Node::accept(statement->statement,
this);
596 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
597 addVerbatim(statement->lparenToken);
598 QQmlJS::AST::Node::accept(statement->expression,
this);
599 addVerbatim(statement->rparenToken);
600 addVerbatim(statement->semicolonToken);
606 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
607 addVerbatim(statement->lparenToken);
608 QQmlJS::AST::Node::accept(statement->expression,
this);
609 addVerbatim(statement->rparenToken);
610 QQmlJS::AST::Node::accept(statement->statement,
this);
616 addMarkedUpToken(statement->forToken,
"keyword"_L1);
617 addVerbatim(statement->lparenToken);
618 QQmlJS::AST::Node::accept(statement->initialiser,
this);
619 addVerbatim(statement->firstSemicolonToken);
620 QQmlJS::AST::Node::accept(statement->condition,
this);
621 addVerbatim(statement->secondSemicolonToken);
622 QQmlJS::AST::Node::accept(statement->expression,
this);
623 addVerbatim(statement->rparenToken);
624 QQmlJS::AST::Node::accept(statement->statement,
this);
630 addMarkedUpToken(statement->forToken,
"keyword"_L1);
631 addVerbatim(statement->lparenToken);
632 QQmlJS::AST::Node::accept(statement->lhs,
this);
633 addVerbatim(statement->inOfToken);
634 QQmlJS::AST::Node::accept(statement->expression,
this);
635 addVerbatim(statement->rparenToken);
636 QQmlJS::AST::Node::accept(statement->statement,
this);
642 addMarkedUpToken(statement->continueToken,
"keyword"_L1);
643 addMarkedUpToken(statement->identifierToken,
"name"_L1);
644 addVerbatim(statement->semicolonToken);
650 addMarkedUpToken(statement->breakToken,
"keyword"_L1);
651 addMarkedUpToken(statement->identifierToken,
"name"_L1);
652 addVerbatim(statement->semicolonToken);
658 addMarkedUpToken(statement->returnToken,
"keyword"_L1);
659 QQmlJS::AST::Node::accept(statement->expression,
this);
660 addVerbatim(statement->semicolonToken);
666 addMarkedUpToken(statement->withToken,
"keyword"_L1);
667 addVerbatim(statement->lparenToken);
668 QQmlJS::AST::Node::accept(statement->expression,
this);
669 addVerbatim(statement->rparenToken);
670 QQmlJS::AST::Node::accept(statement->statement,
this);
676 addVerbatim(block->lbraceToken);
682 addVerbatim(block->rbraceToken, block->rbraceToken);
687 addMarkedUpToken(statement->switchToken,
"keyword"_L1);
688 addVerbatim(statement->lparenToken);
689 QQmlJS::AST::Node::accept(statement->expression,
this);
690 addVerbatim(statement->rparenToken);
691 QQmlJS::AST::Node::accept(statement->block,
this);
697 addMarkedUpToken(clause->caseToken,
"keyword"_L1);
698 QQmlJS::AST::Node::accept(clause->expression,
this);
699 addVerbatim(clause->colonToken);
700 QQmlJS::AST::Node::accept(clause->statements,
this);
706 addMarkedUpToken(clause->defaultToken,
"keyword"_L1);
707 addVerbatim(clause->colonToken, clause->colonToken);
713 addMarkedUpToken(statement->identifierToken,
"name"_L1);
714 addVerbatim(statement->colonToken);
715 QQmlJS::AST::Node::accept(statement->statement,
this);
721 addMarkedUpToken(statement->throwToken,
"keyword"_L1);
722 QQmlJS::AST::Node::accept(statement->expression,
this);
723 addVerbatim(statement->semicolonToken);
729 addMarkedUpToken(c->catchToken,
"keyword"_L1);
730 addVerbatim(c->lparenToken);
731 addMarkedUpToken(c->identifierToken,
"name"_L1);
732 addVerbatim(c->rparenToken);
738 addMarkedUpToken(f->finallyToken,
"keyword"_L1);
739 QQmlJS::AST::Node::accept(f->statement,
this);
745 addMarkedUpToken(statement->tryToken,
"keyword"_L1);
746 QQmlJS::AST::Node::accept(statement->statement,
this);
747 QQmlJS::AST::Node::accept(statement->catchExpression,
this);
748 QQmlJS::AST::Node::accept(statement->finallyExpression,
this);
754 addMarkedUpToken(expression->functionToken,
"keyword"_L1);
755 addMarkedUpToken(expression->identifierToken,
"name"_L1);
756 addVerbatim(expression->lparenToken);
757 QQmlJS::AST::Node::accept(expression->formals,
this);
758 addVerbatim(expression->rparenToken);
759 addVerbatim(expression->lbraceToken);
760 QQmlJS::AST::Node::accept(expression->body,
this);
761 addVerbatim(expression->rbraceToken);
767 addMarkedUpToken(declaration->functionToken,
"keyword"_L1);
768 addMarkedUpToken(declaration->identifierToken,
"name"_L1);
769 addVerbatim(declaration->lparenToken);
770 QQmlJS::AST::Node::accept(declaration->formals,
this);
771 addVerbatim(declaration->rparenToken);
772 addVerbatim(declaration->lbraceToken);
773 QQmlJS::AST::Node::accept(declaration->body,
this);
774 addVerbatim(declaration->rbraceToken);
780 QQmlJS::AST::Node::accept(list->element,
this);
786 addVerbatim(statement->debuggerToken);
787 addVerbatim(statement->semicolonToken);
795 if (
auto fullLocation = getFullyQualifiedLocation(definition->qualifiedTypeNameId))
796 addMarkedUpToken(fullLocation.value(),
"type"_L1);
798 QQmlJS::AST::Node::accept(definition->qualifiedTypeNameId,
this);
800 QQmlJS::AST::Node::accept(definition->initializer,
this);
806 m_hasRecursionDepthError =
true;
void throwRecursionDepthError() final
void endVisit(QQmlJS::AST::UiImport *) override
bool visit(QQmlJS::AST::UiImport *) override