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->typeToken,
"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->typeToken,
"type"_L1);
250 QQmlJS::AST::Node::accept(member->parameters,
this);
252 addVerbatim(member->semicolonToken);
258 addVerbatim(initializer->lbraceToken, initializer->lbraceToken);
264 addVerbatim(initializer->rbraceToken, initializer->rbraceToken);
269 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
270 addVerbatim(binding->colonToken);
271 if (
auto fullLocation = getFullyQualifiedLocation(binding->qualifiedTypeNameId))
272 addMarkedUpToken(fullLocation.value(),
"type"_L1);
274 QQmlJS::AST::Node::accept(binding->qualifiedTypeNameId,
this);
276 QQmlJS::AST::Node::accept(binding->initializer,
this);
282 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
283 addVerbatim(binding->colonToken);
284 QQmlJS::AST::Node::accept(binding->statement,
this);
290 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
291 addVerbatim(binding->colonToken);
292 addVerbatim(binding->lbracketToken);
293 QQmlJS::AST::Node::accept(binding->members,
this);
294 addVerbatim(binding->rbracketToken);
300 for (QQmlJS::AST::UiArrayMemberList *it = list; it; it = it->next) {
301 QQmlJS::AST::Node::accept(it->member,
this);
309 addMarkedUpToken(getLocationForMarkup(id),
"name"_L1);
315 addVerbatim(expression->thisToken);
321 addMarkedUpToken(identifier->identifierToken,
"name"_L1);
327 addMarkedUpToken(null->nullToken,
"number"_L1);
333 addMarkedUpToken(literal->trueToken,
"number"_L1);
339 addMarkedUpToken(literal->falseToken,
"number"_L1);
345 addMarkedUpToken(literal->literalToken,
"number"_L1);
351 addMarkedUpToken(literal->literalToken,
"string"_L1);
357 addVerbatim(literal->literalToken);
363 addVerbatim(literal->lbracketToken);
364 QQmlJS::AST::Node::accept(literal->elements,
this);
365 addVerbatim(literal->rbracketToken);
371 addVerbatim(literal->lbraceToken);
377 addVerbatim(literal->rbraceToken);
382 for (QQmlJS::AST::PatternElementList *it = list; it; it = it->next) {
383 QQmlJS::AST::Node::accept(it->element,
this);
386 QQmlJS::AST::Node::accept(list->elision,
this);
392 addVerbatim(elision->commaToken, elision->commaToken);
398 QQmlJS::AST::Node::accept(list->name,
this);
399 addVerbatim(list->colonToken, list->colonToken);
400 QQmlJS::AST::Node::accept(list->initializer,
this);
407 QQmlJS::AST::Node::accept(expression->base,
this);
408 addVerbatim(expression->lbracketToken);
409 QQmlJS::AST::Node::accept(expression->expression,
this);
410 addVerbatim(expression->rbracketToken);
416 QQmlJS::AST::Node::accept(expression->base,
this);
417 addVerbatim(expression->dotToken);
418 addMarkedUpToken(expression->identifierToken,
"name"_L1);
424 addVerbatim(expression->newToken);
425 QQmlJS::AST::Node::accept(expression->base,
this);
426 addVerbatim(expression->lparenToken);
427 QQmlJS::AST::Node::accept(expression->arguments,
this);
428 addVerbatim(expression->rparenToken);
434 addVerbatim(expression->newToken);
440 addVerbatim(list->commaToken, list->commaToken);
446 addVerbatim(expression->incrementToken);
452 addVerbatim(expression->decrementToken);
458 addVerbatim(expression->deleteToken);
464 addVerbatim(expression->voidToken);
470 addVerbatim(expression->typeofToken);
476 addVerbatim(expression->incrementToken);
482 addVerbatim(expression->decrementToken);
488 addVerbatim(expression->plusToken);
494 addVerbatim(expression->minusToken);
500 addVerbatim(expression->tildeToken);
506 addVerbatim(expression->notToken);
512 QQmlJS::AST::Node::accept(expression->left,
this);
513 addMarkedUpToken(expression->operatorToken,
"op"_L1);
514 QQmlJS::AST::Node::accept(expression->right,
this);
520 QQmlJS::AST::Node::accept(expression->expression,
this);
521 addVerbatim(expression->questionToken);
522 QQmlJS::AST::Node::accept(expression->ok,
this);
523 addVerbatim(expression->colonToken);
524 QQmlJS::AST::Node::accept(expression->ko,
this);
530 QQmlJS::AST::Node::accept(expression->left,
this);
531 addVerbatim(expression->commaToken);
532 QQmlJS::AST::Node::accept(expression->right,
this);
538 addVerbatim(block->lbraceToken);
544 addVerbatim(block->rbraceToken);
549 addVerbatim(statement->declarationKindToken);
550 QQmlJS::AST::Node::accept(statement->declarations,
this);
557 for (QQmlJS::AST::VariableDeclarationList *it = list; it; it = it->next) {
558 QQmlJS::AST::Node::accept(it->declaration,
this);
559 addVerbatim(it->commaToken);
566 addVerbatim(statement->semicolonToken);
572 QQmlJS::AST::Node::accept(statement->expression,
this);
573 addVerbatim(statement->semicolonToken);
579 addMarkedUpToken(statement->ifToken,
"keyword"_L1);
580 addVerbatim(statement->lparenToken);
581 QQmlJS::AST::Node::accept(statement->expression,
this);
582 addVerbatim(statement->rparenToken);
583 QQmlJS::AST::Node::accept(statement->ok,
this);
585 addMarkedUpToken(statement->elseToken,
"keyword"_L1);
586 QQmlJS::AST::Node::accept(statement->ko,
this);
593 addMarkedUpToken(statement->doToken,
"keyword"_L1);
594 QQmlJS::AST::Node::accept(statement->statement,
this);
595 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
596 addVerbatim(statement->lparenToken);
597 QQmlJS::AST::Node::accept(statement->expression,
this);
598 addVerbatim(statement->rparenToken);
599 addVerbatim(statement->semicolonToken);
605 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
606 addVerbatim(statement->lparenToken);
607 QQmlJS::AST::Node::accept(statement->expression,
this);
608 addVerbatim(statement->rparenToken);
609 QQmlJS::AST::Node::accept(statement->statement,
this);
615 addMarkedUpToken(statement->forToken,
"keyword"_L1);
616 addVerbatim(statement->lparenToken);
617 QQmlJS::AST::Node::accept(statement->initialiser,
this);
618 addVerbatim(statement->firstSemicolonToken);
619 QQmlJS::AST::Node::accept(statement->condition,
this);
620 addVerbatim(statement->secondSemicolonToken);
621 QQmlJS::AST::Node::accept(statement->expression,
this);
622 addVerbatim(statement->rparenToken);
623 QQmlJS::AST::Node::accept(statement->statement,
this);
629 addMarkedUpToken(statement->forToken,
"keyword"_L1);
630 addVerbatim(statement->lparenToken);
631 QQmlJS::AST::Node::accept(statement->lhs,
this);
632 addVerbatim(statement->inOfToken);
633 QQmlJS::AST::Node::accept(statement->expression,
this);
634 addVerbatim(statement->rparenToken);
635 QQmlJS::AST::Node::accept(statement->statement,
this);
641 addMarkedUpToken(statement->continueToken,
"keyword"_L1);
642 addMarkedUpToken(statement->identifierToken,
"name"_L1);
643 addVerbatim(statement->semicolonToken);
649 addMarkedUpToken(statement->breakToken,
"keyword"_L1);
650 addMarkedUpToken(statement->identifierToken,
"name"_L1);
651 addVerbatim(statement->semicolonToken);
657 addMarkedUpToken(statement->returnToken,
"keyword"_L1);
658 QQmlJS::AST::Node::accept(statement->expression,
this);
659 addVerbatim(statement->semicolonToken);
665 addMarkedUpToken(statement->withToken,
"keyword"_L1);
666 addVerbatim(statement->lparenToken);
667 QQmlJS::AST::Node::accept(statement->expression,
this);
668 addVerbatim(statement->rparenToken);
669 QQmlJS::AST::Node::accept(statement->statement,
this);
675 addVerbatim(block->lbraceToken);
681 addVerbatim(block->rbraceToken, block->rbraceToken);
686 addMarkedUpToken(statement->switchToken,
"keyword"_L1);
687 addVerbatim(statement->lparenToken);
688 QQmlJS::AST::Node::accept(statement->expression,
this);
689 addVerbatim(statement->rparenToken);
690 QQmlJS::AST::Node::accept(statement->block,
this);
696 addMarkedUpToken(clause->caseToken,
"keyword"_L1);
697 QQmlJS::AST::Node::accept(clause->expression,
this);
698 addVerbatim(clause->colonToken);
699 QQmlJS::AST::Node::accept(clause->statements,
this);
705 addMarkedUpToken(clause->defaultToken,
"keyword"_L1);
706 addVerbatim(clause->colonToken, clause->colonToken);
712 addMarkedUpToken(statement->identifierToken,
"name"_L1);
713 addVerbatim(statement->colonToken);
714 QQmlJS::AST::Node::accept(statement->statement,
this);
720 addMarkedUpToken(statement->throwToken,
"keyword"_L1);
721 QQmlJS::AST::Node::accept(statement->expression,
this);
722 addVerbatim(statement->semicolonToken);
728 addMarkedUpToken(c->catchToken,
"keyword"_L1);
729 addVerbatim(c->lparenToken);
730 addMarkedUpToken(c->identifierToken,
"name"_L1);
731 addVerbatim(c->rparenToken);
737 addMarkedUpToken(f->finallyToken,
"keyword"_L1);
738 QQmlJS::AST::Node::accept(f->statement,
this);
744 addMarkedUpToken(statement->tryToken,
"keyword"_L1);
745 QQmlJS::AST::Node::accept(statement->statement,
this);
746 QQmlJS::AST::Node::accept(statement->catchExpression,
this);
747 QQmlJS::AST::Node::accept(statement->finallyExpression,
this);
753 addMarkedUpToken(expression->functionToken,
"keyword"_L1);
754 addMarkedUpToken(expression->identifierToken,
"name"_L1);
755 addVerbatim(expression->lparenToken);
756 QQmlJS::AST::Node::accept(expression->formals,
this);
757 addVerbatim(expression->rparenToken);
758 addVerbatim(expression->lbraceToken);
759 QQmlJS::AST::Node::accept(expression->body,
this);
760 addVerbatim(expression->rbraceToken);
766 addMarkedUpToken(declaration->functionToken,
"keyword"_L1);
767 addMarkedUpToken(declaration->identifierToken,
"name"_L1);
768 addVerbatim(declaration->lparenToken);
769 QQmlJS::AST::Node::accept(declaration->formals,
this);
770 addVerbatim(declaration->rparenToken);
771 addVerbatim(declaration->lbraceToken);
772 QQmlJS::AST::Node::accept(declaration->body,
this);
773 addVerbatim(declaration->rbraceToken);
779 QQmlJS::AST::Node::accept(list->element,
this);
785 addVerbatim(statement->debuggerToken);
786 addVerbatim(statement->semicolonToken);
794 if (
auto fullLocation = getFullyQualifiedLocation(definition->qualifiedTypeNameId))
795 addMarkedUpToken(fullLocation.value(),
"type"_L1);
797 QQmlJS::AST::Node::accept(definition->qualifiedTypeNameId,
this);
799 QQmlJS::AST::Node::accept(definition->initializer,
this);
805 m_hasRecursionDepthError =
true;
void throwRecursionDepthError() final
void endVisit(QQmlJS::AST::UiImport *) override
bool visit(QQmlJS::AST::UiImport *) override