Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmljstypedescriptionreader.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include <QtQml/private/qqmljsparser_p.h>
7#include <QtQml/private/qqmljslexer_p.h>
8#include <QtQml/private/qqmljsengine_p.h>
9
10#include <QtCore/qdir.h>
11#include <QtCore/qstring.h>
12
14
15using namespace QQmlJS;
16using namespace QQmlJS::AST;
17using namespace Qt::StringLiterals;
18
19QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
20{
22
23 for (const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
24 if (iter != qualifiedId)
25 result += delimiter;
26
27 result += iter->name;
28 }
29
30 return result;
31}
32
34 QList<QQmlJSExportedScope> *objects, QStringList *dependencies)
35{
37
38 Lexer lexer(&engine);
39 Parser parser(&engine);
40
41 lexer.setCode(m_source, /*lineno = */ 1, /*qmlMode = */true);
42
43 if (!parser.parse()) {
44 m_errorMessage = QString::fromLatin1("%1:%2: %3").arg(
45 QString::number(parser.errorLineNumber()),
46 QString::number(parser.errorColumnNumber()),
47 parser.errorMessage());
48 return false;
49 }
50
51 m_objects = objects;
52 m_dependencies = dependencies;
53 readDocument(parser.ast());
54
55 return m_errorMessage.isEmpty();
56}
57
58void QQmlJSTypeDescriptionReader::readDocument(UiProgram *ast)
59{
60 if (!ast) {
61 addError(SourceLocation(), tr("Could not parse document."));
62 return;
63 }
64
65 if (!ast->headers || ast->headers->next || !cast<UiImport *>(ast->headers->headerItem)) {
66 addError(SourceLocation(), tr("Expected a single import."));
67 return;
68 }
69
70 auto *import = cast<UiImport *>(ast->headers->headerItem);
71 if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
72 addError(import->importToken, tr("Expected import of QtQuick.tooling."));
73 return;
74 }
75
76 if (!import->version) {
77 addError(import->firstSourceLocation(), tr("Import statement without version."));
78 return;
79 }
80
81 if (import->version->version.majorVersion() != 1) {
82 addError(import->version->firstSourceLocation(),
83 tr("Major version different from 1 not supported."));
84 return;
85 }
86
87 if (!ast->members || !ast->members->member || ast->members->next) {
88 addError(SourceLocation(), tr("Expected document to contain a single object definition."));
89 return;
90 }
91
92 auto *module = cast<UiObjectDefinition *>(ast->members->member);
93 if (!module) {
94 addError(SourceLocation(), tr("Expected document to contain a single object definition."));
95 return;
96 }
97
98 if (toString(module->qualifiedTypeNameId) != QLatin1String("Module")) {
99 addError(SourceLocation(), tr("Expected document to contain a Module {} member."));
100 return;
101 }
102
103 readModule(module);
104}
105
106void QQmlJSTypeDescriptionReader::readModule(UiObjectDefinition *ast)
107{
108 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
109 UiObjectMember *member = it->member;
110 auto *component = cast<UiObjectDefinition *>(member);
111
112 auto *script = cast<UiScriptBinding *>(member);
113 if (script && (toString(script->qualifiedId) == QStringLiteral("dependencies"))) {
114 readDependencies(script);
115 continue;
116 }
117
119 if (component)
120 typeName = toString(component->qualifiedTypeNameId);
121
122 if (!component || typeName != QLatin1String("Component")) {
123 continue;
124 }
125
126 if (typeName == QLatin1String("Component"))
127 readComponent(component);
128 }
129}
130
131void QQmlJSTypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
132{
133 m_errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
134 QDir::toNativeSeparators(m_fileName),
137 message);
138}
139
140void QQmlJSTypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message)
141{
142 m_warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
143 QDir::toNativeSeparators(m_fileName),
146 message);
147}
148
149void QQmlJSTypeDescriptionReader::readDependencies(UiScriptBinding *ast)
150{
151 auto *stmt = cast<ExpressionStatement*>(ast->statement);
152 if (!stmt) {
153 addError(ast->statement->firstSourceLocation(), tr("Expected dependency definitions"));
154 return;
155 }
156 auto *exp = cast<ArrayPattern *>(stmt->expression);
157 if (!exp) {
158 addError(stmt->expression->firstSourceLocation(), tr("Expected dependency definitions"));
159 return;
160 }
161 for (PatternElementList *l = exp->elements; l; l = l->next) {
162 auto *str = cast<StringLiteral *>(l->element->initializer);
163 *m_dependencies << str->value.toString();
164 }
165}
166
167void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
168{
169 m_currentCtorIndex = 0;
172
173 UiScriptBinding *metaObjectRevisions = nullptr;
174 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
175 UiObjectMember *member = it->member;
176 auto *component = cast<UiObjectDefinition *>(member);
177 auto *script = cast<UiScriptBinding *>(member);
178 if (component) {
179 QString name = toString(component->qualifiedTypeNameId);
180 if (name == QLatin1String("Property"))
181 readProperty(component, scope);
182 else if (name == QLatin1String("Method") || name == QLatin1String("Signal"))
183 readSignalOrMethod(component, name == QLatin1String("Method"), scope);
184 else if (name == QLatin1String("Enum"))
185 readEnum(component, scope);
186 else
187 addWarning(component->firstSourceLocation(),
188 tr("Expected only Property, Method, Signal and Enum object definitions, "
189 "not \"%1\".").arg(name));
190 } else if (script) {
191 QString name = toString(script->qualifiedId);
192 if (name == QLatin1String("file")) {
193 scope->setFilePath(readStringBinding(script));
194 } else if (name == QLatin1String("name")) {
195 scope->setInternalName(readStringBinding(script));
196 } else if (name == QLatin1String("prototype")) {
197 scope->setBaseTypeName(readStringBinding(script));
198 } else if (name == QLatin1String("defaultProperty")) {
199 scope->setOwnDefaultPropertyName(readStringBinding(script));
200 } else if (name == QLatin1String("parentProperty")) {
201 scope->setOwnParentPropertyName(readStringBinding(script));
202 } else if (name == QLatin1String("exports")) {
203 exports = readExports(script);
204 } else if (name == QLatin1String("interfaces")) {
205 readInterfaces(script, scope);
206 } else if (name == QLatin1String("exportMetaObjectRevisions")) {
207 metaObjectRevisions = script;
208 } else if (name == QLatin1String("attachedType")) {
209 scope->setOwnAttachedTypeName(readStringBinding(script));
210 } else if (name == QLatin1String("valueType")) {
211 scope->setValueTypeName(readStringBinding(script));
212 } else if (name == QLatin1String("isSingleton")) {
213 scope->setIsSingleton(readBoolBinding(script));
214 } else if (name == QLatin1String("isCreatable")) {
215 scope->setCreatableFlag(readBoolBinding(script));
216 } else if (name == QLatin1String("isStructured")) {
217 scope->setStructuredFlag(readBoolBinding(script));
218 } else if (name == QLatin1String("isComposite")) {
219 scope->setIsComposite(readBoolBinding(script));
220 } else if (name == QLatin1String("hasCustomParser")) {
221 scope->setHasCustomParser(readBoolBinding(script));
222 } else if (name == QLatin1String("accessSemantics")) {
223 const QString semantics = readStringBinding(script);
224 if (semantics == QLatin1String("reference")) {
225 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Reference);
226 } else if (semantics == QLatin1String("value")) {
227 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Value);
228 } else if (semantics == QLatin1String("none")) {
229 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::None);
230 } else if (semantics == QLatin1String("sequence")) {
231 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
232 } else {
233 addWarning(script->firstSourceLocation(),
234 tr("Unknown access semantics \"%1\".").arg(semantics));
235 }
236 } else if (name == QLatin1String("extension")) {
237 scope->setExtensionTypeName(readStringBinding(script));
238 } else if (name == QLatin1String("extensionIsNamespace")) {
239 scope->setExtensionIsNamespace(readBoolBinding(script));
240 } else if (name == QLatin1String("deferredNames")) {
241 readDeferredNames(script, scope);
242 } else if (name == QLatin1String("immediateNames")) {
243 readImmediateNames(script, scope);
244 } else {
245 addWarning(script->firstSourceLocation(),
246 tr("Expected only name, prototype, defaultProperty, attachedType, "
247 "valueType, exports, interfaces, isSingleton, isCreatable, "
248 "isStructured, isComposite, hasCustomParser, "
249 "exportMetaObjectRevisions, deferredNames, and immediateNames "
250 "in script bindings, not \"%1\".")
251 .arg(name));
252 }
253 } else {
254 addWarning(member->firstSourceLocation(),
255 tr("Expected only script bindings and object definitions."));
256 }
257 }
258
259 if (scope->internalName().isEmpty()) {
260 addError(ast->firstSourceLocation(), tr("Component definition is missing a name binding."));
261 return;
262 }
263
264 if (metaObjectRevisions)
265 checkMetaObjectRevisions(metaObjectRevisions, &exports);
266 m_objects->append({scope, exports});
267}
268
269void QQmlJSTypeDescriptionReader::readSignalOrMethod(
270 UiObjectDefinition *ast, bool isMethod, const QQmlJSScope::Ptr &scope)
271{
272 QQmlJSMetaMethod metaMethod;
273 // ### confusion between Method and Slot. Method should be removed.
274 if (isMethod)
275 metaMethod.setMethodType(QQmlJSMetaMethodType::Slot);
276 else
277 metaMethod.setMethodType(QQmlJSMetaMethodType::Signal);
278
279 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
280 UiObjectMember *member = it->member;
281 auto *component = cast<UiObjectDefinition *>(member);
282 auto *script = cast<UiScriptBinding *>(member);
283 if (component) {
284 QString name = toString(component->qualifiedTypeNameId);
285 if (name == QLatin1String("Parameter")) {
286 readParameter(component, &metaMethod);
287 } else {
288 addWarning(component->firstSourceLocation(),
289 tr("Expected only Parameter in object definitions."));
290 }
291 } else if (script) {
292 QString name = toString(script->qualifiedId);
293 if (name == QLatin1String("name")) {
294 metaMethod.setMethodName(readStringBinding(script));
295 } else if (name == QLatin1String("type")) {
296 metaMethod.setReturnTypeName(readStringBinding(script));
297 } else if (name == QLatin1String("revision")) {
298 metaMethod.setRevision(readIntBinding(script));
299 } else if (name == QLatin1String("isCloned")) {
300 metaMethod.setIsCloned(true);
301 } else if (name == QLatin1String("isConstructor")) {
302 metaMethod.setIsConstructor(true);
303
304 // The constructors in the moc json output are ordered the same
305 // way as the ones in the metaobject. qmltyperegistrar moves them into
306 // the same list as the other members, but maintains their order.
307 metaMethod.setConstructorIndex(
308 QQmlJSMetaMethod::RelativeFunctionIndex(m_currentCtorIndex++));
309
310 } else if (name == QLatin1String("isJavaScriptFunction")) {
311 metaMethod.setIsJavaScriptFunction(true);
312 } else if (name == QLatin1String("isList")) {
313 // TODO: Theoretically this can happen. QQmlJSMetaMethod should store it.
314 } else if (name == QLatin1String("isPointer")) {
315 // TODO: We don't need this information. We can probably drop all isPointer members
316 // once we make sure that the type information is always complete. The
317 // description of the type being referenced has access semantics after all.
318 } else {
319 addWarning(script->firstSourceLocation(),
320 tr("Expected only name, type, revision, isPointer, isList, "
321 "isCloned, isConstructor, and "
322 "isJavaScriptFunction in script bindings."));
323 }
324 } else {
325 addWarning(member->firstSourceLocation(),
326 tr("Expected only script bindings and object definitions."));
327 }
328 }
329
330 if (metaMethod.methodName().isEmpty()) {
331 addError(ast->firstSourceLocation(),
332 tr("Method or signal is missing a name script binding."));
333 return;
334 }
335
336 scope->addOwnMethod(metaMethod);
337}
338
339void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQmlJSScope::Ptr &scope)
340{
342 property.setIsWritable(true); // default is writable
343 bool isRequired = false;
344
345 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
346 UiObjectMember *member = it->member;
347 auto *script = cast<UiScriptBinding *>(member);
348 if (!script) {
349 addWarning(member->firstSourceLocation(), tr("Expected script binding."));
350 continue;
351 }
352
353 QString id = toString(script->qualifiedId);
354 if (id == QLatin1String("name")) {
355 property.setPropertyName(readStringBinding(script));
356 } else if (id == QLatin1String("type")) {
357 property.setTypeName(readStringBinding(script));
358 } else if (id == QLatin1String("isPointer")) {
359 property.setIsPointer(readBoolBinding(script));
360 } else if (id == QLatin1String("isReadonly")) {
361 property.setIsWritable(!readBoolBinding(script));
362 } else if (id == QLatin1String("isRequired")) {
363 isRequired = readBoolBinding(script);
364 } else if (id == QLatin1String("isList")) {
365 property.setIsList(readBoolBinding(script));
366 } else if (id == QLatin1String("isFinal")) {
367 property.setIsFinal(readBoolBinding(script));
368 } else if (id == QLatin1String("isConstant")) {
369 property.setIsConstant(readBoolBinding(script));
370 } else if (id == QLatin1String("revision")) {
371 property.setRevision(readIntBinding(script));
372 } else if (id == QLatin1String("bindable")) {
373 property.setBindable(readStringBinding(script));
374 } else if (id == QLatin1String("read")) {
375 property.setRead(readStringBinding(script));
376 } else if (id == QLatin1String("write")) {
377 property.setWrite(readStringBinding(script));
378 } else if (id == QLatin1String("reset")) {
379 property.setReset(readStringBinding(script));
380 } else if (id == QLatin1String("notify")) {
381 property.setNotify(readStringBinding(script));
382 } else if (id == QLatin1String("index")) {
383 property.setIndex(readIntBinding(script));
384 } else if (id == QLatin1String("privateClass")) {
385 property.setPrivateClass(readStringBinding(script));
386 } else {
387 addWarning(script->firstSourceLocation(),
388 tr("Expected only type, name, revision, isPointer, isReadonly, isRequired, "
389 "isFinal, isList, bindable, read, write, reset, notify, index, and "
390 "privateClass and script bindings."));
391 }
392 }
393
394 if (property.propertyName().isEmpty()) {
395 addError(ast->firstSourceLocation(),
396 tr("Property object is missing a name script binding."));
397 return;
398 }
399
400 scope->addOwnProperty(property);
401 if (isRequired)
402 scope->setPropertyLocallyRequired(property.propertyName(), true);
403}
404
405void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast, const QQmlJSScope::Ptr &scope)
406{
407 QQmlJSMetaEnum metaEnum;
408
409 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
410 UiObjectMember *member = it->member;
411 auto *script = cast<UiScriptBinding *>(member);
412 if (!script) {
413 addWarning(member->firstSourceLocation(), tr("Expected script binding."));
414 continue;
415 }
416
417 QString name = toString(script->qualifiedId);
418 if (name == QLatin1String("name")) {
419 metaEnum.setName(readStringBinding(script));
420 } else if (name == QLatin1String("alias")) {
421 metaEnum.setAlias(readStringBinding(script));
422 } else if (name == QLatin1String("isFlag")) {
423 metaEnum.setIsFlag(readBoolBinding(script));
424 } else if (name == QLatin1String("values")) {
425 readEnumValues(script, &metaEnum);
426 } else if (name == QLatin1String("scoped")) {
427 metaEnum.setScoped(readBoolBinding(script));
428 } else if (name == QLatin1String("type")) {
429 metaEnum.setTypeName(readStringBinding(script));
430 } else {
431 addWarning(script->firstSourceLocation(),
432 tr("Expected only name, alias, isFlag, values, scoped, or type."));
433 }
434 }
435
436 scope->addOwnEnumeration(metaEnum);
437}
438
439void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSMetaMethod *metaMethod)
440{
443 bool isConstant = false;
444 bool isPointer = false;
445 bool isList = false;
446
447 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
448 UiObjectMember *member = it->member;
449 auto *script = cast<UiScriptBinding *>(member);
450 if (!script) {
451 addWarning(member->firstSourceLocation(), tr("Expected script binding."));
452 continue;
453 }
454
455 const QString id = toString(script->qualifiedId);
456 if (id == QLatin1String("name")) {
457 name = readStringBinding(script);
458 } else if (id == QLatin1String("type")) {
459 type = readStringBinding(script);
460 } else if (id == QLatin1String("isPointer")) {
461 isPointer = readBoolBinding(script);
462 } else if (id == QLatin1String("isConstant")) {
463 isConstant = readBoolBinding(script);
464 } else if (id == QLatin1String("isReadonly")) {
465 // ### unhandled
466 } else if (id == QLatin1String("isList")) {
467 isList = readBoolBinding(script);
468 } else {
469 addWarning(script->firstSourceLocation(),
470 tr("Expected only name, type, isPointer, isConstant, isReadonly, "
471 "or IsList script bindings."));
472 }
473 }
474
476 p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
477 p.setIsPointer(isPointer);
478 p.setIsList(isList);
479 metaMethod->addParameter(std::move(p));
480}
481
482QString QQmlJSTypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
483{
484 Q_ASSERT(ast);
485
486 if (!ast->statement) {
487 addError(ast->colonToken, tr("Expected string after colon."));
488 return QString();
489 }
490
491 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
492 if (!expStmt) {
493 addError(ast->statement->firstSourceLocation(), tr("Expected string after colon."));
494 return QString();
495 }
496
497 auto *stringLit = cast<StringLiteral *>(expStmt->expression);
498 if (!stringLit) {
499 addError(expStmt->firstSourceLocation(), tr("Expected string after colon."));
500 return QString();
501 }
502
503 return stringLit->value.toString();
504}
505
506bool QQmlJSTypeDescriptionReader::readBoolBinding(UiScriptBinding *ast)
507{
508 Q_ASSERT(ast);
509
510 if (!ast->statement) {
511 addError(ast->colonToken, tr("Expected boolean after colon."));
512 return false;
513 }
514
515 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
516 if (!expStmt) {
517 addError(ast->statement->firstSourceLocation(), tr("Expected boolean after colon."));
518 return false;
519 }
520
521 auto *trueLit = cast<TrueLiteral *>(expStmt->expression);
522 auto *falseLit = cast<FalseLiteral *>(expStmt->expression);
523 if (!trueLit && !falseLit) {
524 addError(expStmt->firstSourceLocation(), tr("Expected true or false after colon."));
525 return false;
526 }
527
528 return trueLit;
529}
530
531double QQmlJSTypeDescriptionReader::readNumericBinding(UiScriptBinding *ast)
532{
533 Q_ASSERT(ast);
534
535 if (!ast->statement) {
536 addError(ast->colonToken, tr("Expected numeric literal after colon."));
537 return 0;
538 }
539
540 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
541 if (!expStmt) {
542 addError(ast->statement->firstSourceLocation(),
543 tr("Expected numeric literal after colon."));
544 return 0;
545 }
546
547 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
548 if (!numericLit) {
549 addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
550 return 0;
551 }
552
553 return numericLit->value;
554}
555
556static QTypeRevision parseVersion(const QString &versionString)
557{
558 const int dotIdx = versionString.indexOf(QLatin1Char('.'));
559 if (dotIdx == -1)
560 return QTypeRevision();
561 bool ok = false;
562 const int maybeMajor = QStringView{versionString}.left(dotIdx).toInt(&ok);
563 if (!ok)
564 return QTypeRevision();
565 const int maybeMinor = QStringView{versionString}.mid(dotIdx + 1).toInt(&ok);
566 if (!ok)
567 return QTypeRevision();
568 return QTypeRevision::fromVersion(maybeMajor, maybeMinor);
569}
570
571QTypeRevision QQmlJSTypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
572{
573 QTypeRevision invalidVersion;
574
575 if (!ast || !ast->statement) {
576 addError((ast ? ast->colonToken : SourceLocation()),
577 tr("Expected numeric literal after colon."));
578 return invalidVersion;
579 }
580
581 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
582 if (!expStmt) {
583 addError(ast->statement->firstSourceLocation(),
584 tr("Expected numeric literal after colon."));
585 return invalidVersion;
586 }
587
588 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
589 if (!numericLit) {
590 addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
591 return invalidVersion;
592 }
593
594 return parseVersion(m_source.mid(numericLit->literalToken.begin(),
595 numericLit->literalToken.length));
596}
597
598int QQmlJSTypeDescriptionReader::readIntBinding(UiScriptBinding *ast)
599{
600 double v = readNumericBinding(ast);
601 int i = static_cast<int>(v);
602
603 if (i != v) {
604 addError(ast->firstSourceLocation(), tr("Expected integer after colon."));
605 return 0;
606 }
607
608 return i;
609}
610
611ArrayPattern* QQmlJSTypeDescriptionReader::getArray(UiScriptBinding *ast)
612{
613 Q_ASSERT(ast);
614
615 if (!ast->statement) {
616 addError(ast->colonToken, tr("Expected array of strings after colon."));
617 return nullptr;
618 }
619
620 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
621 if (!expStmt) {
622 addError(ast->statement->firstSourceLocation(),
623 tr("Expected array of strings after colon."));
624 return nullptr;
625 }
626
627 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
628 if (!arrayLit) {
629 addError(expStmt->firstSourceLocation(), tr("Expected array of strings after colon."));
630 return nullptr;
631 }
632
633 return arrayLit;
634}
635
636QList<QQmlJSScope::Export> QQmlJSTypeDescriptionReader::readExports(UiScriptBinding *ast)
637{
639 auto *arrayLit = getArray(ast);
640
641 if (!arrayLit)
642 return exports;
643
644 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
645 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
646
647 if (!stringLit) {
648 addError(arrayLit->firstSourceLocation(),
649 tr("Expected array literal with only string literal members."));
650 return exports;
651 }
652
653 QString exp = stringLit->value.toString();
654 int slashIdx = exp.indexOf(QLatin1Char('/'));
655 int spaceIdx = exp.indexOf(QLatin1Char(' '));
656 const QTypeRevision version = parseVersion(exp.mid(spaceIdx + 1));
657
658 if (spaceIdx == -1 || !version.isValid()) {
659 addError(stringLit->firstSourceLocation(),
660 tr("Expected string literal to contain 'Package/Name major.minor' "
661 "or 'Name major.minor'."));
662 continue;
663 }
664 QString package;
665 if (slashIdx != -1)
666 package = exp.left(slashIdx);
667 QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
668
669 // ### relocatable exports where package is empty?
670 exports.append(QQmlJSScope::Export(package, name, version, version));
671 }
672
673 return exports;
674}
675
676void QQmlJSTypeDescriptionReader::readInterfaces(UiScriptBinding *ast, const QQmlJSScope::Ptr &scope)
677{
678 auto *arrayLit = getArray(ast);
679
680 if (!arrayLit)
681 return;
682
684
685 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
686 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
687 if (!stringLit) {
688 addError(arrayLit->firstSourceLocation(),
689 tr("Expected array literal with only string literal members."));
690 return;
691 }
692
693 list << stringLit->value.toString();
694 }
695
696 scope->setInterfaceNames(list);
697}
698
699void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
701{
702 Q_ASSERT(ast);
703
704 if (!ast->statement) {
705 addError(ast->colonToken, tr("Expected array of numbers after colon."));
706 return;
707 }
708
709 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
710 if (!expStmt) {
711 addError(ast->statement->firstSourceLocation(),
712 tr("Expected array of numbers after colon."));
713 return;
714 }
715
716 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
717 if (!arrayLit) {
718 addError(expStmt->firstSourceLocation(), tr("Expected array of numbers after colon."));
719 return;
720 }
721
722 int exportIndex = 0;
723 const int exportCount = exports->size();
724 for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
725 auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
726 if (!numberLit) {
727 addError(arrayLit->firstSourceLocation(),
728 tr("Expected array literal with only number literal members."));
729 return;
730 }
731
732 if (exportIndex >= exportCount) {
733 addError(numberLit->firstSourceLocation(),
734 tr("Meta object revision without matching export."));
735 return;
736 }
737
738 const double v = numberLit->value;
739 const int metaObjectRevision = static_cast<int>(v);
740 if (metaObjectRevision != v) {
741 addError(numberLit->firstSourceLocation(), tr("Expected integer."));
742 return;
743 }
744
745 const QTypeRevision metaObjectVersion
746 = QTypeRevision::fromEncodedVersion(metaObjectRevision);
747 const QQmlJSScope::Export &entry = exports->at(exportIndex);
748 const QTypeRevision exportVersion = entry.version();
749 if (metaObjectVersion != exportVersion) {
750 addWarning(numberLit->firstSourceLocation(),
751 tr("Meta object revision and export version differ.\n"
752 "Revision %1 corresponds to version %2.%3; it should be %4.%5.")
753 .arg(metaObjectRevision)
754 .arg(metaObjectVersion.majorVersion()).arg(metaObjectVersion.minorVersion())
755 .arg(exportVersion.majorVersion()).arg(exportVersion.minorVersion()));
756 (*exports)[exportIndex] = QQmlJSScope::Export(entry.package(), entry.type(),
757 exportVersion, metaObjectVersion);
758 }
759 }
760}
761
762QStringList QQmlJSTypeDescriptionReader::readStringList(UiScriptBinding *ast)
763{
764 auto *arrayLit = getArray(ast);
765 if (!arrayLit)
766 return {};
767
769
770 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
771 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
772 if (!stringLit) {
773 addError(arrayLit->firstSourceLocation(),
774 tr("Expected array literal with only string literal members."));
775 return {};
776 }
777
778 list << stringLit->value.toString();
779 }
780
781 return list;
782}
783
784void QQmlJSTypeDescriptionReader::readDeferredNames(UiScriptBinding *ast,
785 const QQmlJSScope::Ptr &scope)
786{
787 scope->setOwnDeferredNames(readStringList(ast));
788}
789
790void QQmlJSTypeDescriptionReader::readImmediateNames(UiScriptBinding *ast,
791 const QQmlJSScope::Ptr &scope)
792{
793 scope->setOwnImmediateNames(readStringList(ast));
794}
795
796void QQmlJSTypeDescriptionReader::readEnumValues(UiScriptBinding *ast, QQmlJSMetaEnum *metaEnum)
797{
798 if (!ast)
799 return;
800 if (!ast->statement) {
801 addError(ast->colonToken, tr("Expected object literal after colon."));
802 return;
803 }
804
805 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
806 if (!expStmt) {
807 addError(ast->statement->firstSourceLocation(), tr("Expected expression after colon."));
808 return;
809 }
810
811 if (auto *objectLit = cast<ObjectPattern *>(expStmt->expression)) {
812 int currentValue = -1;
813 for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
814 if (PatternProperty *assignement = it->property) {
815 if (auto *name = cast<StringLiteralPropertyName *>(assignement->name)) {
816 metaEnum->addKey(name->id.toString());
817
818 if (auto *value = AST::cast<NumericLiteral *>(assignement->initializer)) {
819 currentValue = int(value->value);
820 } else if (auto *minus = AST::cast<UnaryMinusExpression *>(
821 assignement->initializer)) {
822 if (auto *value = AST::cast<NumericLiteral *>(minus->expression))
823 currentValue = -int(value->value);
824 else
825 ++currentValue;
826 } else {
827 ++currentValue;
828 }
829
830 metaEnum->addValue(currentValue);
831 continue;
832 }
833 }
834 addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
835 }
836 } else if (auto *arrayLit = cast<ArrayPattern *>(expStmt->expression)) {
837 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
838 if (PatternElement *element = it->element) {
839 if (auto *name = cast<StringLiteral *>(element->initializer)) {
840 metaEnum->addKey(name->value.toString());
841 continue;
842 }
843 }
844 addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
845 }
846 } else {
847 addError(ast->statement->firstSourceLocation(),
848 tr("Expected either array or object literal as enum definition."));
849 }
850}
851
void parse(QIODevice &input, const QString &name)
Definition parser.cpp:536
\inmodule QtCore
Definition qchar.h:48
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
T value(qsizetype i) const
Definition qlist.h:661
void append(parameter_type t)
Definition qlist.h:441
void setIsFlag(bool isFlag)
void setName(const QString &name)
void setTypeName(const QString &typeName)
void addValue(int value)
void addKey(const QString &key)
void setScoped(bool v)
void setAlias(const QString &alias)
void setIsConstructor(bool isConstructor)
void setIsJavaScriptFunction(bool isJavaScriptFunction)
QString methodName() const
void setMethodName(const QString &name)
void setMethodType(MethodType methodType)
void setIsCloned(bool isCloned)
void setConstructorIndex(RelativeFunctionIndex index)
void addParameter(const QQmlJSMetaParameter &p)
void setReturnTypeName(const QString &type)
void setIsComposite(bool v)
void setOwnDeferredNames(const QStringList &names)
void setExtensionTypeName(const QString &name)
void setInterfaceNames(const QStringList &interfaces)
static QQmlJSScope::Ptr create()
void setStructuredFlag(bool v)
void setAccessSemantics(AccessSemantics semantics)
void setOwnParentPropertyName(const QString &name)
void setOwnAttachedTypeName(const QString &name)
void setInternalName(const QString &internalName)
QString internalName() const
void setHasCustomParser(bool v)
void setIsSingleton(bool v)
void addOwnProperty(const QQmlJSMetaProperty &prop)
void setExtensionIsNamespace(bool v)
void setBaseTypeName(const QString &baseTypeName)
void setValueTypeName(const QString &name)
void setOwnImmediateNames(const QStringList &names)
void addOwnEnumeration(const QQmlJSMetaEnum &enumeration)
void addOwnMethod(const QQmlJSMetaMethod &method)
void setCreatableFlag(bool v)
void setOwnDefaultPropertyName(const QString &name)
void setFilePath(const QString &file)
void setPropertyLocallyRequired(const QString &name, bool isRequired)
bool operator()(QList< QQmlJSExportedScope > *objects, QStringList *dependencies)
virtual SourceLocation firstSourceLocation() const =0
SourceLocation firstSourceLocation() const override
UiObjectInitializer * initializer
SourceLocation firstSourceLocation() const override=0
UiHeaderItemList * headers
UiObjectMemberList * members
SourceLocation firstSourceLocation() const override
void setCode(const QString &code, int lineno, bool qmlMode=true, CodeContinuation codeContinuation=CodeContinuation::Reset)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:660
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
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
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
\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 fromEncodedVersion(Integer value)
Produces a QTypeRevision from the given value.
constexpr quint8 minorVersion() const
Returns the minor version encoded in the revision.
constexpr bool isValid() const
Returns true if the major version or the minor version is known, otherwise false.
constexpr quint8 majorVersion() const
Returns the major version encoded in the revision.
QString str
[2]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * typeName
GLsizei const GLfloat * v
[13]
GLenum type
GLuint GLsizei const GLchar * message
GLuint name
GLuint entry
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
static qreal component(const QPointF &point, unsigned int i)
static QTypeRevision parseVersion(const QString &str)
static QTypeRevision parseVersion(const QString &versionString)
QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define tr(X)
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
char * toString(const MyType &t)
[31]
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:17