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,
131 const QHash<QString, QString> &attributes)
133 if (!location.isValid())
136 if (m_cursor < location.offset)
137 addExtra(m_cursor, location.offset);
138 else if (m_cursor > location.offset)
141 m_output +=
"<@%1"_L1.arg(tagName);
142 for (
const auto &key : attributes)
143 m_output +=
" %1=\"%2\""_L1.arg(key, attributes[key]);
144 m_output +=
">%2</@%3>"_L1.arg(TextUtils::protect(sourceText(location)), tagName);
145 m_cursor += location.length;
150 return m_source.mid(location.offset, location.length);
154
155
156
157
158
159
160
161
162std::optional<QQmlJS::SourceLocation>
163QmlMarkupVisitor::getFullyQualifiedLocation(QQmlJS::AST::UiQualifiedId *id) {
164 if (!id || !id->identifierToken.isValid())
167 auto location = id->identifierToken;
169 for (
auto current = id->next; current; current = current->next) {
170 if (!current->identifierToken.isValid())
173 const auto currentEnd = current->identifierToken.offset + current->identifierToken.length;
174 location.length = currentEnd - location.offset;
181
182
183
184
185
186QQmlJS::SourceLocation
189 if (
auto fullLocation = getFullyQualifiedLocation(id))
190 return fullLocation.value();
191 return id->identifierToken;
195 QQmlJS::SourceLocation last)
197 if (!first.isValid())
200 quint32 start = first.begin();
205 finish = first.end();
207 if (m_cursor < start)
208 addExtra(m_cursor, start);
209 else if (m_cursor > start)
212 QString text = m_source.mid(start, finish - start);
213 m_output += TextUtils::protect(text);
219 addVerbatim(uiimport->importToken);
220 if (!uiimport->importUri)
221 addMarkedUpToken(uiimport->fileNameToken,
"headerfile"_L1);
227 if (uiimport->version)
228 addVerbatim(uiimport->version->firstSourceLocation(),
229 uiimport->version->lastSourceLocation());
230 addVerbatim(uiimport->asToken);
231 addMarkedUpToken(uiimport->importIdToken,
"headerfile"_L1);
232 addVerbatim(uiimport->semicolonToken);
237 if (member->type == QQmlJS::AST::UiPublicMember::Property) {
238 addVerbatim(member->defaultToken());
239 addVerbatim(member->readonlyToken());
240 addVerbatim(member->propertyToken());
241 addVerbatim(member->typeModifierToken);
242 addMarkedUpToken(member->typeToken,
"type"_L1);
243 addMarkedUpToken(member->identifierToken,
"name"_L1);
244 addVerbatim(member->colonToken);
246 QQmlJS::AST::Node::accept(member->binding,
this);
247 else if (member->statement)
248 QQmlJS::AST::Node::accept(member->statement,
this);
250 addVerbatim(member->propertyToken());
251 addVerbatim(member->typeModifierToken);
252 addMarkedUpToken(member->typeToken,
"type"_L1);
254 QQmlJS::AST::Node::accept(member->parameters,
this);
256 addVerbatim(member->semicolonToken);
262 addVerbatim(initializer->lbraceToken, initializer->lbraceToken);
268 addVerbatim(initializer->rbraceToken, initializer->rbraceToken);
273 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
274 addVerbatim(binding->colonToken);
275 if (
auto fullLocation = getFullyQualifiedLocation(binding->qualifiedTypeNameId))
276 addMarkedUpToken(fullLocation.value(),
"type"_L1);
278 QQmlJS::AST::Node::accept(binding->qualifiedTypeNameId,
this);
280 QQmlJS::AST::Node::accept(binding->initializer,
this);
286 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
287 addVerbatim(binding->colonToken);
288 QQmlJS::AST::Node::accept(binding->statement,
this);
294 QQmlJS::AST::Node::accept(binding->qualifiedId,
this);
295 addVerbatim(binding->colonToken);
296 addVerbatim(binding->lbracketToken);
297 QQmlJS::AST::Node::accept(binding->members,
this);
298 addVerbatim(binding->rbracketToken);
304 for (QQmlJS::AST::UiArrayMemberList *it = list; it; it = it->next) {
305 QQmlJS::AST::Node::accept(it->member,
this);
313 addMarkedUpToken(getLocationForMarkup(id),
"name"_L1);
319 addVerbatim(expression->thisToken);
325 addMarkedUpToken(identifier->identifierToken,
"name"_L1);
331 addMarkedUpToken(null->nullToken,
"number"_L1);
337 addMarkedUpToken(literal->trueToken,
"number"_L1);
343 addMarkedUpToken(literal->falseToken,
"number"_L1);
349 addMarkedUpToken(literal->literalToken,
"number"_L1);
355 addMarkedUpToken(literal->literalToken,
"string"_L1);
361 addVerbatim(literal->literalToken);
367 addVerbatim(literal->lbracketToken);
368 QQmlJS::AST::Node::accept(literal->elements,
this);
369 addVerbatim(literal->rbracketToken);
375 addVerbatim(literal->lbraceToken);
381 addVerbatim(literal->rbraceToken);
386 for (QQmlJS::AST::PatternElementList *it = list; it; it = it->next) {
387 QQmlJS::AST::Node::accept(it->element,
this);
390 QQmlJS::AST::Node::accept(list->elision,
this);
396 addVerbatim(elision->commaToken, elision->commaToken);
402 QQmlJS::AST::Node::accept(list->name,
this);
403 addVerbatim(list->colonToken, list->colonToken);
404 QQmlJS::AST::Node::accept(list->initializer,
this);
411 QQmlJS::AST::Node::accept(expression->base,
this);
412 addVerbatim(expression->lbracketToken);
413 QQmlJS::AST::Node::accept(expression->expression,
this);
414 addVerbatim(expression->rbracketToken);
420 QQmlJS::AST::Node::accept(expression->base,
this);
421 addVerbatim(expression->dotToken);
422 addMarkedUpToken(expression->identifierToken,
"name"_L1);
428 addVerbatim(expression->newToken);
429 QQmlJS::AST::Node::accept(expression->base,
this);
430 addVerbatim(expression->lparenToken);
431 QQmlJS::AST::Node::accept(expression->arguments,
this);
432 addVerbatim(expression->rparenToken);
438 addVerbatim(expression->newToken);
444 addVerbatim(list->commaToken, list->commaToken);
450 addVerbatim(expression->incrementToken);
456 addVerbatim(expression->decrementToken);
462 addVerbatim(expression->deleteToken);
468 addVerbatim(expression->voidToken);
474 addVerbatim(expression->typeofToken);
480 addVerbatim(expression->incrementToken);
486 addVerbatim(expression->decrementToken);
492 addVerbatim(expression->plusToken);
498 addVerbatim(expression->minusToken);
504 addVerbatim(expression->tildeToken);
510 addVerbatim(expression->notToken);
516 QQmlJS::AST::Node::accept(expression->left,
this);
517 addMarkedUpToken(expression->operatorToken,
"op"_L1);
518 QQmlJS::AST::Node::accept(expression->right,
this);
524 QQmlJS::AST::Node::accept(expression->expression,
this);
525 addVerbatim(expression->questionToken);
526 QQmlJS::AST::Node::accept(expression->ok,
this);
527 addVerbatim(expression->colonToken);
528 QQmlJS::AST::Node::accept(expression->ko,
this);
534 QQmlJS::AST::Node::accept(expression->left,
this);
535 addVerbatim(expression->commaToken);
536 QQmlJS::AST::Node::accept(expression->right,
this);
542 addVerbatim(block->lbraceToken);
548 addVerbatim(block->rbraceToken);
553 addVerbatim(statement->declarationKindToken);
554 QQmlJS::AST::Node::accept(statement->declarations,
this);
561 for (QQmlJS::AST::VariableDeclarationList *it = list; it; it = it->next) {
562 QQmlJS::AST::Node::accept(it->declaration,
this);
563 addVerbatim(it->commaToken);
570 addVerbatim(statement->semicolonToken);
576 QQmlJS::AST::Node::accept(statement->expression,
this);
577 addVerbatim(statement->semicolonToken);
583 addMarkedUpToken(statement->ifToken,
"keyword"_L1);
584 addVerbatim(statement->lparenToken);
585 QQmlJS::AST::Node::accept(statement->expression,
this);
586 addVerbatim(statement->rparenToken);
587 QQmlJS::AST::Node::accept(statement->ok,
this);
589 addMarkedUpToken(statement->elseToken,
"keyword"_L1);
590 QQmlJS::AST::Node::accept(statement->ko,
this);
597 addMarkedUpToken(statement->doToken,
"keyword"_L1);
598 QQmlJS::AST::Node::accept(statement->statement,
this);
599 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
600 addVerbatim(statement->lparenToken);
601 QQmlJS::AST::Node::accept(statement->expression,
this);
602 addVerbatim(statement->rparenToken);
603 addVerbatim(statement->semicolonToken);
609 addMarkedUpToken(statement->whileToken,
"keyword"_L1);
610 addVerbatim(statement->lparenToken);
611 QQmlJS::AST::Node::accept(statement->expression,
this);
612 addVerbatim(statement->rparenToken);
613 QQmlJS::AST::Node::accept(statement->statement,
this);
619 addMarkedUpToken(statement->forToken,
"keyword"_L1);
620 addVerbatim(statement->lparenToken);
621 QQmlJS::AST::Node::accept(statement->initialiser,
this);
622 addVerbatim(statement->firstSemicolonToken);
623 QQmlJS::AST::Node::accept(statement->condition,
this);
624 addVerbatim(statement->secondSemicolonToken);
625 QQmlJS::AST::Node::accept(statement->expression,
this);
626 addVerbatim(statement->rparenToken);
627 QQmlJS::AST::Node::accept(statement->statement,
this);
633 addMarkedUpToken(statement->forToken,
"keyword"_L1);
634 addVerbatim(statement->lparenToken);
635 QQmlJS::AST::Node::accept(statement->lhs,
this);
636 addVerbatim(statement->inOfToken);
637 QQmlJS::AST::Node::accept(statement->expression,
this);
638 addVerbatim(statement->rparenToken);
639 QQmlJS::AST::Node::accept(statement->statement,
this);
645 addMarkedUpToken(statement->continueToken,
"keyword"_L1);
646 addMarkedUpToken(statement->identifierToken,
"name"_L1);
647 addVerbatim(statement->semicolonToken);
653 addMarkedUpToken(statement->breakToken,
"keyword"_L1);
654 addMarkedUpToken(statement->identifierToken,
"name"_L1);
655 addVerbatim(statement->semicolonToken);
661 addMarkedUpToken(statement->returnToken,
"keyword"_L1);
662 QQmlJS::AST::Node::accept(statement->expression,
this);
663 addVerbatim(statement->semicolonToken);
669 addMarkedUpToken(statement->withToken,
"keyword"_L1);
670 addVerbatim(statement->lparenToken);
671 QQmlJS::AST::Node::accept(statement->expression,
this);
672 addVerbatim(statement->rparenToken);
673 QQmlJS::AST::Node::accept(statement->statement,
this);
679 addVerbatim(block->lbraceToken);
685 addVerbatim(block->rbraceToken, block->rbraceToken);
690 addMarkedUpToken(statement->switchToken,
"keyword"_L1);
691 addVerbatim(statement->lparenToken);
692 QQmlJS::AST::Node::accept(statement->expression,
this);
693 addVerbatim(statement->rparenToken);
694 QQmlJS::AST::Node::accept(statement->block,
this);
700 addMarkedUpToken(clause->caseToken,
"keyword"_L1);
701 QQmlJS::AST::Node::accept(clause->expression,
this);
702 addVerbatim(clause->colonToken);
703 QQmlJS::AST::Node::accept(clause->statements,
this);
709 addMarkedUpToken(clause->defaultToken,
"keyword"_L1);
710 addVerbatim(clause->colonToken, clause->colonToken);
716 addMarkedUpToken(statement->identifierToken,
"name"_L1);
717 addVerbatim(statement->colonToken);
718 QQmlJS::AST::Node::accept(statement->statement,
this);
724 addMarkedUpToken(statement->throwToken,
"keyword"_L1);
725 QQmlJS::AST::Node::accept(statement->expression,
this);
726 addVerbatim(statement->semicolonToken);
732 addMarkedUpToken(c->catchToken,
"keyword"_L1);
733 addVerbatim(c->lparenToken);
734 addMarkedUpToken(c->identifierToken,
"name"_L1);
735 addVerbatim(c->rparenToken);
741 addMarkedUpToken(f->finallyToken,
"keyword"_L1);
742 QQmlJS::AST::Node::accept(f->statement,
this);
748 addMarkedUpToken(statement->tryToken,
"keyword"_L1);
749 QQmlJS::AST::Node::accept(statement->statement,
this);
750 QQmlJS::AST::Node::accept(statement->catchExpression,
this);
751 QQmlJS::AST::Node::accept(statement->finallyExpression,
this);
757 addMarkedUpToken(expression->functionToken,
"keyword"_L1);
758 addMarkedUpToken(expression->identifierToken,
"name"_L1);
759 addVerbatim(expression->lparenToken);
760 QQmlJS::AST::Node::accept(expression->formals,
this);
761 addVerbatim(expression->rparenToken);
762 addVerbatim(expression->lbraceToken);
763 QQmlJS::AST::Node::accept(expression->body,
this);
764 addVerbatim(expression->rbraceToken);
770 addMarkedUpToken(declaration->functionToken,
"keyword"_L1);
771 addMarkedUpToken(declaration->identifierToken,
"name"_L1);
772 addVerbatim(declaration->lparenToken);
773 QQmlJS::AST::Node::accept(declaration->formals,
this);
774 addVerbatim(declaration->rparenToken);
775 addVerbatim(declaration->lbraceToken);
776 QQmlJS::AST::Node::accept(declaration->body,
this);
777 addVerbatim(declaration->rbraceToken);
783 QQmlJS::AST::Node::accept(list->element,
this);
789 addVerbatim(statement->debuggerToken);
790 addVerbatim(statement->semicolonToken);
798 if (
auto fullLocation = getFullyQualifiedLocation(definition->qualifiedTypeNameId))
799 addMarkedUpToken(fullLocation.value(),
"type"_L1);
801 QQmlJS::AST::Node::accept(definition->qualifiedTypeNameId,
this);
803 QQmlJS::AST::Node::accept(definition->initializer,
this);
809 m_hasRecursionDepthError =
true;
void throwRecursionDepthError() final
void endVisit(QQmlJS::AST::UiImport *) override
bool visit(QQmlJS::AST::UiImport *) override