9#include <QtCore/qglobal.h>
10#include <QtCore/qstringlist.h>
12#include <private/qqmljsast_p.h>
13#include <private/qqmljsengine_p.h>
15using namespace Qt::StringLiterals;
19QmlMarkupVisitor::QmlMarkupVisitor(
const QString &source,
20 const QList<QQmlJS::SourceLocation> &pragmas,
21 QQmlJS::Engine *engine)
23 this->m_source = source;
24 this->m_engine = engine;
32 const QList<QQmlJS::SourceLocation> comments = engine->comments();
33 while (i < comments.size() && j < pragmas.size()) {
34 if (comments[i].offset < pragmas[j].offset) {
35 m_extraTypes.append(Comment);
36 m_extraLocations.append(comments[i]);
39 m_extraTypes.append(Pragma);
40 m_extraLocations.append(comments[j]);
45 while (i < comments.size()) {
46 m_extraTypes.append(Comment);
47 m_extraLocations.append(comments[i]);
51 while (j < pragmas.size()) {
52 m_extraTypes.append(Pragma);
53 m_extraLocations.append(pragmas[j]);
60 if (
int(m_cursor) < m_source.size())
61 addExtra(m_cursor, m_source.size());
68 return m_hasRecursionDepthError;
73 if (m_extraIndex >= m_extraLocations.size()) {
74 QString extra = m_source.mid(start, finish - start);
75 if (extra.trimmed().isEmpty())
78 m_output += TextUtils::protect(extra);
84 while (m_extraIndex < m_extraLocations.size()) {
85 if (m_extraTypes[m_extraIndex] == Comment) {
86 if (m_extraLocations[m_extraIndex].offset - 2 >= start)
89 if (m_extraLocations[m_extraIndex].offset >= start)
96 while (i < finish && m_extraIndex < m_extraLocations.size()) {
97 quint32 j = m_extraLocations[m_extraIndex].offset - 2;
98 if (i <= j && j < finish) {
100 m_output += TextUtils::protect(m_source.mid(i, j - i));
102 quint32 l = m_extraLocations[m_extraIndex].length;
103 if (m_extraTypes[m_extraIndex] == Comment) {
104 if (m_source.mid(j, 2) ==
"/*"_L1)
108 m_output +=
"<@comment>"_L1;
109 m_output += TextUtils::protect(m_source.mid(j, l));
110 m_output +=
"</@comment>"_L1;
112 m_output += TextUtils::protect(m_source.mid(j, l));
120 QString extra = m_source.mid(i, finish - i);
121 if (extra.trimmed().isEmpty())
124 m_output += TextUtils::protect(extra);
129void QmlMarkupVisitor::addMarkedUpToken(
const QQmlJS::SourceLocation &location,
130 const QString &tagName)
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>%2</@%1>"_L1.arg(tagName, TextUtils::protect(sourceText(location)));
141 m_cursor += location.length;
146 return m_source.mid(location.offset, location.length);
150
151
152
153
154
155
156
157
158std::optional<QQmlJS::SourceLocation>
159QmlMarkupVisitor::getFullyQualifiedLocation(QQmlJS::AST::UiQualifiedId *id) {
160 if (!id || !id->identifierToken.isValid())
163 auto location = id->identifierToken;
165 for (
auto current = id->next; current; current = current->next) {
166 if (!current->identifierToken.isValid())
169 const auto currentEnd = current->identifierToken.offset + current->identifierToken.length;
170 location.length = currentEnd - location.offset;
177
178
179
180
181
182QQmlJS::SourceLocation
185 if (
auto fullLocation = getFullyQualifiedLocation(id))
186 return fullLocation.value();
187 return id->identifierToken;
191 QQmlJS::SourceLocation last)
193 if (!first.isValid())
196 quint32 start = first.begin();
201 finish = first.end();
203 if (m_cursor < start)
204 addExtra(m_cursor, start);
205 else if (m_cursor > start)
208 QString text = m_source.mid(start, finish - start);
209 m_output += TextUtils::protect(text);
215 addVerbatim(uiimport->importToken);
216 if (!uiimport->importUri)
217 addMarkedUpToken(uiimport->fileNameToken,
"headerfile"_L1);
223 if (uiimport->version)
224 addVerbatim(uiimport->version->firstSourceLocation(),
225 uiimport->version->lastSourceLocation());
226 addVerbatim(uiimport->asToken);
227 addMarkedUpToken(uiimport->importIdToken,
"headerfile"_L1);
228 addVerbatim(uiimport->semicolonToken);
233 if (member->type == QQmlJS::AST::UiPublicMember::Property) {
234 addVerbatim(member->defaultToken());
235 addVerbatim(member->readonlyToken());
236 addVerbatim(member->propertyToken());
237 addVerbatim(member->typeModifierToken);
238 addMarkedUpToken(member->memberType->firstSourceLocation(),
"type"_L1);
239 addMarkedUpToken(member->identifierToken,
"name"_L1);
240 addVerbatim(member->colonToken);
242 QQmlJS::AST::Node::accept(member->binding,
this);
243 else if (member->statement)
244 QQmlJS::AST::Node::accept(member->statement,
this);
246 addVerbatim(member->propertyToken());
247 addVerbatim(member->typeModifierToken);
248 addMarkedUpToken(member->identifierToken,
"type"_L1);
249 QQmlJS::AST::Node::accept(member->parameters,
this);
251 addVerbatim(member->semicolonToken);
257 addVerbatim(initializer->lbraceToken, initializer->lbraceToken);
263 addVerbatim(initializer->rbraceToken, initializer->rbraceToken);
268 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
269 addVerbatim(binding->colonToken);
270 if (
auto fullLocation = getFullyQualifiedLocation(binding->qualifiedTypeNameId))
271 addMarkedUpToken(fullLocation.value(),
"type"_L1);
273 QQmlJS::AST::Node::accept(binding->qualifiedTypeNameId,
this);
275 QQmlJS::AST::Node::accept(binding->initializer,
this);
281 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
282 addVerbatim(binding->colonToken);
283 QQmlJS::AST::Node::accept(binding->statement,
this);
289 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
290 addVerbatim(binding->colonToken);
291 addVerbatim(binding->lbracketToken);
292 QQmlJS::AST::Node::accept(binding->members,
this);
293 addVerbatim(binding->rbracketToken);
299 for (QQmlJS::AST::UiArrayMemberList *it = list; it; it = it->next) {
300 QQmlJS::AST::Node::accept(it->member,
this);
308 addMarkedUpToken(getLocationForMarkup(id),
"name"_L1);
314 addVerbatim(expression->thisToken);
320 addMarkedUpToken(identifier->identifierToken,
"name"_L1);
326 addMarkedUpToken(null->nullToken,
"number"_L1);
332 addMarkedUpToken(literal->trueToken,
"number"_L1);
338 addMarkedUpToken(literal->falseToken,
"number"_L1);
344 addMarkedUpToken(literal->literalToken,
"number"_L1);
350 addMarkedUpToken(literal->literalToken,
"string"_L1);
356 addVerbatim(literal->literalToken);
362 addVerbatim(literal->lbracketToken);
363 QQmlJS::AST::Node::accept(literal->elements,
this);
364 addVerbatim(literal->rbracketToken);
370 addVerbatim(literal->lbraceToken);
376 addVerbatim(literal->rbraceToken);
381 for (QQmlJS::AST::PatternElementList *it = list; it; it = it->next) {
382 QQmlJS::AST::Node::accept(it->element,
this);
385 QQmlJS::AST::Node::accept(list->elision,
this);
391 addVerbatim(elision->commaToken, elision->commaToken);
397 QQmlJS::AST::Node::accept(list->name,
this);
398 addVerbatim(list->colonToken, list->colonToken);
399 QQmlJS::AST::Node::accept(list->initializer,
this);
406 QQmlJS::AST::Node::accept(expression->base,
this);
407 addVerbatim(expression->lbracketToken);
408 QQmlJS::AST::Node::accept(expression->expression,
this);
409 addVerbatim(expression->rbracketToken);
415 QQmlJS::AST::Node::accept(expression->base,
this);
416 addVerbatim(expression->dotToken);
417 addMarkedUpToken(expression->identifierToken,
"name"_L1);
423 addVerbatim(expression->newToken);
424 QQmlJS::AST::Node::accept(expression->base,
this);
425 addVerbatim(expression->lparenToken);
426 QQmlJS::AST::Node::accept(expression->arguments,
this);
427 addVerbatim(expression->rparenToken);
433 addVerbatim(expression->newToken);
439 addVerbatim(list->commaToken, list->commaToken);
445 addVerbatim(expression->incrementToken);
451 addVerbatim(expression->decrementToken);
457 addVerbatim(expression->deleteToken);
463 addVerbatim(expression->voidToken);
469 addVerbatim(expression->typeofToken);
475 addVerbatim(expression->incrementToken);
481 addVerbatim(expression->decrementToken);
487 addVerbatim(expression->plusToken);
493 addVerbatim(expression->minusToken);
499 addVerbatim(expression->tildeToken);
505 addVerbatim(expression->notToken);
511 QQmlJS::AST::Node::accept(expression->left,
this);
512 addMarkedUpToken(expression->operatorToken,
"op"_L1);
513 QQmlJS::AST::Node::accept(expression->right,
this);
519 QQmlJS::AST::Node::accept(expression->expression,
this);
520 addVerbatim(expression->questionToken);
521 QQmlJS::AST::Node::accept(expression->ok,
this);
522 addVerbatim(expression->colonToken);
523 QQmlJS::AST::Node::accept(expression->ko,
this);
529 QQmlJS::AST::Node::accept(expression->left,
this);
530 addVerbatim(expression->commaToken);
531 QQmlJS::AST::Node::accept(expression->right,
this);
537 addVerbatim(block->lbraceToken);
543 addVerbatim(block->rbraceToken);
548 addVerbatim(statement->declarationKindToken);
549 QQmlJS::AST::Node::accept(statement->declarations,
this);
556 for (QQmlJS::AST::VariableDeclarationList *it = list; it; it = it->next) {
557 QQmlJS::AST::Node::accept(it->declaration,
this);
558 addVerbatim(it->commaToken);
565 addVerbatim(statement->semicolonToken);
571 QQmlJS::AST::Node::accept(statement->expression,
this);
572 addVerbatim(statement->semicolonToken);
578 addMarkedUpToken(statement->ifToken,
"keyword"_L1);
579 addVerbatim(statement->lparenToken);
580 QQmlJS::AST::Node::accept(statement->expression,
this);
581 addVerbatim(statement->rparenToken);
582 QQmlJS::AST::Node::accept(statement->ok,
this);
584 addMarkedUpToken(statement->elseToken,
"keyword"_L1);
585 QQmlJS::AST::Node::accept(statement->ko,
this);
592 addMarkedUpToken(statement->doToken,
"keyword"_L1);
593 QQmlJS::AST::Node::accept(statement->statement,
this);
594 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
595 addVerbatim(statement->lparenToken);
596 QQmlJS::AST::Node::accept(statement->expression,
this);
597 addVerbatim(statement->rparenToken);
598 addVerbatim(statement->semicolonToken);
604 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
605 addVerbatim(statement->lparenToken);
606 QQmlJS::AST::Node::accept(statement->expression,
this);
607 addVerbatim(statement->rparenToken);
608 QQmlJS::AST::Node::accept(statement->statement,
this);
614 addMarkedUpToken(statement->forToken,
"keyword"_L1);
615 addVerbatim(statement->lparenToken);
616 QQmlJS::AST::Node::accept(statement->initialiser,
this);
617 addVerbatim(statement->firstSemicolonToken);
618 QQmlJS::AST::Node::accept(statement->condition,
this);
619 addVerbatim(statement->secondSemicolonToken);
620 QQmlJS::AST::Node::accept(statement->expression,
this);
621 addVerbatim(statement->rparenToken);
622 QQmlJS::AST::Node::accept(statement->statement,
this);
628 addMarkedUpToken(statement->forToken,
"keyword"_L1);
629 addVerbatim(statement->lparenToken);
630 QQmlJS::AST::Node::accept(statement->lhs,
this);
631 addVerbatim(statement->inOfToken);
632 QQmlJS::AST::Node::accept(statement->expression,
this);
633 addVerbatim(statement->rparenToken);
634 QQmlJS::AST::Node::accept(statement->statement,
this);
640 addMarkedUpToken(statement->continueToken,
"keyword"_L1);
641 addMarkedUpToken(statement->identifierToken,
"name"_L1);
642 addVerbatim(statement->semicolonToken);
648 addMarkedUpToken(statement->breakToken,
"keyword"_L1);
649 addMarkedUpToken(statement->identifierToken,
"name"_L1);
650 addVerbatim(statement->semicolonToken);
656 addMarkedUpToken(statement->returnToken,
"keyword"_L1);
657 QQmlJS::AST::Node::accept(statement->expression,
this);
658 addVerbatim(statement->semicolonToken);
664 addMarkedUpToken(statement->withToken,
"keyword"_L1);
665 addVerbatim(statement->lparenToken);
666 QQmlJS::AST::Node::accept(statement->expression,
this);
667 addVerbatim(statement->rparenToken);
668 QQmlJS::AST::Node::accept(statement->statement,
this);
674 addVerbatim(block->lbraceToken);
680 addVerbatim(block->rbraceToken, block->rbraceToken);
685 addMarkedUpToken(statement->switchToken,
"keyword"_L1);
686 addVerbatim(statement->lparenToken);
687 QQmlJS::AST::Node::accept(statement->expression,
this);
688 addVerbatim(statement->rparenToken);
689 QQmlJS::AST::Node::accept(statement->block,
this);
695 addMarkedUpToken(clause->caseToken,
"keyword"_L1);
696 QQmlJS::AST::Node::accept(clause->expression,
this);
697 addVerbatim(clause->colonToken);
698 QQmlJS::AST::Node::accept(clause->statements,
this);
704 addMarkedUpToken(clause->defaultToken,
"keyword"_L1);
705 addVerbatim(clause->colonToken, clause->colonToken);
711 addMarkedUpToken(statement->identifierToken,
"name"_L1);
712 addVerbatim(statement->colonToken);
713 QQmlJS::AST::Node::accept(statement->statement,
this);
719 addMarkedUpToken(statement->throwToken,
"keyword"_L1);
720 QQmlJS::AST::Node::accept(statement->expression,
this);
721 addVerbatim(statement->semicolonToken);
727 addMarkedUpToken(c->catchToken,
"keyword"_L1);
728 addVerbatim(c->lparenToken);
729 addMarkedUpToken(c->patternElement->identifierToken,
"name"_L1);
730 addVerbatim(c->rparenToken);
736 addMarkedUpToken(f->finallyToken,
"keyword"_L1);
737 QQmlJS::AST::Node::accept(f->statement,
this);
743 addMarkedUpToken(statement->tryToken,
"keyword"_L1);
744 QQmlJS::AST::Node::accept(statement->statement,
this);
745 QQmlJS::AST::Node::accept(statement->catchExpression,
this);
746 QQmlJS::AST::Node::accept(statement->finallyExpression,
this);
752 addMarkedUpToken(expression->functionToken,
"keyword"_L1);
753 addMarkedUpToken(expression->identifierToken,
"name"_L1);
754 addVerbatim(expression->lparenToken);
755 QQmlJS::AST::Node::accept(expression->formals,
this);
756 addVerbatim(expression->rparenToken);
757 addVerbatim(expression->lbraceToken);
758 QQmlJS::AST::Node::accept(expression->body,
this);
759 addVerbatim(expression->rbraceToken);
765 addMarkedUpToken(declaration->functionToken,
"keyword"_L1);
766 addMarkedUpToken(declaration->identifierToken,
"name"_L1);
767 addVerbatim(declaration->lparenToken);
768 QQmlJS::AST::Node::accept(declaration->formals,
this);
769 addVerbatim(declaration->rparenToken);
770 addVerbatim(declaration->lbraceToken);
771 QQmlJS::AST::Node::accept(declaration->body,
this);
772 addVerbatim(declaration->rbraceToken);
778 QQmlJS::AST::Node::accept(list->element,
this);
784 addVerbatim(statement->debuggerToken);
785 addVerbatim(statement->semicolonToken);
793 if (
auto fullLocation = getFullyQualifiedLocation(definition->qualifiedTypeNameId))
794 addMarkedUpToken(fullLocation.value(),
"type"_L1);
796 QQmlJS::AST::Node::accept(definition->qualifiedTypeNameId,
this);
798 QQmlJS::AST::Node::accept(definition->initializer,
this);
804 m_hasRecursionDepthError =
true;
void throwRecursionDepthError() final
void endVisit(QQmlJS::AST::UiImport *) override
bool visit(QQmlJS::AST::UiImport *) override