Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmlirbuilder.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlirbuilder_p.h"
5
6#include <private/qv4staticvalue_p.h>
7#include <private/qv4compileddata_p.h>
8#include <private/qqmljsparser_p.h>
9#include <private/qqmljslexer_p.h>
10#include <private/qv4compilerscanfunctions_p.h>
11#include <QCoreApplication>
12#include <QCryptographicHash>
13#include <cmath>
14
16
17using namespace Qt::StringLiterals;
18
19static const quint32 emptyStringIndex = 0;
20using namespace QmlIR;
21using namespace QQmlJS;
22
23#define COMPILE_EXCEPTION(location, desc) \
24 { \
25 recordError(location, desc); \
26 return false; \
27 }
28
29void Object::simplifyRequiredProperties() {
30 // if a property of the current object was marked as required
31 // do not store that information in the ExtraData
32 // but rather mark the property as required
33 QSet<int> required;
34 for (auto it = this->requiredPropertyExtraDataBegin(); it != this->requiredPropertyExtraDataEnd(); ++it)
35 required.insert(it->nameIndex);
36 if (required.isEmpty())
37 return;
38 for (auto it = this->propertiesBegin(); it != this->propertiesEnd(); ++it) {
39 auto requiredIt = required.find(it->nameIndex);
40 if (requiredIt != required.end()) {
41 it->setIsRequired(true);
42 required.erase(requiredIt);
43 }
44 }
46 auto current = this->requiredPropertyExtraDatas->first;
47 while (current) {
48 if (required.contains(current->nameIndex))
49 prev = current;
50 else
51 requiredPropertyExtraDatas->unlink(prev, current);
52 current = current->next;
53 }
54}
55
58 const QString &typeName, int typeNameIndex,
60{
61 auto builtinType = stringToBuiltinType(typeName);
62 if (builtinType == QV4::CompiledData::CommonType::Invalid) {
63 if (typeName.isEmpty()) {
64 paramType->set(listFlag, 0);
65 return false;
66 }
67 Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
68 paramType->set(listFlag, typeNameIndex);
69 } else {
70 Q_ASSERT(quint32(builtinType) < (1u << 31));
72 static_cast<quint32>(builtinType));
73 }
74 return true;
75}
76
78{
79 static const struct TypeNameToType {
80 const char *name;
81 size_t nameLength;
83 } propTypeNameToTypes[] = {
84 { "void", strlen("void"), QV4::CompiledData::CommonType::Void },
85 { "int", strlen("int"), QV4::CompiledData::CommonType::Int },
86 { "bool", strlen("bool"), QV4::CompiledData::CommonType::Bool },
87 { "double", strlen("double"), QV4::CompiledData::CommonType::Real },
88 { "real", strlen("real"), QV4::CompiledData::CommonType::Real },
89 { "string", strlen("string"), QV4::CompiledData::CommonType::String },
90 { "url", strlen("url"), QV4::CompiledData::CommonType::Url },
91 { "date", strlen("date"), QV4::CompiledData::CommonType::DateTime },
92 { "regexp", strlen("regexp"), QV4::CompiledData::CommonType::RegExp },
93 { "rect", strlen("rect"), QV4::CompiledData::CommonType::Rect },
94 { "point", strlen("point"), QV4::CompiledData::CommonType::Point },
95 { "size", strlen("size"), QV4::CompiledData::CommonType::Size },
96 { "variant", strlen("variant"), QV4::CompiledData::CommonType::Var },
97 { "var", strlen("var"), QV4::CompiledData::CommonType::Var }
98 };
99 static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
100 sizeof(propTypeNameToTypes[0]);
101
102 for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
103 const TypeNameToType *t = propTypeNameToTypes + typeIndex;
104 if (typeName == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
105 return t->type;
106 }
107 }
109}
110
111void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex,
113{
114 Q_ASSERT(loc.line() > 0 && loc.column() > 0);
115 inheritedTypeNameIndex = typeNameIndex;
116 location = loc;
117 idNameIndex = idIndex;
118 id = -1;
122 properties = pool->New<PoolList<Property> >();
123 aliases = pool->New<PoolList<Alias> >();
124 qmlEnums = pool->New<PoolList<Enum>>();
125 qmlSignals = pool->New<PoolList<Signal> >();
126 bindings = pool->New<PoolList<Binding> >();
127 functions = pool->New<PoolList<Function> >();
129 inlineComponents = pool->New<PoolList<InlineComponent>>();
130 requiredPropertyExtraDatas = pool->New<PoolList<RequiredPropertyExtraData>>();
131 declarationsOverride = nullptr;
132}
133
135{
136 QSet<int> functionNames;
137 for (auto functionit = obj->functionsBegin(); functionit != obj->functionsEnd(); ++functionit) {
138 Function *f = functionit.ptr;
139 errorLocation->startLine = f->location.line();
140 errorLocation->startColumn = f->location.column();
141 if (functionNames.contains(f->nameIndex))
142 return tr("Duplicate method name");
143 functionNames.insert(f->nameIndex);
144
145 for (auto signalit = obj->signalsBegin(); signalit != obj->signalsEnd(); ++signalit) {
146 QmlIR::Signal *s = signalit.ptr;
147 if (s->nameIndex == f->nameIndex)
148 return tr("Duplicate method name");
149 }
150
151 const QString name = stringAt(f->nameIndex);
152 if (name.at(0).isUpper())
153 return tr("Method names cannot begin with an upper case letter");
155 return tr("Illegal method name");
156 }
157 return QString(); // no error
158}
159
161{
163 if (!target)
164 target = this;
165
166 for (Enum *e = qmlEnums->first; e; e = e->next) {
167 if (e->nameIndex == enumeration->nameIndex)
168 return tr("Duplicate scoped enum name");
169 }
170
171 target->qmlEnums->append(enumeration);
172 return QString(); // no error
173}
174
176{
178 if (!target)
179 target = this;
180
181 for (Signal *s = qmlSignals->first; s; s = s->next) {
182 if (s->nameIndex == signal->nameIndex)
183 return tr("Duplicate signal name");
184 }
185
186 target->qmlSignals->append(signal);
187 return QString(); // no error
188}
189
190QString Object::appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation)
191{
193 if (!target)
194 target = this;
195
196 for (Property *p = target->properties->first; p; p = p->next)
197 if (p->nameIndex == prop->nameIndex)
198 return tr("Duplicate property name");
199
200 for (Alias *a = target->aliases->first; a; a = a->next)
201 if (a->nameIndex() == prop->nameIndex)
202 return tr("Property duplicates alias name");
203
204 if (propertyName.constData()->isUpper())
205 return tr("Property names cannot begin with an upper case letter");
206
207 const int index = target->properties->append(prop);
208 if (isDefaultProperty) {
209 if (target->indexOfDefaultPropertyOrAlias != -1) {
210 *errorLocation = defaultToken;
211 return tr("Duplicate default property");
212 }
213 target->indexOfDefaultPropertyOrAlias = index;
214 }
215 return QString(); // no error
216}
217
218QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation)
219{
221 if (!target)
222 target = this;
223
224 const auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){
225 return targetAlias.nameIndex() == alias->nameIndex();
226 });
227 if (aliasWithSameName != target->aliases->end())
228 return tr("Duplicate alias name");
229
230 const auto aliasSameAsProperty = std::find_if(target->properties->begin(), target->properties->end(), [&alias](const Property &targetProp){
231 return targetProp.nameIndex == alias->nameIndex();
232 });
233
234 if (aliasSameAsProperty != target->properties->end())
235 return tr("Alias has same name as existing property");
236
237 if (aliasName.constData()->isUpper())
238 return tr("Alias names cannot begin with an upper case letter");
239
240 const int index = target->aliases->append(alias);
241
242 if (isDefaultProperty) {
243 if (target->indexOfDefaultPropertyOrAlias != -1) {
244 *errorLocation = defaultToken;
245 return tr("Duplicate default property");
246 }
247 target->indexOfDefaultPropertyOrAlias = index;
248 target->defaultPropertyIsAlias = true;
249 }
250
251 return QString(); // no error
252}
253
255{
256 // Unlike properties, a function definition inside a grouped property does not go into
257 // the surrounding object. It's been broken since the Qt 5 era, and the semantics
258 // seems super confusing, so it wouldn't make sense to support that.
260 functions->append(f);
261}
262
264{
265 inlineComponents->append(ic);
266}
267
269{
270 requiredPropertyExtraDatas->append(extraData);
271}
272
274{
275 const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
276 if (!isListBinding
277 && !bindingToDefaultProperty
281 Binding *existing = findBinding(b->propertyNameIndex);
282 if (existing
283 && existing->isValueBinding() == b->isValueBinding()
285 return tr("Property value set multiple times");
286 }
287 }
288 if (bindingToDefaultProperty)
290 else
291 bindings->prepend(b);
292 return QString(); // no error
293}
294
296{
297 for (Binding *b = bindings->first; b; b = b->next)
298 if (b->propertyNameIndex == nameIndex)
299 return b;
300 return nullptr;
301}
302
304{
305 Binding *insertionPoint = bindings->findSortedInsertionPoint<quint32, Binding, &Binding::offset>(b);
306 bindings->insertAfter(insertionPoint, b);
307}
308
309QString Object::bindingAsString(Document *doc, int scriptIndex) const
310{
311 CompiledFunctionOrExpression *foe = functionsAndExpressions->slowAt(scriptIndex);
312 QQmlJS::AST::Node *node = foe->node;
313 if (QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(node))
314 node = exprStmt->expression;
317 return doc->code.mid(start.offset, end.offset + end.length - start.offset);
318}
319
321{
323 result.reserve(parameters->count);
324 for (Parameter *param = parameters->first; param; param = param->next)
325 result << stringPool->stringForIndex(param->nameIndex);
326 return result;
327}
328
329Document::Document(bool debugMode)
330 : jsModule(debugMode)
332 , jsGenerator(&jsModule)
333{
334}
335
337 : document(doc)
338 , engine(&doc->jsParserEngine)
339 , jsGenerator(&doc->jsGenerator)
340{
341}
342
344{
346}
347
348void ScriptDirectivesCollector::importFile(const QString &jsfile, const QString &module, int lineNumber, int column)
349{
352 import->uriIndex = jsGenerator->registerString(jsfile);
353 import->qualifierIndex = jsGenerator->registerString(module);
354 import->location.set(lineNumber, column);
355 document->imports << import;
356}
357
358void ScriptDirectivesCollector::importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column)
359{
362 import->uriIndex = jsGenerator->registerString(uri);
363 import->version = IRBuilder::extractVersion(version);
364 import->qualifierIndex = jsGenerator->registerString(module);
365 import->location.set(lineNumber, column);
366 document->imports << import;
367}
368
370 : illegalNames(illegalNames)
371 , _object(nullptr)
372 , _propertyDeclaration(nullptr)
373 , pool(nullptr)
374 , jsGenerator(nullptr)
375{
376}
377
379{
381 {
382 QQmlJS::Lexer lexer(&output->jsParserEngine);
383 lexer.setCode(code, /*line = */ 1);
384
385 QQmlJS::Parser parser(&output->jsParserEngine);
386
387 const bool parseResult = parser.parse();
388 const auto diagnosticMessages = parser.diagnosticMessages();
389 if (!parseResult || !diagnosticMessages.isEmpty()) {
390 // Extract errors from the parser
391 for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
392 if (m.isWarning()) {
393 qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
394 continue;
395 }
396
397 errors << m;
398 }
399
400 if (!errors.isEmpty() || !parseResult)
401 return false;
402 }
403 program = parser.ast();
405 }
406
407 output->code = code;
408 output->program = program;
409
410 qSwap(_imports, output->imports);
411 qSwap(_pragmas, output->pragmas);
412 qSwap(_objects, output->objects);
413 this->pool = output->jsParserEngine.pool();
414 this->jsGenerator = &output->jsGenerator;
415
417
418 sourceCode = code;
419
420 accept(program->headers);
421
422 if (program->members->next) {
423 QQmlJS::SourceLocation loc = program->members->next->firstSourceLocation();
424 recordError(loc, QCoreApplication::translate("QQmlParser", "Unexpected object definition"));
425 return false;
426 }
427
428 QQmlJS::AST::UiObjectDefinition *rootObject = QQmlJS::AST::cast<QQmlJS::AST::UiObjectDefinition*>(program->members->member);
429 Q_ASSERT(rootObject);
430 int rootObjectIndex = -1;
431 if (defineQMLObject(&rootObjectIndex, rootObject)) {
432 Q_ASSERT(rootObjectIndex == 0);
433 }
434
435 qSwap(_imports, output->imports);
436 qSwap(_pragmas, output->pragmas);
437 qSwap(_objects, output->objects);
438
439 for (auto object: output->objects)
440 object->simplifyRequiredProperties();
441
442 return errors.isEmpty();
443}
444
446{
447 if (name.size() < 3) return false;
448 if (!name.startsWith(QLatin1String("on"))) return false;
449 int ns = name.size();
450 for (int i = 2; i < ns; ++i) {
451 const QChar curr = name.at(i);
452 if (curr.unicode() == '_') continue;
453 if (curr.isUpper()) return true;
454 return false;
455 }
456 return false; // consists solely of underscores - invalid.
457}
458
460{
461 Q_ASSERT(signalPropertyName.startsWith(QLatin1String("on")));
462 QString signalNameCandidate = signalPropertyName;
463 signalNameCandidate.remove(0, 2);
464
465 // Note that the property name could start with any alpha or '_' or '$' character,
466 // so we need to do the lower-casing of the first alpha character.
467 for (int firstAlphaIndex = 0; firstAlphaIndex < signalNameCandidate.size(); ++firstAlphaIndex) {
468 if (signalNameCandidate.at(firstAlphaIndex).isUpper()) {
469 signalNameCandidate[firstAlphaIndex] = signalNameCandidate.at(firstAlphaIndex).toLower();
470 return signalNameCandidate;
471 }
472 }
473
474 Q_UNREACHABLE_RETURN(QString());
475}
476
478{
479 return QQmlJS::AST::Visitor::visit(ast);
480}
481
483{
484 Q_ASSERT(!"should not happen");
485 return false;
486}
487
489{
490 // The grammar can't distinguish between two different definitions here:
491 // Item { ... }
492 // versus
493 // font { ... }
494 // The former is a new binding with no property name and "Item" as type name,
495 // and the latter is a binding to the font property with no type name but
496 // only initializer.
497
499 while (lastId->next)
500 lastId = lastId->next;
501 bool isType = lastId->name.data()->isUpper();
502 if (isType) {
503 int idx = 0;
504 if (!defineQMLObject(&idx, node))
505 return false;
507 appendBinding(nameLocation, nameLocation, emptyStringIndex, idx);
508 } else {
509 int idx = 0;
511 if (!defineQMLObject(
512 &idx, /*qualfied type name id*/nullptr,
513 { location.startLine, location.startColumn }, node->initializer,
514 /*declarations should go here*/_object)) {
515 return false;
516 }
518 }
519 return false;
520}
521
523{
524 int idx = -1;
526 recordError(ast->firstSourceLocation(), QLatin1String("Nested inline components are not supported"));
527 return false;
528 }
530 recordError(ast->firstSourceLocation(), QLatin1String("Inline component names must be unique per file"));
531 return false;
532 } else {
534 }
535 {
537 if (!defineQMLObject(&idx, ast->component))
538 return false;
539 }
540 Q_ASSERT(idx > 0);
541 Object* definedObject = _objects.at(idx);
544 auto inlineComponent = New<InlineComponent>();
545 inlineComponent->nameIndex = registerString(ast->name.toString());
546 inlineComponent->objectIndex = idx;
547 auto location = ast->firstSourceLocation();
548 inlineComponent->location.set(location.startLine, location.startColumn);
549 _object->appendInlineComponent(inlineComponent);
550 return false;
551}
552
554{
555 int idx = 0;
557 if (!defineQMLObject(&idx, node->qualifiedTypeNameId,
558 { location.startLine, location.startColumn }, node->initializer)) {
559 return false;
560 }
561 appendBinding(node->qualifiedId, idx, node->hasOnToken);
562 return false;
563}
564
566{
567 appendBinding(node->qualifiedId, node->statement, node);
568 return false;
569}
570
572{
573 const QQmlJS::SourceLocation qualifiedNameLocation = node->qualifiedId->identifierToken;
574 Object *object = nullptr;
576 if (!resolveQualifiedId(&name, &object))
577 return false;
578
579 qSwap(_object, object);
580
581 const int propertyNameIndex = registerString(name->name.toString());
582
583 if (bindingsTarget()->findBinding(propertyNameIndex) != nullptr) {
584 recordError(name->identifierToken, tr("Property value set multiple times"));
585 return false;
586 }
587
590 while (member) {
591 memberList.append(member);
592 member = member->next;
593 }
594 for (int i = memberList.size() - 1; i >= 0; --i) {
595 member = memberList.at(i);
596 QQmlJS::AST::UiObjectDefinition *def = QQmlJS::AST::cast<QQmlJS::AST::UiObjectDefinition*>(member->member);
597
598 int idx = 0;
599 if (!defineQMLObject(&idx, def))
600 return false;
601 appendBinding(qualifiedNameLocation, name->identifierToken, propertyNameIndex, idx, /*isListItem*/ true);
602 }
603
604 qSwap(_object, object);
605 return false;
606}
607
609{
610 return QQmlJS::AST::Visitor::visit(list);
611}
612
614{
615 return QQmlJS::AST::Visitor::visit(ast);
616}
617
619{
620 return QQmlJS::AST::Visitor::visit(ast);
621}
622
624{
625 return QQmlJS::AST::Visitor::visit(ast);
626}
627
629{
630 return QQmlJS::AST::Visitor::visit(id);
631}
632
634{
635 QQmlJS::AST::Node::accept(node, this);
636}
637
639 int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId,
641 Object *declarationsOverride)
642{
643 if (QQmlJS::AST::UiQualifiedId *lastName = qualifiedTypeNameId) {
644 while (lastName->next)
645 lastName = lastName->next;
646 if (!lastName->name.constData()->isUpper()) {
647 recordError(lastName->identifierToken, tr("Expected type name"));
648 return false;
649 }
650 }
651
652 Object *obj = New<Object>();
653
654 _objects.append(obj);
655 *objectIndex = _objects.size() - 1;
656 qSwap(_object, obj);
657
659 _object->declarationsOverride = declarationsOverride;
662 }
663
664 // A new object is also a boundary for property declarations.
665 Property *declaration = nullptr;
666 qSwap(_propertyDeclaration, declaration);
667
668 accept(initializer);
669
670 qSwap(_propertyDeclaration, declaration);
671
672 qSwap(_object, obj);
673
674 if (!errors.isEmpty())
675 return false;
676
679 if (!error.isEmpty()) {
680 recordError(loc, error);
681 return false;
682 }
683
684 return true;
685}
686
688{
689 QString uri;
690 QV4::CompiledData::Import *import = New<QV4::CompiledData::Import>();
691
692 if (!node->fileName.isNull()) {
693 uri = node->fileName.toString();
694
695 if (uri.endsWith(QLatin1String(".js")) || uri.endsWith(QLatin1String(".mjs"))) {
697 } else {
699 }
700 } else {
702 uri = asString(node->importUri);
703 }
704
705 import->qualifierIndex = emptyStringIndex;
706
707 // Qualifier
708 if (!node->importId.isNull()) {
709 QString qualifier = node->importId.toString();
710 if (!qualifier.at(0).isUpper()) {
711 recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Invalid import qualifier ID"));
712 return false;
713 }
714 if (qualifier == QLatin1String("Qt")) {
715 recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Reserved name \"Qt\" cannot be used as an qualifier"));
716 return false;
717 }
718 import->qualifierIndex = registerString(qualifier);
719
720 // Check for script qualifier clashes
722 for (int ii = 0; ii < _imports.size(); ++ii) {
724 bool otherIsScript = other->type == QV4::CompiledData::Import::ImportScript;
725
726 if ((isScript || otherIsScript) && qualifier == jsGenerator->stringForIndex(other->qualifierIndex)) {
727 recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique."));
728 return false;
729 }
730 }
731
732 } else if (import->type == QV4::CompiledData::Import::ImportScript) {
733 recordError(node->fileNameToken, QCoreApplication::translate("QQmlParser","Script import requires a qualifier"));
734 return false;
735 }
736
737 if (node->version) {
738 import->version = node->version->version;
739 } else {
740 // Otherwise initialize the major and minor version to invalid to signal "latest".
741 import->version = QTypeRevision();
742 }
743
744 import->location.set(node->importToken.startLine, node->importToken.startColumn);
745
746 import->uriIndex = registerString(uri);
747
748 _imports.append(import);
749
750 return false;
751}
752
753
754template<typename Argument>
756{
757 static bool run(IRBuilder *builder, QQmlJS::AST::UiPragma *node, Pragma *pragma)
758 {
759 Q_ASSERT(builder);
760 Q_ASSERT(node);
761 Q_ASSERT(pragma);
762
763 if (!isUnique(builder)) {
764 builder->recordError(
766 "QQmlParser", "Multiple %1 pragmas found").arg(name()));
767 return false;
768 }
769
770 pragma->type = type();
771
772 if (QQmlJS::AST::UiPragmaValueList *bad = assign(pragma, node->values)) {
773 builder->recordError(
775 "QQmlParser", "Unknown %1 '%2' in pragma").arg(name(), bad->value));
776 return false;
777 }
778
779 return true;
780 }
781
782private:
783 static constexpr Pragma::PragmaType type()
784 {
785 if constexpr (std::is_same_v<Argument, Pragma::ComponentBehaviorValue>) {
787 } else if constexpr (std::is_same_v<Argument, Pragma::ListPropertyAssignBehaviorValue>) {
789 } else if constexpr (std::is_same_v<Argument, Pragma::FunctionSignatureBehaviorValue>) {
791 } else if constexpr (std::is_same_v<Argument, Pragma::NativeMethodBehaviorValue>) {
793 } else if constexpr (std::is_same_v<Argument, Pragma::ValueTypeBehaviorValue>) {
795 }
796
797 Q_UNREACHABLE_RETURN(Pragma::PragmaType(-1));
798 }
799
800 template<typename F>
801 static QQmlJS::AST::UiPragmaValueList *iterateValues(
803 {
804 for (QQmlJS::AST::UiPragmaValueList *i = input; i; i = i->next) {
805 if (!process(i->value))
806 return i;
807 }
808 return nullptr;
809 }
810
811 static QQmlJS::AST::UiPragmaValueList *assign(
813 {
814 // We could use QMetaEnum here to make the code more compact,
815 // but it's probably more expensive.
816
817 if constexpr (std::is_same_v<Argument, Pragma::ComponentBehaviorValue>) {
818 return iterateValues(values, [pragma](QStringView value) {
819 if (value == "Unbound"_L1) {
821 return true;
822 }
823 if (value == "Bound"_L1) {
825 return true;
826 }
827 return false;
828 });
829 } else if constexpr (std::is_same_v<Argument, Pragma::ListPropertyAssignBehaviorValue>) {
830 return iterateValues(values, [pragma](QStringView value) {
831 if (value == "Append"_L1) {
833 return true;
834 }
835 if (value == "Replace"_L1) {
837 return true;
838 }
839 if (value == "ReplaceIfNotDefault"_L1) {
841 return true;
842 }
843 return false;
844 });
845 } else if constexpr (std::is_same_v<Argument, Pragma::FunctionSignatureBehaviorValue>) {
846 return iterateValues(values, [pragma](QStringView value) {
847 if (value == "Ignored"_L1) {
849 return true;
850 }
851 if (value == "Enforced"_L1) {
853 return true;
854 }
855 return false;
856 });
857 } else if constexpr (std::is_same_v<Argument, Pragma::NativeMethodBehaviorValue>) {
858 return iterateValues(values, [pragma](QStringView value) {
859 if (value == "AcceptThisObject"_L1) {
861 return true;
862 }
863 if (value == "RejectThisObject"_L1) {
865 return true;
866 }
867 return false;
868 });
869 } else if constexpr (std::is_same_v<Argument, Pragma::ValueTypeBehaviorValue>) {
870 pragma->valueTypeBehavior = Pragma::ValueTypeBehaviorValues().toInt();
871 return iterateValues(values, [pragma](QStringView value) {
872 const auto setFlag = [pragma](Pragma::ValueTypeBehaviorValue flag, bool value) {
873 pragma->valueTypeBehavior
874 = Pragma::ValueTypeBehaviorValues(pragma->valueTypeBehavior)
875 .setFlag(flag, value).toInt();
876 };
877
878 if (value == "Reference"_L1) {
879 setFlag(Pragma::Copy, false);
880 return true;
881 }
882 if (value == "Copy"_L1) {
883 setFlag(Pragma::Copy, true);
884 return true;
885 }
886
887 if (value == "Inaddressable"_L1) {
888 setFlag(Pragma::Addressable, false);
889 return true;
890 }
891 if (value == "Addressable"_L1) {
892 setFlag(Pragma::Addressable, true);
893 return true;
894 }
895
896 return false;
897 });
898 }
899
900 Q_UNREACHABLE_RETURN(nullptr);
901 }
902
903 static bool isUnique(IRBuilder *builder)
904 {
905 for (const Pragma *prev : builder->_pragmas) {
906 if (prev->type == type())
907 return false;
908 }
909 return true;
910 };
911
912 static QLatin1StringView name()
913 {
914 switch (type()) {
916 return "list property assign behavior"_L1;
918 return "component behavior"_L1;
920 return "function signature behavior"_L1;
922 return "native method behavior"_L1;
924 return "value type behavior"_L1;
925 default:
926 break;
927 }
928 Q_UNREACHABLE_RETURN(QLatin1StringView());
929 }
930};
931
933{
934 Pragma *pragma = New<Pragma>();
935
936 if (!node->name.isNull()) {
937 if (node->name == "Singleton"_L1) {
938 pragma->type = Pragma::Singleton;
939 } else if (node->name == "Strict"_L1) {
940 pragma->type = Pragma::Strict;
941 } else if (node->name == "ComponentBehavior"_L1) {
943 return false;
944 } else if (node->name == "ListPropertyAssignBehavior"_L1) {
946 return false;
947 } else if (node->name == "FunctionSignatureBehavior"_L1) {
949 return false;
950 } else if (node->name == "NativeMethodBehavior"_L1) {
952 return false;
953 } else if (node->name == "ValueTypeBehavior"_L1) {
955 return false;
956 } else {
958 "QQmlParser", "Unknown pragma '%1'").arg(node->name));
959 return false;
960 }
961 } else {
963 "QQmlParser", "Empty pragma found"));
964 return false;
965 }
966
968 _pragmas.append(pragma);
969
970 return false;
971}
972
974{
976 QString name =
977 static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
978 return QStringList() << name;
981
983 if (rv.isEmpty())
984 return rv;
985 rv.append(expr->name.toString());
986 return rv;
987 }
988 return QStringList();
989}
990
992{
993 Enum *enumeration = New<Enum>();
994 QString enumName = node->name.toString();
995 enumeration->nameIndex = registerString(enumName);
996
997 if (enumName.at(0).isLower())
998 COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter"));
999
1000 enumeration->location.set(node->enumToken.startLine, node->enumToken.startColumn);
1001
1002 enumeration->enumValues = New<PoolList<EnumValue>>();
1003
1005 while (e) {
1006 EnumValue *enumValue = New<EnumValue>();
1007 QString member = e->member.toString();
1008 enumValue->nameIndex = registerString(member);
1009 if (member.at(0).isLower())
1010 COMPILE_EXCEPTION(e->memberToken, tr("Enum names must begin with an upper case letter"));
1011
1012 double part;
1013 if (std::modf(e->value, &part) != 0.0)
1014 COMPILE_EXCEPTION(e->valueToken, tr("Enum value must be an integer"));
1015 if (e->value > std::numeric_limits<qint32>::max() || e->value < std::numeric_limits<qint32>::min())
1016 COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range"));
1017 enumValue->value = e->value;
1018
1019 enumValue->location.set(e->memberToken.startLine, e->memberToken.startColumn);
1020 enumeration->enumValues->append(enumValue);
1021
1022 e = e->next;
1023 }
1024
1025 QString error = _object->appendEnum(enumeration);
1026 if (!error.isEmpty()) {
1027 recordError(node->enumToken, error);
1028 return false;
1029 }
1030
1031 return false;
1032}
1033
1034
1036{
1038 Signal *signal = New<Signal>();
1039 const QString signalName = node->name.toString();
1040 signal->nameIndex = registerString(signalName);
1041
1043 signal->location.set(loc.startLine, loc.startColumn);
1044
1045 signal->parameters = New<PoolList<Parameter> >();
1046
1048 while (p) {
1049 if (!p->type) {
1050 recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected parameter type"));
1051 return false;
1052 }
1053
1054 Parameter *param = New<Parameter>();
1055 param->nameIndex = registerString(p->name.toString());
1057 &param->type, [this](const QString &str) { return registerString(str); },
1058 p->type)) {
1059 QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
1060 errStr.append(p->type->toString());
1061 recordError(node->typeToken, errStr);
1062 return false;
1063 }
1064 signal->parameters->append(param);
1065 p = p->next;
1066 }
1067
1068 for (const QChar &ch : signalName) {
1069 if (ch.isLower())
1070 break;
1071 if (ch.isUpper()) {
1073 tr("Signal names cannot begin with an upper case letter"));
1074 }
1075 }
1076
1077 if (illegalNames.contains(signalName))
1078 COMPILE_EXCEPTION(node->identifierToken, tr("Illegal signal name"));
1079
1081 if (!error.isEmpty()) {
1083 return false;
1084 }
1085 } else {
1086 QString memberType = asString(node->memberType);
1087 if (memberType == QLatin1String("alias")) {
1088 return appendAlias(node);
1089 } else {
1090 QStringView name = node->name;
1091
1092 Property *property = New<Property>();
1093 property->setIsReadOnly(node->isReadonly());
1094 property->setIsRequired(node->isRequired());
1095
1096 const QV4::CompiledData::CommonType builtinPropertyType
1097 = Parameter::stringToBuiltinType(memberType);
1098 if (builtinPropertyType != QV4::CompiledData::CommonType::Invalid)
1099 property->setCommonType(builtinPropertyType);
1100 else
1101 property->setTypeNameIndex(registerString(memberType));
1102
1103 QStringView typeModifier = node->typeModifier;
1104 if (typeModifier == QLatin1String("list")) {
1105 property->setIsList(true);
1106 } else if (!typeModifier.isEmpty()) {
1107 recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
1108 return false;
1109 }
1110
1111 const QString propName = name.toString();
1112 property->nameIndex = registerString(propName);
1113
1115 property->location.set(loc.startLine, loc.startColumn);
1116
1117 QQmlJS::SourceLocation errorLocation;
1118 QString error;
1119
1120 if (illegalNames.contains(propName))
1121 error = tr("Illegal property name");
1122 else
1123 error = _object->appendProperty(property, propName, node->isDefaultMember(), node->defaultToken(), &errorLocation);
1124
1125 if (!error.isEmpty()) {
1126 if (errorLocation.startLine == 0)
1127 errorLocation = node->identifierToken;
1128
1129 recordError(errorLocation, error);
1130 return false;
1131 }
1132
1134 if (node->binding) {
1135 // process QML-like initializers (e.g. property Object o: Object {})
1137 } else if (node->statement) {
1140 }
1142 }
1143 }
1144
1145 return false;
1146}
1147
1149{
1152 // See Object::appendFunction() for why.
1155 "QQmlParser", "Function declaration inside grouped property"));
1156 return false;
1157 }
1158
1159 CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
1160 foe->node = funDecl;
1161 foe->parentNode = funDecl;
1162 foe->nameIndex = registerString(funDecl->name.toString());
1163 const int index = _object->functionsAndExpressions->append(foe);
1164
1165 Function *f = New<Function>();
1166 QQmlJS::SourceLocation loc = funDecl->identifierToken;
1167 f->location.set(loc.startLine, loc.startColumn);
1168 f->index = index;
1169 f->nameIndex = registerString(funDecl->name.toString());
1170
1171 const auto idGenerator = [this](const QString &str) { return registerString(str); };
1172
1174 &f->returnType, idGenerator,
1175 funDecl->typeAnnotation ? funDecl->typeAnnotation->type : nullptr);
1176
1177 const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames();
1178 int formalsCount = formals.size();
1179 f->formals.allocate(pool, formalsCount);
1180
1181 int i = 0;
1182 for (const auto &arg : formals) {
1183 Parameter *functionParameter = &f->formals[i];
1184 functionParameter->nameIndex = registerString(arg.id);
1186 &functionParameter->type, idGenerator,
1187 arg.typeAnnotation.isNull() ? nullptr : arg.typeAnnotation->type);
1188 ++i;
1189 }
1190
1192 } else {
1193 recordError(node->firstSourceLocation(), QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
1194 }
1195 return false;
1196}
1197
1199{
1200 auto extraData = New<RequiredPropertyExtraData>();
1201 extraData->nameIndex = registerString(ast->name.toString());
1203 return false;
1204}
1205
1207{
1208 QString s;
1209
1210 for (QQmlJS::AST::UiQualifiedId *it = node; it; it = it->next) {
1211 s.append(it->name);
1212
1213 if (it->next)
1214 s.append(QLatin1Char('.'));
1215 }
1216
1217 return s;
1218}
1219
1221{
1222 if (!node)
1223 return QStringView();
1224
1225 return textRefAt(node->firstSourceLocation(), node->lastSourceLocation());
1226}
1227
1229{
1230 if (string.isEmpty())
1231 return QTypeRevision();
1232
1233 const int dot = string.indexOf(QLatin1Char('.'));
1234 return (dot < 0)
1236 : QTypeRevision::fromVersion(string.left(dot).toInt(), string.mid(dot + 1).toInt());
1237}
1238
1240{
1241 return QStringView(sourceCode).mid(first.offset, last.offset + last.length - first.offset);
1242}
1243
1245{
1247 binding->valueLocation.set(loc.startLine, loc.startColumn);
1251
1252 QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
1253 if (exprStmt) {
1254 QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
1255 if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr)) {
1257 binding->stringIndex = registerString(lit->value.toString());
1258 } else if (QQmlJS::AST::TemplateLiteral *templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
1259 templateLit && templateLit->hasNoSubstitution) {
1260 // A template literal without substitution is just a string.
1261 // With substitution, it could however be an arbitrarily complex expression
1263 binding->stringIndex = registerString(templateLit->value.toString());
1264 } else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral) {
1266 binding->value.b = true;
1267 } else if (expr->kind == QQmlJS::AST::Node::Kind_FalseLiteral) {
1269 binding->value.b = false;
1270 } else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
1273 } else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
1274 if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) {
1275 tryGeneratingTranslationBinding(base->name, call->arguments, binding);
1276 // If it wasn't a translation binding, a normal script binding will be generated
1277 // below.
1278 }
1279 } else if (QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(expr)) {
1281 } else if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
1282 if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
1285 }
1286 } else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) {
1288 binding->value.nullMarker = 0;
1289 }
1290 }
1291
1292 // Do binding instead
1295
1296 CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
1297 expr->node = statement;
1298 expr->parentNode = parentNode;
1299 expr->nameIndex = registerString(QLatin1String("expression for ")
1300 + stringAt(binding->propertyNameIndex));
1301 const int index = bindingsTarget()->functionsAndExpressions->append(expr);
1302 binding->value.compiledScriptIndex = index;
1303 // We don't need to store the binding script as string, except for script strings
1304 // and types with custom parsers. Those will be added later in the compilation phase.
1305 // Except that we cannot recover the string when cachegen runs; we need to therefore retain
1306 // "undefined". Any other "special" strings (for the various literals) are already handled above
1307 QQmlJS::AST::Node *nodeForString = statement;
1308 if (exprStmt)
1309 nodeForString = exprStmt->expression;
1310 if (asStringRef(nodeForString) == u"undefined")
1311 binding->stringIndex = registerString(u"undefined"_s);
1312 else
1313 binding->stringIndex = emptyStringIndex;
1314 }
1315}
1316
1318{
1319 const auto registerString = [&](QStringView string) {
1320 return jsGenerator->registerString(string.toString()) ;
1321 };
1322
1323 const auto finalizeTranslationData = [&](
1325 QV4::CompiledData::TranslationData translationData) {
1326 binding->setType(type);
1329 binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
1331 binding->stringIndex = translationData.number;
1332 }
1333 };
1334
1336 base, args,
1337 registerString, registerString, registerString, finalizeTranslationData);
1338}
1339
1341{
1342 const QQmlJS::SourceLocation qualifiedNameLocation = name->identifierToken;
1343 Object *object = nullptr;
1344 if (!resolveQualifiedId(&name, &object))
1345 return;
1346 if (_object == object && name->name == QLatin1String("id")) {
1347 setId(name->identifierToken, value);
1348 return;
1349 }
1350 qSwap(_object, object);
1351 appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), value, parentNode);
1352 qSwap(_object, object);
1353}
1354
1355void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment)
1356{
1357 const QQmlJS::SourceLocation qualifiedNameLocation = name->identifierToken;
1358 Object *object = nullptr;
1359 if (!resolveQualifiedId(&name, &object, isOnAssignment))
1360 return;
1361 qSwap(_object, object);
1362 appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), objectIndex, /*isListItem*/false, isOnAssignment);
1363 qSwap(_object, object);
1364}
1365
1366void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation, const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex,
1368{
1369 Binding *binding = New<Binding>();
1370 binding->propertyNameIndex = propertyNameIndex;
1371 binding->offset = nameLocation.offset;
1372 binding->location.set(nameLocation.startLine, nameLocation.startColumn);
1373 binding->clearFlags();
1374 setBindingValue(binding, value, parentNode);
1375 QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false);
1376 if (!error.isEmpty()) {
1377 recordError(qualifiedNameLocation, error);
1378 }
1379}
1380
1381void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation, const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
1382{
1383 if (stringAt(propertyNameIndex) == QLatin1String("id")) {
1384 recordError(nameLocation, tr("Invalid component id specification"));
1385 return;
1386 }
1387
1388 Binding *binding = New<Binding>();
1389 binding->propertyNameIndex = propertyNameIndex;
1390 binding->offset = nameLocation.offset;
1391 binding->location.set(nameLocation.startLine, nameLocation.startColumn);
1392
1393 const Object *obj = _objects.at(objectIndex);
1394 binding->valueLocation = obj->location;
1395
1396 binding->clearFlags();
1397
1400
1401 // No type name on the initializer means it must be a group property
1402 if (_objects.at(objectIndex)->inheritedTypeNameIndex == emptyStringIndex)
1404 else
1405 binding->setType(Binding::Type_Object);
1406
1407 if (isOnAssignment)
1409 if (isListItem)
1410 binding->setFlag(Binding::IsListItem);
1411
1412 binding->value.objectIndex = objectIndex;
1413 QString error = bindingsTarget()->appendBinding(binding, isListItem);
1414 if (!error.isEmpty()) {
1415 recordError(qualifiedNameLocation, error);
1416 }
1417}
1418
1420{
1421 Alias *alias = New<Alias>();
1422 alias->clearFlags();
1423 if (node->isReadonly())
1425
1426 const QString propName = node->name.toString();
1427 alias->setNameIndex(registerString(propName));
1428
1430 alias->location.set(loc.startLine, loc.startColumn);
1431
1433
1434 if (!node->statement && !node->binding)
1435 COMPILE_EXCEPTION(loc, tr("No property alias location"));
1436
1438 if (node->binding)
1439 rhsLoc = node->binding->firstSourceLocation();
1440 else if (node->statement)
1441 rhsLoc = node->statement->firstSourceLocation();
1442 else
1443 rhsLoc = node->semicolonToken;
1444 alias->referenceLocation.set(rhsLoc.startLine, rhsLoc.startColumn);
1445
1446 QStringList aliasReference;
1447
1448 if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) {
1449 aliasReference = astNodeToStringList(stmt->expression);
1450 if (aliasReference.isEmpty()) {
1451 if (isStatementNodeScript(node->statement)) {
1452 COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
1453 } else {
1454 COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location"));
1455 }
1456 }
1457 } else {
1458 COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
1459 }
1460
1461 if (aliasReference.size() < 1 || aliasReference.size() > 3)
1462 COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
1463
1464 alias->setIdIndex(registerString(aliasReference.first()));
1465
1466 QString propertyValue = aliasReference.value(1);
1467 if (aliasReference.size() == 3)
1468 propertyValue += QLatin1Char('.') + aliasReference.at(2);
1469 alias->propertyNameIndex = registerString(propertyValue);
1470
1471 QQmlJS::SourceLocation errorLocation;
1472 QString error;
1473
1474 if (illegalNames.contains(propName))
1475 error = tr("Illegal property name");
1476 else
1477 error = _object->appendAlias(alias, propName, node->isDefaultMember(), node->defaultToken(), &errorLocation);
1478
1479 if (!error.isEmpty()) {
1480 if (errorLocation.startLine == 0)
1481 errorLocation = node->identifierToken;
1482
1483 recordError(errorLocation, error);
1484 return false;
1485 }
1486
1487 return false;
1488}
1489
1491{
1494 return _object;
1495}
1496
1498{
1499 QQmlJS::SourceLocation loc = value->firstSourceLocation();
1501
1502 QQmlJS::AST::Node *node = value;
1503 if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(node)) {
1504 if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(stmt->expression)) {
1505 str = lit->value;
1506 node = nullptr;
1507 } else
1508 node = stmt->expression;
1509 }
1510
1511 if (node && str.isEmpty())
1512 str = asStringRef(node);
1513
1514 if (str.isEmpty())
1515 COMPILE_EXCEPTION(loc, tr( "Invalid empty ID"));
1516
1517 QChar ch = str.at(0);
1518 if (ch.isLetter() && !ch.isLower())
1519 COMPILE_EXCEPTION(loc, tr( "IDs cannot start with an uppercase letter"));
1520
1521 QChar u(QLatin1Char('_'));
1522 if (!ch.isLetter() && ch != u)
1523 COMPILE_EXCEPTION(loc, tr( "IDs must start with a letter or underscore"));
1524
1525 for (int ii = 1; ii < str.size(); ++ii) {
1526 ch = str.at(ii);
1527 if (!ch.isLetterOrNumber() && ch != u)
1528 COMPILE_EXCEPTION(loc, tr( "IDs must contain only letters, numbers, and underscores"));
1529 }
1530
1531 QString idQString(str.toString());
1532 if (illegalNames.contains(idQString))
1533 COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property"));
1534
1536 COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
1537
1538 _object->idNameIndex = registerString(idQString);
1539 _object->locationOfIdProperty.set(idLocation.startLine, idLocation.startColumn);
1540
1541 return true;
1542}
1543
1544bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object, bool onAssignment)
1545{
1546 QQmlJS::AST::UiQualifiedId *qualifiedIdElement = *nameToResolve;
1547
1548 if (qualifiedIdElement->name == QLatin1String("id") && qualifiedIdElement->next)
1549 COMPILE_EXCEPTION(qualifiedIdElement->identifierToken, tr( "Invalid use of id property"));
1550
1551 // If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type.
1552 QString currentName = qualifiedIdElement->name.toString();
1553 if (qualifiedIdElement->next) {
1554 for (const QV4::CompiledData::Import* import : std::as_const(_imports))
1555 if (import->qualifierIndex != emptyStringIndex
1556 && stringAt(import->qualifierIndex) == currentName) {
1557 qualifiedIdElement = qualifiedIdElement->next;
1558 currentName += QLatin1Char('.') + qualifiedIdElement->name;
1559
1560 if (!qualifiedIdElement->name.data()->isUpper())
1561 COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr("Expected type name"));
1562
1563 break;
1564 }
1565 }
1566
1567 *object = _object;
1568 while (qualifiedIdElement->next) {
1569 const quint32 propertyNameIndex = registerString(currentName);
1570 const bool isAttachedProperty = qualifiedIdElement->name.data()->isUpper();
1571
1572 Binding *binding = (*object)->findBinding(propertyNameIndex);
1573 if (binding) {
1574 if (isAttachedProperty) {
1575 if (!binding->isAttachedProperty())
1576 binding = nullptr;
1577 } else if (!binding->isGroupProperty()) {
1578 binding = nullptr;
1579 }
1580 }
1581 if (!binding) {
1582 binding = New<Binding>();
1583 binding->propertyNameIndex = propertyNameIndex;
1584 binding->offset = qualifiedIdElement->identifierToken.offset;
1585 binding->location.set(qualifiedIdElement->identifierToken.startLine,
1586 qualifiedIdElement->identifierToken.startColumn);
1587 binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine,
1588 qualifiedIdElement->next->identifierToken.startColumn);
1589 binding->clearFlags();
1590
1591 if (onAssignment)
1593
1594 if (isAttachedProperty)
1596 else
1598
1599 int objIndex = 0;
1600 if (!defineQMLObject(&objIndex, nullptr, binding->location, nullptr, nullptr))
1601 return false;
1602 binding->value.objectIndex = objIndex;
1603
1604 QString error = (*object)->appendBinding(binding, /*isListBinding*/false);
1605 if (!error.isEmpty()) {
1606 recordError(qualifiedIdElement->identifierToken, error);
1607 return false;
1608 }
1609 *object = _objects.at(objIndex);
1610 } else {
1611 Q_ASSERT(binding->isAttachedProperty() || binding->isGroupProperty());
1612 *object = _objects.at(binding->value.objectIndex);
1613 }
1614
1615 qualifiedIdElement = qualifiedIdElement->next;
1616 if (qualifiedIdElement)
1617 currentName = qualifiedIdElement->name.toString();
1618 }
1619 *nameToResolve = qualifiedIdElement;
1620 return true;
1621}
1622
1624{
1626 error.loc = location;
1627 error.message = description;
1628 errors << error;
1629}
1630
1632{
1633 if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement)) {
1634 QQmlJS::AST::ExpressionNode *expr = stmt->expression;
1635 if (QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr))
1636 return false;
1637 else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral)
1638 return false;
1640 return false;
1641 else if (QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr))
1642 return false;
1643 else {
1644
1645 if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
1646 if (QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
1647 return false;
1648 }
1649 }
1650 }
1651 }
1652
1653 return true;
1654}
1655
1657{
1658 if (property->isCommonType() || property->isList())
1659 return false;
1660 QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
1661 if (!exprStmt)
1662 return false;
1663 QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
1664 return QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr);
1665}
1666
1668{
1669 using namespace QV4::CompiledData;
1670
1671 output.jsGenerator.stringTable.registerString(output.jsModule.fileName);
1672 output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl);
1673
1674 Unit *jsUnit = nullptr;
1675
1676 // We may already have unit data if we're loading an ahead-of-time generated cache file.
1677 if (output.javaScriptCompilationUnit.data) {
1678 jsUnit = const_cast<Unit *>(output.javaScriptCompilationUnit.data);
1679 output.javaScriptCompilationUnit.dynamicStrings = output.jsGenerator.stringTable.allStrings();
1680 } else {
1681 Unit *createdUnit;
1682 jsUnit = createdUnit = output.jsGenerator.generateUnit();
1683
1684 // enable flag if we encountered pragma Singleton
1685 for (Pragma *p : std::as_const(output.pragmas)) {
1686 switch (p->type) {
1687 case Pragma::Singleton:
1688 createdUnit->flags |= Unit::IsSingleton;
1689 break;
1690 case Pragma::Strict:
1691 createdUnit->flags |= Unit::IsStrict;
1692 break;
1694 // ### Qt7: Change the default to Bound by reverting the meaning of the flag.
1695 switch (p->componentBehavior) {
1696 case Pragma::Bound:
1697 createdUnit->flags |= Unit::ComponentsBound;
1698 break;
1699 case Pragma::Unbound:
1700 // this is the default
1701 break;
1702 }
1703 break;
1705 switch (p->listPropertyAssignBehavior) {
1706 case Pragma::Replace:
1707 createdUnit->flags |= Unit::ListPropertyAssignReplace;
1708 break;
1710 createdUnit->flags |= Unit::ListPropertyAssignReplaceIfNotDefault;
1711 break;
1712 case Pragma::Append:
1713 // this is the default
1714 break;
1715 }
1716 break;
1718 switch (p->functionSignatureBehavior) {
1719 case Pragma::Enforced:
1720 break;
1721 case Pragma::Ignored:
1722 createdUnit->flags |= Unit::FunctionSignaturesIgnored;
1723 break;
1724 }
1725 break;
1727 switch (p->nativeMethodBehavior) {
1729 createdUnit->flags |= Unit::NativeMethodsAcceptThisObject;
1730 break;
1732 // this is the default;
1733 break;
1734 }
1735 break;
1737 if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
1738 .testFlag(Pragma::Copy)) {
1739 createdUnit->flags |= Unit::ValueTypesCopied;
1740 }
1741 if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
1742 .testFlag(Pragma::Addressable)) {
1743 createdUnit->flags |= Unit::ValueTypesAddressable;
1744 }
1745 break;
1746 }
1747 }
1748
1749 if (dependencyHasher) {
1750 const QByteArray checksum = dependencyHasher();
1751 if (checksum.size() == sizeof(createdUnit->dependencyMD5Checksum)) {
1752 memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(),
1753 sizeof(createdUnit->dependencyMD5Checksum));
1754 }
1755 }
1756
1757 createdUnit->sourceFileIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.fileName);
1758 createdUnit->finalUrlIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.finalUrl);
1759 }
1760
1761 // No more new strings after this point, we're calculating offsets.
1762 output.jsGenerator.stringTable.freeze();
1763
1764 const uint importSize = uint(sizeof(QV4::CompiledData::Import)) * output.imports.size();
1765 const uint objectOffsetTableSize = output.objects.size() * uint(sizeof(quint32));
1766
1767 QHash<const Object*, quint32> objectOffsets;
1768
1769 const unsigned int objectOffset = sizeof(QV4::CompiledData::QmlUnit) + importSize;
1770 uint nextOffset = objectOffset + objectOffsetTableSize;
1771 for (Object *o : std::as_const(output.objects)) {
1772 objectOffsets.insert(o, nextOffset);
1773 nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size(), o->inlineComponentCount(), o->requiredPropertyExtraDataCount());
1774
1775 int signalTableSize = 0;
1776 for (const Signal *s = o->firstSignal(); s; s = s->next)
1777 signalTableSize += QV4::CompiledData::Signal::calculateSize(s->parameters->count);
1778
1779 nextOffset += signalTableSize;
1780
1781 int enumTableSize = 0;
1782 for (const Enum *e = o->firstEnum(); e; e = e->next)
1783 enumTableSize += QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
1784
1785 nextOffset += enumTableSize;
1786 }
1787
1788 const uint totalSize = nextOffset;
1789 char *data = (char*)malloc(totalSize);
1790 memset(data, 0, totalSize);
1791 QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit *>(data);
1792 qmlUnit->offsetToImports = sizeof(*qmlUnit);
1793 qmlUnit->nImports = output.imports.size();
1794 qmlUnit->offsetToObjects = objectOffset;
1795 qmlUnit->nObjects = output.objects.size();
1796
1797 // write imports
1798 char *importPtr = data + qmlUnit->offsetToImports;
1799 for (const QV4::CompiledData::Import *imp : std::as_const(output.imports)) {
1800 QV4::CompiledData::Import *importToWrite = reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
1801 *importToWrite = *imp;
1802 importPtr += sizeof(QV4::CompiledData::Import);
1803 }
1804
1805 // write objects
1806 quint32_le *objectTable = reinterpret_cast<quint32_le*>(data + qmlUnit->offsetToObjects);
1807 for (int i = 0; i < output.objects.size(); ++i) {
1808 const Object *o = output.objects.at(i);
1809 char * const objectPtr = data + objectOffsets.value(o);
1810 *objectTable++ = objectOffsets.value(o);
1811
1812 QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
1813 objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
1814 objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
1815 objectToWrite->setHasAliasAsDefaultProperty(o->defaultPropertyIsAlias);
1816 objectToWrite->setFlags(QV4::CompiledData::Object::Flags(o->flags));
1817 objectToWrite->idNameIndex = o->idNameIndex;
1818 objectToWrite->setObjectId(o->id);
1819 objectToWrite->location = o->location;
1820 objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
1821
1822 quint32 nextOffset = sizeof(QV4::CompiledData::Object);
1823
1824 objectToWrite->nFunctions = o->functionCount();
1825 objectToWrite->offsetToFunctions = nextOffset;
1826 nextOffset += objectToWrite->nFunctions * sizeof(quint32);
1827
1828 objectToWrite->nProperties = o->propertyCount();
1829 objectToWrite->offsetToProperties = nextOffset;
1830 nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property);
1831
1832 objectToWrite->nAliases = o->aliasCount();
1833 objectToWrite->offsetToAliases = nextOffset;
1834 nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias);
1835
1836 objectToWrite->nEnums = o->enumCount();
1837 objectToWrite->offsetToEnums = nextOffset;
1838 nextOffset += objectToWrite->nEnums * sizeof(quint32);
1839
1840 objectToWrite->nSignals = o->signalCount();
1841 objectToWrite->offsetToSignals = nextOffset;
1842 nextOffset += objectToWrite->nSignals * sizeof(quint32);
1843
1844 objectToWrite->nBindings = o->bindingCount();
1845 objectToWrite->offsetToBindings = nextOffset;
1846 nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
1847
1848 objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.size();
1849 objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
1850 nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
1851
1852 objectToWrite->nInlineComponents = o->inlineComponentCount();
1853 objectToWrite->offsetToInlineComponents = nextOffset;
1854 nextOffset += objectToWrite->nInlineComponents * sizeof (QV4::CompiledData::InlineComponent);
1855
1856 objectToWrite->nRequiredPropertyExtraData = o->requiredPropertyExtraDataCount();
1857 objectToWrite->offsetToRequiredPropertyExtraData = nextOffset;
1858 nextOffset += objectToWrite->nRequiredPropertyExtraData * sizeof(QV4::CompiledData::RequiredPropertyExtraData);
1859
1860 quint32_le *functionsTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions);
1861 for (const Function *f = o->firstFunction(); f; f = f->next)
1862 *functionsTable++ = o->runtimeFunctionIndices.at(f->index);
1863
1864 char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
1865 for (const Property *p = o->firstProperty(); p; p = p->next) {
1866 QV4::CompiledData::Property *propertyToWrite = reinterpret_cast<QV4::CompiledData::Property*>(propertiesPtr);
1867 *propertyToWrite = *p;
1868 propertiesPtr += sizeof(QV4::CompiledData::Property);
1869 }
1870
1871 char *aliasesPtr = objectPtr + objectToWrite->offsetToAliases;
1872 for (const Alias *a = o->firstAlias(); a; a = a->next) {
1873 QV4::CompiledData::Alias *aliasToWrite = reinterpret_cast<QV4::CompiledData::Alias*>(aliasesPtr);
1874 *aliasToWrite = *a;
1875 aliasesPtr += sizeof(QV4::CompiledData::Alias);
1876 }
1877
1878 char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
1879 bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias);
1880 bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler);
1881 bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isAttachedProperty);
1882 bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isGroupProperty);
1883 bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingToAlias);
1884 Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount()));
1885
1886 quint32_le *signalOffsetTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToSignals);
1887 quint32 signalTableSize = 0;
1888 char *signalPtr = objectPtr + nextOffset;
1889 for (const Signal *s = o->firstSignal(); s; s = s->next) {
1890 *signalOffsetTable++ = signalPtr - objectPtr;
1891 QV4::CompiledData::Signal *signalToWrite = reinterpret_cast<QV4::CompiledData::Signal*>(signalPtr);
1892
1893 signalToWrite->nameIndex = s->nameIndex;
1894 signalToWrite->location = s->location;
1895 signalToWrite->nParameters = s->parameters->count;
1896
1897 QV4::CompiledData::Parameter *parameterToWrite = reinterpret_cast<QV4::CompiledData::Parameter*>(signalPtr + sizeof(*signalToWrite));
1898 for (Parameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
1899 *parameterToWrite = *param;
1900
1901 int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count);
1902 signalTableSize += size;
1903 signalPtr += size;
1904 }
1905 nextOffset += signalTableSize;
1906
1907 quint32_le *enumOffsetTable = reinterpret_cast<quint32_le*>(objectPtr + objectToWrite->offsetToEnums);
1908 char *enumPtr = objectPtr + nextOffset;
1909 for (const Enum *e = o->firstEnum(); e; e = e->next) {
1910 *enumOffsetTable++ = enumPtr - objectPtr;
1911 QV4::CompiledData::Enum *enumToWrite = reinterpret_cast<QV4::CompiledData::Enum*>(enumPtr);
1912
1913 enumToWrite->nameIndex = e->nameIndex;
1914 enumToWrite->location = e->location;
1915 enumToWrite->nEnumValues = e->enumValues->count;
1916
1917 QV4::CompiledData::EnumValue *enumValueToWrite = reinterpret_cast<QV4::CompiledData::EnumValue*>(enumPtr + sizeof(*enumToWrite));
1918 for (EnumValue *enumValue = e->enumValues->first; enumValue; enumValue = enumValue->next, ++enumValueToWrite)
1919 *enumValueToWrite = *enumValue;
1920
1921 int size = QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
1922 enumPtr += size;
1923 }
1924
1925 quint32_le *namedObjectInComponentPtr = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
1926 for (int i = 0; i < o->namedObjectsInComponent.size(); ++i) {
1927 *namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
1928 }
1929
1930 char *inlineComponentPtr = objectPtr + objectToWrite->offsetToInlineComponents;
1931 for (auto it = o->inlineComponentsBegin(); it != o->inlineComponentsEnd(); ++it) {
1932 const InlineComponent *ic = it.ptr;
1933 QV4::CompiledData::InlineComponent *icToWrite = reinterpret_cast<QV4::CompiledData::InlineComponent*>(inlineComponentPtr);
1934 *icToWrite = *ic;
1935 inlineComponentPtr += sizeof(QV4::CompiledData::InlineComponent);
1936 }
1937
1938 char *requiredPropertyExtraDataPtr = objectPtr + objectToWrite->offsetToRequiredPropertyExtraData;
1939 for (auto it = o->requiredPropertyExtraDataBegin(); it != o->requiredPropertyExtraDataEnd(); ++it) {
1940 const RequiredPropertyExtraData *extraData = it.ptr;
1941 QV4::CompiledData::RequiredPropertyExtraData *extraDataToWrite = reinterpret_cast<QV4::CompiledData::RequiredPropertyExtraData*>(requiredPropertyExtraDataPtr);
1942 *extraDataToWrite = *extraData;
1943 requiredPropertyExtraDataPtr += sizeof(QV4::CompiledData::RequiredPropertyExtraData);
1944 }
1945 }
1946
1947 if (!output.javaScriptCompilationUnit.data) {
1948 // Combine the qml data into the general unit data.
1949 jsUnit = static_cast<QV4::CompiledData::Unit *>(realloc(jsUnit, jsUnit->unitSize + totalSize));
1950 jsUnit->offsetToQmlUnit = jsUnit->unitSize;
1951 jsUnit->unitSize += totalSize;
1952 memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize);
1953 free(qmlUnit);
1955 qmlUnit = jsUnit->qmlUnit();
1956 }
1957
1958 static const bool showStats = qEnvironmentVariableIsSet("QML_SHOW_UNIT_STATS");
1959 if (showStats) {
1960 qDebug() << "Generated QML unit that is" << totalSize << "bytes big contains:";
1961 qDebug() << " " << jsUnit->functionTableSize << "functions";
1962 qDebug() << " " << jsUnit->unitSize << "for JS unit";
1963 qDebug() << " " << importSize << "for imports";
1964 qDebug() << " " << nextOffset - objectOffset - objectOffsetTableSize << "for" << qmlUnit->nObjects << "objects";
1965 quint32 totalBindingCount = 0;
1966 for (quint32 i = 0; i < qmlUnit->nObjects; ++i)
1967 totalBindingCount += qmlUnit->objectAt(i)->nBindings;
1968 qDebug() << " " << totalBindingCount << "bindings";
1969 quint32 totalCodeSize = 0;
1970 for (quint32 i = 0; i < jsUnit->functionTableSize; ++i)
1971 totalCodeSize += jsUnit->functionAt(i)->codeSize;
1972 qDebug() << " " << totalCodeSize << "bytes total byte code";
1973 qDebug() << " " << jsUnit->stringTableSize << "strings";
1974 quint32 totalStringSize = 0;
1975 for (quint32 i = 0; i < jsUnit->stringTableSize; ++i)
1976 totalStringSize += QV4::CompiledData::String::calculateSize(jsUnit->stringAtInternal(i));
1977 qDebug() << " " << totalStringSize << "bytes total strings";
1978 }
1979
1980 output.javaScriptCompilationUnit.setUnitData(jsUnit, qmlUnit, output.jsModule.fileName,
1981 output.jsModule.finalUrl);
1982}
1983
1984char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
1985{
1986 for (const Binding *b = o->firstBinding(); b; b = b->next) {
1987 if (!(b->*(filter))())
1988 continue;
1989 QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
1990 *bindingToWrite = *b;
1992 bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
1993 bindingPtr += sizeof(QV4::CompiledData::Binding);
1994 }
1995 return bindingPtr;
1996}
1997
1998JSCodeGen::JSCodeGen(Document *document, const QSet<QString> &globalNames,
2000 bool storeSourceLocations)
2001 : QV4::Compiler::Codegen(&document->jsGenerator, /*strict mode*/ false, iface,
2002 storeSourceLocations),
2003 document(document)
2004{
2005 m_globalNames = globalNames;
2006 _module = &document->jsModule;
2007 _fileNameIsUrl = true;
2008}
2009
2011 const QList<CompiledFunctionOrExpression> &functions)
2012{
2013 auto qmlName = [&](const CompiledFunctionOrExpression &c) {
2014 if (c.nameIndex != 0)
2015 return document->stringAt(c.nameIndex);
2016 else
2017 return QStringLiteral("%qml-expression-entry");
2018 };
2019 QVector<int> runtimeFunctionIndices(functions.size());
2020
2023 for (const CompiledFunctionOrExpression &f : functions) {
2024 Q_ASSERT(f.node != document->program);
2025 Q_ASSERT(f.parentNode && f.parentNode != document->program);
2026 auto function = f.node->asFunctionDefinition();
2027
2028 if (function) {
2030 } else {
2031 Q_ASSERT(f.node != f.parentNode);
2032 scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding, qmlName(f));
2033 }
2034
2035 /* We do not want to visit the whole function, as we already called enterQmlFunction
2036 However, there might be a function defined as a default argument of the function.
2037 That needs to be considered, too, so we call handleTopLevelFunctionFormals to
2038 deal with them.
2039 */
2041 scan(function ? function->body : f.node);
2042 scan.leaveEnvironment();
2043 }
2044 scan.leaveEnvironment();
2045
2046 if (hasError())
2047 return QVector<int>();
2048
2049 _context = nullptr;
2050
2051 for (int i = 0; i < functions.size(); ++i) {
2052 const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
2053 QQmlJS::AST::Node *node = qmlFunction.node;
2054 Q_ASSERT(node != document->program);
2055
2057
2058 QString name;
2059 if (function)
2060 name = function->name.toString();
2061 else
2062 name = qmlName(qmlFunction);
2063
2065 if (function) {
2066 body = function->body;
2067 } else {
2068 // Synthesize source elements.
2070
2071 QQmlJS::AST::Statement *stmt = node->statementCast();
2072 if (!stmt) {
2073 Q_ASSERT(node->expressionCast());
2075 stmt = new (pool) QQmlJS::AST::ExpressionStatement(expr);
2076 }
2077 body = new (pool) QQmlJS::AST::StatementList(stmt);
2078 body = body->finish();
2079 }
2080
2081 int idx = defineFunction(name, function ? function : qmlFunction.parentNode,
2082 function ? function->formals : nullptr, body);
2083 runtimeFunctionIndices[i] = idx;
2084 }
2085
2086 return runtimeFunctionIndices;
2087}
2088
2090{
2091 if (object->functionsAndExpressions->count == 0)
2092 return true;
2093
2095 functionsToCompile.reserve(object->functionsAndExpressions->count);
2096 for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe;
2097 foe = foe->next) {
2098 functionsToCompile << *foe;
2099 }
2100
2101 const auto runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
2102 if (hasError())
2103 return false;
2104
2105 object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
2106 runtimeFunctionIndices);
2107 return true;
2108}
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
QChar toLower() const noexcept
Returns the lowercase equivalent if the character is uppercase or titlecase; otherwise returns the ch...
Definition qchar.h:448
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
constexpr bool isLower() const noexcept
Returns true if the character is a lowercase letter, for example category() is Letter_Lowercase.
Definition qchar.h:474
constexpr bool isUpper() const noexcept
Returns true if the character is an uppercase letter, for example category() is Letter_Uppercase.
Definition qchar.h:475
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore
Definition qhash.h:818
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
virtual SourceLocation firstSourceLocation() const =0
void accept(BaseVisitor *visitor)
virtual Statement * statementCast()
Definition qqmljsast.cpp:49
virtual SourceLocation lastSourceLocation() const =0
virtual ExpressionNode * expressionCast()
Definition qqmljsast.cpp:39
virtual FunctionExpression * asFunctionDefinition()
Definition qqmljsast.cpp:69
StatementList * finish()
UiArrayMemberList * members
UiVersionSpecifier * version
SourceLocation importIdToken
UiQualifiedId * importUri
SourceLocation fileNameToken
SourceLocation importToken
SourceLocation firstSourceLocation() const override
UiObjectDefinition * component
UiQualifiedId * qualifiedTypeNameId
UiObjectInitializer * initializer
UiObjectInitializer * initializer
SourceLocation firstSourceLocation() const override=0
UiPragmaValueList * values
SourceLocation pragmaToken
UiParameterList * parameters
SourceLocation firstSourceLocation() const override
enum QQmlJS::AST::UiPublicMember::@695 type
SourceLocation defaultToken() const
SourceLocation typeModifierToken
SourceLocation firstSourceLocation() const override
SourceLocation identifierToken
SourceLocation firstSourceLocation() const override
MemoryPool * pool()
void setCode(const QString &code, int lineno, bool qmlMode=true, CodeContinuation codeContinuation=CodeContinuation::Reset)
Definition qset.h:18
iterator end()
Definition qset.h:140
bool isEmpty() const
Definition qset.h:52
iterator erase(const_iterator i)
Definition qset.h:145
iterator find(const T &value)
Definition qset.h:159
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
const_pointer data() const noexcept
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
constexpr bool isNull() const noexcept
Returns whether this string view is null - that is, whether {data() == nullptr}.
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & append(QChar c)
Definition qstring.cpp:3227
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
\inmodule QtCore
static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
Produces a QTypeRevision from the given majorVersion and minorVersion, both of which need to be a val...
static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
Produces a QTypeRevision from the given majorVersion with an invalid minor version.
QSet< QString > m_globalNames
virtual int defineFunction(const QString &name, QQmlJS::AST::Node *ast, QQmlJS::AST::FormalParameterList *formals, QQmlJS::AST::StatementList *body)
void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast)
void handleTopLevelFunctionFormals(QQmlJS::AST::FunctionExpression *node)
void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode, const QString &name)
void enterGlobalEnvironment(ContextType compilationMode)
constexpr size_type size() const noexcept
const T & at(qsizetype idx) const
void append(const T &t)
void importFile(const QString &jsfile, const QString &module, int lineNumber, int column) override
void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override
ScriptDirectivesCollector(QmlIR::Document *doc)
QString str
[2]
qSwap(pi, e)
double e
QSet< QString >::iterator it
auto signal
std::function< QByteArray()> DependentTypesHasher
\qmltype Particle \inqmlmodule QtQuick.Particles
void tryGeneratingTranslationBindingBase(QStringView base, QQmlJS::AST::ArgumentList *args, RegisterMainString registerMainString, RegisterCommentString registerCommentString, RegisterContextString registerContextString, FinalizeTranslationData finalizeTranslationData)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static quint32 checksum(const QByteArray &table)
static bool isScript(QStringView tag)
Definition qlocale.cpp:555
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
const char * typeName
GLint location
GLenum GLsizei GLsizei GLint * values
[15]
GLboolean GLboolean GLboolean b
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLuint object
[3]
GLfloat GLfloat f
GLint left
GLenum type
GLenum target
GLbitfield flags
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint program
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum const GLint * param
GLuint name
GLint first
GLenum GLenum GLsizei void GLsizei void * column
GLhandleARB obj
[2]
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLenum GLenum GLenum input
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
static qreal dot(const QPointF &a, const QPointF &b)
static const quint32 emptyStringIndex
#define COMPILE_EXCEPTION(location, desc)
static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(*) void arg)
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define tr(X)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
unsigned int quint32
Definition qtypes.h:45
unsigned int uint
Definition qtypes.h:29
static int toInt(const QChar &qc, int R)
QT_BEGIN_NAMESPACE typedef uchar * output
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
char * toString(const MyType &t)
[31]
QJSValueList args
QJSEngine engine
[0]
static bool run(IRBuilder *builder, QQmlJS::AST::UiPragma *node, Pragma *pragma)
\inmodule QtCore \reentrant
Definition qchar.h:17
void setNameIndex(quint32 nameIndex)
void setIdIndex(quint32 idIndex)
union QV4::CompiledData::Binding::@543 value
bool hasFlag(Flag flag) const
static int calculateSize(int nEnumValues)
void set(quint32 line, quint32 column)
static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
void setHasAliasAsDefaultProperty(bool defaultAlias)
void set(Flags flags, quint32 typeNameIndexOrCommonType)
const Object * objectAt(int idx) const
static int calculateSize(int nParameters)
static int calculateSize(const QString &str)
QString stringAtInternal(uint idx) const
const Function * functionAt(int idx) const
const QmlUnit * qmlUnit() const
static void generateUnitChecksum(CompiledData::Unit *unit)
int registerTranslation(const CompiledData::TranslationData &translation)
QString stringForIndex(int index) const
int registerConstant(ReturnedValue v)
int registerString(const QString &str)
QString stringForIndex(int index) const
QQmlJS::AST::UiProgram * program
QString stringAt(int index) const
QV4::Compiler::Module jsModule
QV4::Compiler::JSUnitGenerator jsGenerator
QList< const QV4::CompiledData::Import * > imports
Document(bool debugMode)
QQmlJS::Engine jsParserEngine
QV4::CompiledData::Location location
PoolList< EnumValue > * enumValues
QVector< Object * > _objects
bool resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object, bool onAssignment=false)
QList< const QV4::CompiledData::Import * > _imports
QList< Pragma * > _pragmas
bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QV4::CompiledData::Location &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride=nullptr)
QStringView asStringRef(QQmlJS::AST::Node *node)
static QTypeRevision extractVersion(QStringView string)
Object * bindingsTarget() const
IRBuilder(const QSet< QString > &illegalNames)
bool setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Statement *value)
static bool isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode)
QString stringAt(int index) const
void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode)
QQmlJS::MemoryPool * pool
void accept(QQmlJS::AST::Node *node)
static QString signalNameFromSignalPropertyName(const QString &signalPropertyName)
static bool isSignalPropertyName(const QString &name)
bool visit(QQmlJS::AST::UiArrayMemberList *ast) override
Property * _propertyDeclaration
bool generateFromQml(const QString &code, const QString &url, Document *output)
QList< QQmlJS::DiagnosticMessage > errors
static bool isStatementNodeScript(QQmlJS::AST::Statement *statement)
QV4::Compiler::JSUnitGenerator * jsGenerator
bool appendAlias(QQmlJS::AST::UiPublicMember *node)
quint32 registerString(const QString &str) const
QSet< QString > inlineComponentsNames
void tryGeneratingTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding)
static QString asString(QQmlJS::AST::UiQualifiedId *node)
void recordError(const QQmlJS::SourceLocation &location, const QString &description)
QString sanityCheckFunctionNames(Object *obj, const QSet< QString > &illegalNames, QQmlJS::SourceLocation *errorLocation)
QSet< QString > illegalNames
QStringView textRefAt(const QQmlJS::SourceLocation &loc) const
bool generateRuntimeFunctions(QmlIR::Object *object)
JSCodeGen(Document *document, const QSet< QString > &globalNames, QV4::Compiler::CodegenWarningInterface *iface=QV4::Compiler::defaultCodegenWarningInterface(), bool storeSourceLocations=false)
QVector< int > generateJSCodeForFunctionsAndBindings(const QList< CompiledFunctionOrExpression > &functions)
int indexOfDefaultPropertyOrAlias
QString appendEnum(Enum *enumeration)
void appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraData)
void insertSorted(Binding *b)
QString appendBinding(Binding *b, bool isListBinding)
void appendInlineComponent(InlineComponent *ic)
QString appendSignal(Signal *signal)
QString bindingAsString(Document *doc, int scriptIndex) const
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QV4::CompiledData::Location &location)
Object * declarationsOverride
QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation)
QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation)
PoolList< CompiledFunctionOrExpression > * functionsAndExpressions
void appendFunction(QmlIR::Function *f)
quint32 inheritedTypeNameIndex
QV4::CompiledData::Location locationOfIdProperty
Binding * findBinding(quint32 nameIndex) const
static bool initType(QV4::CompiledData::ParameterType *type, const IdGenerator &idGenerator, const QQmlJS::AST::Type *annotation)
static QV4::CompiledData::CommonType stringToBuiltinType(const QString &typeName)
NativeMethodBehaviorValue nativeMethodBehavior
ComponentBehaviorValue componentBehavior
ValueTypeBehaviorValues::Int valueTypeBehavior
QV4::CompiledData::Location location
FunctionSignatureBehaviorValue functionSignatureBehavior
ListPropertyAssignBehaviorValue listPropertyAssignBehavior
void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher=QV4::CompiledData::DependentTypesHasher())
RequiredPropertyExtraData * next
PoolList< Parameter > * parameters
QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const