7#include <QtQml/private/qqmljsparser_p.h>
8#include <QtQml/private/qqmljslexer_p.h>
9#include <QtQml/private/qqmljsengine_p.h>
11#include <QtCore/qdir.h>
12#include <QtCore/qstring.h>
16using namespace QQmlJS;
17using namespace QQmlJS::AST;
18using namespace Qt::StringLiterals;
20QString toString(
const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char(
'.'))
24 for (
const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
25 if (iter != qualifiedId)
34bool QQmlJSTypeDescriptionReader::operator()(
35 QList<QQmlJSExportedScope> *objects, QStringList *dependencies)
40 Parser parser(&engine);
42 lexer.setCode(m_source, 1,
true);
44 if (!parser.parse()) {
45 m_errorMessage = QString::fromLatin1(
"%1:%2: %3").arg(
46 QString::number(parser.errorLineNumber()),
47 QString::number(parser.errorColumnNumber()),
48 parser.errorMessage());
53 m_dependencies = dependencies;
54 readDocument(parser.ast());
56 return m_errorMessage.isEmpty();
59void QQmlJSTypeDescriptionReader::readDocument(UiProgram *ast)
62 addError(SourceLocation(), tr(
"Could not parse document."));
66 if (!ast->headers || ast->headers->next || !cast<UiImport *>(ast->headers->headerItem)) {
67 addError(SourceLocation(), tr(
"Expected a single import."));
71 auto *import = cast<UiImport *>(ast->headers->headerItem);
72 if (toString(import->importUri) != QLatin1String(
"QtQuick.tooling")) {
73 addError(import->importToken, tr(
"Expected import of QtQuick.tooling."));
77 if (!import->version) {
78 addError(import->firstSourceLocation(), tr(
"Import statement without version."));
82 if (import->version->version.majorVersion() != 1) {
83 addError(import->version->firstSourceLocation(),
84 tr(
"Major version different from 1 not supported."));
88 if (!ast->members || !ast->members->member || ast->members->next) {
89 addError(SourceLocation(), tr(
"Expected document to contain a single object definition."));
93 auto *module = cast<UiObjectDefinition *>(ast->members->member);
95 addError(SourceLocation(), tr(
"Expected document to contain a single object definition."));
99 if (toString(module->qualifiedTypeNameId) != QLatin1String(
"Module")) {
100 addError(SourceLocation(), tr(
"Expected document to contain a Module {} member."));
107void QQmlJSTypeDescriptionReader::readModule(UiObjectDefinition *ast)
109 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
110 UiObjectMember *member = it->member;
111 auto *component = cast<UiObjectDefinition *>(member);
113 auto *script = cast<UiScriptBinding *>(member);
114 if (script && (toString(script->qualifiedId) == QStringLiteral(
"dependencies"))) {
115 readDependencies(script);
121 typeName = toString(component->qualifiedTypeNameId);
123 if (!component || typeName != QLatin1String(
"Component")) {
127 if (typeName == QLatin1String(
"Component"))
128 readComponent(component);
132void QQmlJSTypeDescriptionReader::addError(
const SourceLocation &loc,
const QString &message)
134 m_errorMessage += QString::fromLatin1(
"%1:%2:%3: %4\n").arg(
135 QDir::toNativeSeparators(m_fileName),
136 QString::number(loc.startLine),
137 QString::number(loc.startColumn),
141void QQmlJSTypeDescriptionReader::addWarning(
const SourceLocation &loc,
const QString &message)
143 m_warningMessage += QString::fromLatin1(
"%1:%2:%3: %4\n").arg(
144 QDir::toNativeSeparators(m_fileName),
145 QString::number(loc.startLine),
146 QString::number(loc.startColumn),
150void QQmlJSTypeDescriptionReader::readDependencies(UiScriptBinding *ast)
152 auto *stmt = cast<ExpressionStatement*>(ast->statement);
154 addError(ast->statement->firstSourceLocation(), tr(
"Expected dependency definitions"));
157 auto *exp = cast<ArrayPattern *>(stmt->expression);
159 addError(stmt->expression->firstSourceLocation(), tr(
"Expected dependency definitions"));
162 for (PatternElementList *l = exp->elements; l; l = l->next) {
163 auto *str = cast<StringLiteral *>(l->element->initializer);
164 *m_dependencies << str->value.toString();
168void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
170 m_currentCtorIndex = 0;
171 m_currentMethodIndex = 0;
172 QQmlJSScope::Ptr scope = QQmlJSScope::create();
173 QList<QQmlJSScope::Export> exports;
175 UiScriptBinding *metaObjectRevisions =
nullptr;
176 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
177 UiObjectMember *member = it->member;
178 auto *component = cast<UiObjectDefinition *>(member);
179 auto *script = cast<UiScriptBinding *>(member);
181 QString name = toString(component->qualifiedTypeNameId);
182 if (name == QLatin1String(
"Property"))
183 readProperty(component, scope);
184 else if (name == QLatin1String(
"Method") || name == QLatin1String(
"Signal"))
185 readSignalOrMethod(component, name == QLatin1String(
"Method"), scope);
186 else if (name == QLatin1String(
"Enum"))
187 readEnum(component, scope);
189 addWarning(component->firstSourceLocation(),
190 tr(
"Expected only Property, Method, Signal and Enum object definitions, "
191 "not \"%1\".").arg(name));
193 QString name = toString(script->qualifiedId);
194 if (name == QLatin1String(
"file")) {
195 scope->setFilePath(readStringBinding(script));
196 }
else if (name == QLatin1String(
"lineNumber")) {
197 scope->setLineNumber(readNumericBinding(script));
198 }
else if (name == QLatin1String(
"name")) {
199 scope->setInternalName(readStringBinding(script));
200 }
else if (name == QLatin1String(
"prototype")) {
201 scope->setBaseTypeName(readStringBinding(script));
202 }
else if (name == QLatin1String(
"defaultProperty")) {
203 scope->setOwnDefaultPropertyName(readStringBinding(script));
204 }
else if (name == QLatin1String(
"parentProperty")) {
205 scope->setOwnParentPropertyName(readStringBinding(script));
206 }
else if (name == QLatin1String(
"exports")) {
207 exports = readExports(script);
208 }
else if (name == QLatin1String(
"aliases")) {
209 readAliases(script, scope);
210 }
else if (name == QLatin1String(
"interfaces")) {
211 readInterfaces(script, scope);
212 }
else if (name == QLatin1String(
"exportMetaObjectRevisions")) {
213 metaObjectRevisions = script;
214 }
else if (name == QLatin1String(
"attachedType")) {
215 scope->setOwnAttachedTypeName(readStringBinding(script));
216 }
else if (name == QLatin1String(
"valueType")) {
217 scope->setElementTypeName(readStringBinding(script));
218 }
else if (name == QLatin1String(
"isSingleton")) {
219 scope->setIsSingleton(readBoolBinding(script));
220 }
else if (name == QLatin1String(
"isCreatable")) {
221 scope->setCreatableFlag(readBoolBinding(script));
222 }
else if (name == QLatin1String(
"isStructured")) {
223 scope->setStructuredFlag(readBoolBinding(script));
224 }
else if (name == QLatin1String(
"isComposite")) {
225 scope->setIsComposite(readBoolBinding(script));
226 }
else if (name == QLatin1String(
"hasCustomParser")) {
227 scope->setHasCustomParser(readBoolBinding(script));
228 }
else if (name == QLatin1String(
"enforcesScopedEnums")) {
229 scope->setEnforcesScopedEnumsFlag(readBoolBinding(script));
230 }
else if (name == QLatin1String(
"accessSemantics")) {
231 const QString semantics = readStringBinding(script);
232 if (semantics == QLatin1String(
"reference")) {
233 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Reference);
234 }
else if (semantics == QLatin1String(
"value")) {
235 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Value);
236 }
else if (semantics == QLatin1String(
"none")) {
237 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::None);
238 }
else if (semantics == QLatin1String(
"sequence")) {
239 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
241 addWarning(script->firstSourceLocation(),
242 tr(
"Unknown access semantics \"%1\".").arg(semantics));
244 }
else if (name == QLatin1String(
"extension")) {
245 scope->setExtensionTypeName(readStringBinding(script));
246 }
else if (name == QLatin1String(
"extensionIsJavaScript")) {
247 scope->setExtensionIsJavaScript(readBoolBinding(script));
248 }
else if (name == QLatin1String(
"extensionIsNamespace")) {
249 scope->setExtensionIsNamespace(readBoolBinding(script));
250 }
else if (name == QLatin1String(
"deferredNames")) {
251 readDeferredNames(script, scope);
252 }
else if (name == QLatin1String(
"immediateNames")) {
253 readImmediateNames(script, scope);
254 }
else if (name == QLatin1String(
"isJavaScriptBuiltin")) {
255 scope->setIsJavaScriptBuiltin(readBoolBinding(script));
256 }
else if (name == QLatin1String(
"metaObjectHash")) {
257 scope->setMetaObjectHash(readStringBinding(script));
259 addWarning(script->firstSourceLocation(),
260 tr(
"Expected only lineNumber, name, prototype, defaultProperty, "
262 "valueType, exports, interfaces, isSingleton, isCreatable, "
263 "isStructured, isComposite, hasCustomParser, enforcesScopedEnums, "
264 "aliases, exportMetaObjectRevisions, deferredNames, metaObjectHash, "
265 "and immediateNames in script bindings, not \"%1\".")
269 addWarning(member->firstSourceLocation(),
270 tr(
"Expected only script bindings and object definitions."));
274 if (scope->internalName().isEmpty()) {
275 addError(ast->firstSourceLocation(), tr(
"Component definition is missing a name binding."));
279 if (metaObjectRevisions)
280 checkMetaObjectRevisions(metaObjectRevisions, &exports);
281 m_objects->append({scope, exports});
284void QQmlJSTypeDescriptionReader::readSignalOrMethod(
285 UiObjectDefinition *ast,
bool isMethod,
const QQmlJSScope::Ptr &scope)
287 QQmlJSMetaMethod metaMethod;
290 metaMethod.setMethodType(QQmlJSMetaMethodType::Slot);
292 metaMethod.setMethodType(QQmlJSMetaMethodType::Signal);
294 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
295 UiObjectMember *member = it->member;
296 auto *component = cast<UiObjectDefinition *>(member);
297 auto *script = cast<UiScriptBinding *>(member);
299 QString name = toString(component->qualifiedTypeNameId);
300 if (name == QLatin1String(
"Parameter")) {
301 readParameter(component, &metaMethod);
303 addWarning(component->firstSourceLocation(),
304 tr(
"Expected only Parameter in object definitions."));
307 QString name = toString(script->qualifiedId);
308 if (name == QLatin1String(
"name")) {
309 metaMethod.setMethodName(readStringBinding(script));
310 }
else if (name == QLatin1String(
"lineNumber")) {
311 metaMethod.setSourceLocation(
312 SourceLocation::fromQSizeType(0, 0, readIntBinding(script), 1));
313 }
else if (name == QLatin1String(
"type")) {
314 metaMethod.setReturnTypeName(readStringBinding(script));
315 }
else if (name == QLatin1String(
"revision")) {
316 metaMethod.setRevision(readIntBinding(script));
317 }
else if (name == QLatin1String(
"isCloned")) {
318 metaMethod.setIsCloned(readBoolBinding(script));
319 }
else if (name == QLatin1String(
"isConstructor")) {
323 if (readBoolBinding(script)) {
324 metaMethod.setIsConstructor(
true);
325 metaMethod.setConstructorIndex(
326 QQmlJSMetaMethod::RelativeFunctionIndex(m_currentCtorIndex++));
328 }
else if (name == QLatin1String(
"isJavaScriptFunction")) {
329 metaMethod.setIsJavaScriptFunction(readBoolBinding(script));
330 }
else if (name == QLatin1String(
"isList")) {
331 auto metaReturnType = metaMethod.returnValue();
332 metaReturnType.setIsList(readBoolBinding(script));
333 metaMethod.setReturnValue(metaReturnType);
334 }
else if (name == QLatin1String(
"isPointer")) {
338 auto metaReturnType = metaMethod.returnValue();
339 metaReturnType.setIsPointer(readBoolBinding(script));
340 metaMethod.setReturnValue(metaReturnType);
341 }
else if (name == QLatin1String(
"isTypeConstant")
342 || name == QLatin1String(
"isConstant")) {
344 auto metaReturnType = metaMethod.returnValue();
345 metaReturnType.setTypeQualifier(readBoolBinding(script)
346 ? QQmlJSMetaParameter::Const
347 : QQmlJSMetaParameter::NonConst);
348 metaMethod.setReturnValue(metaReturnType);
349 }
else if (name == QLatin1String(
"isMethodConstant")) {
350 metaMethod.setIsConst(readBoolBinding(script));
352 addWarning(script->firstSourceLocation(),
353 tr(
"Expected only name, lineNumber, type, revision, isPointer, "
355 "isList, isCloned, isConstructor, isMethodConstant, and "
356 "isJavaScriptFunction in script bindings."));
359 addWarning(member->firstSourceLocation(),
360 tr(
"Expected only script bindings and object definitions."));
364 if (metaMethod.methodName().isEmpty()) {
365 addError(ast->firstSourceLocation(),
366 tr(
"Method or signal is missing a name script binding."));
373 if (!metaMethod.isConstructor())
374 metaMethod.setMethodIndex(QQmlJSMetaMethod::RelativeFunctionIndex(m_currentMethodIndex++));
376 if (metaMethod.returnTypeName().isEmpty())
377 metaMethod.setReturnTypeName(QLatin1String(
"void"));
379 scope->addOwnMethod(metaMethod);
382void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast,
const QQmlJSScope::Ptr &scope)
384 QQmlJSMetaProperty property;
385 property.setIsWritable(
true);
386 bool isRequired =
false;
388 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
389 UiObjectMember *member = it->member;
390 auto *script = cast<UiScriptBinding *>(member);
392 addWarning(member->firstSourceLocation(), tr(
"Expected script binding."));
396 QString id = toString(script->qualifiedId);
397 if (id == QLatin1String(
"name")) {
398 property.setPropertyName(readStringBinding(script));
399 }
else if (id == QLatin1String(
"lineNumber")) {
400 property.setSourceLocation(
401 SourceLocation::fromQSizeType(0, 0, readIntBinding(script), 1));
402 }
else if (id == QLatin1String(
"type")) {
403 property.setTypeName(readStringBinding(script));
404 }
else if (id == QLatin1String(
"isPointer")) {
405 property.setIsPointer(readBoolBinding(script));
406 }
else if (id == QLatin1String(
"isReadonly")) {
407 property.setIsWritable(!readBoolBinding(script));
408 }
else if (id == QLatin1String(
"isRequired")) {
409 isRequired = readBoolBinding(script);
410 }
else if (id == QLatin1String(
"isList")) {
411 property.setIsList(readBoolBinding(script));
412 }
else if (id == QLatin1String(
"isFinal")) {
413 property.setIsFinal(readBoolBinding(script));
414 }
else if (id == QLatin1String(
"isVirtual")) {
415 property.setIsVirtual(readBoolBinding(script));
416 }
else if (id == QLatin1String(
"isOverride")) {
417 property.setIsOverride(readBoolBinding(script));
418 }
else if (id == QLatin1String(
"isTypeConstant")) {
419 property.setIsTypeConstant(readBoolBinding(script));
420 }
else if (id == QLatin1String(
"isPropertyConstant")) {
421 property.setIsPropertyConstant(readBoolBinding(script));
422 }
else if (id == QLatin1String(
"isConstant")) {
424 property.setIsPropertyConstant(readBoolBinding(script));
425 }
else if (id == QLatin1String(
"revision")) {
426 property.setRevision(readIntBinding(script));
427 }
else if (id == QLatin1String(
"bindable")) {
428 property.setBindable(readStringBinding(script));
429 }
else if (id == QLatin1String(
"read")) {
430 property.setRead(readStringBinding(script));
431 }
else if (id == QLatin1String(
"write")) {
432 property.setWrite(readStringBinding(script));
433 }
else if (id == QLatin1String(
"reset")) {
434 property.setReset(readStringBinding(script));
435 }
else if (id == QLatin1String(
"notify")) {
436 property.setNotify(readStringBinding(script));
437 }
else if (id == QLatin1String(
"index")) {
438 property.setIndex(readIntBinding(script));
439 }
else if (id == QLatin1String(
"privateClass")) {
440 property.setPrivateClass(readStringBinding(script));
442 addWarning(script->firstSourceLocation(),
443 tr(
"Expected only type, name, lineNumber, revision, isPointer, "
444 "isTypeConstant, isReadonly, isRequired, "
445 "isFinal, isList, bindable, read, write, isPropertyConstant, reset, "
446 "notify, index, privateClass and script bindings."));
450 if (property.propertyName().isEmpty()) {
451 addError(ast->firstSourceLocation(),
452 tr(
"Property object is missing a name script binding."));
456 scope->addOwnProperty(property);
458 scope->setPropertyLocallyRequired(property.propertyName(),
true);
461void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast,
const QQmlJSScope::Ptr &scope)
463 QQmlJSMetaEnum metaEnum;
465 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
466 UiObjectMember *member = it->member;
467 auto *script = cast<UiScriptBinding *>(member);
469 addWarning(member->firstSourceLocation(), tr(
"Expected script binding."));
473 QString name = toString(script->qualifiedId);
474 if (name == QLatin1String(
"name")) {
475 metaEnum.setName(readStringBinding(script));
476 }
else if (name == QLatin1String(
"alias")) {
477 metaEnum.setAlias(readStringBinding(script));
478 }
else if (name == QLatin1String(
"isFlag")) {
479 metaEnum.setIsFlag(readBoolBinding(script));
480 }
else if (name == QLatin1String(
"values")) {
481 readEnumValues(script, &metaEnum);
482 }
else if (name == QLatin1String(
"isScoped")) {
483 metaEnum.setIsScoped(readBoolBinding(script));
484 }
else if (name == QLatin1String(
"type")) {
485 metaEnum.setTypeName(readStringBinding(script));
486 }
else if (name == QLatin1String(
"lineNumber")) {
487 metaEnum.setLineNumber(readIntBinding(script));
489 addWarning(script->firstSourceLocation(),
490 tr(
"Expected only name, alias, isFlag, values, isScoped, type, or "
495 scope->addOwnEnumeration(metaEnum);
498void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSMetaMethod *metaMethod)
502 bool isConstant =
false;
503 bool isPointer =
false;
506 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
507 UiObjectMember *member = it->member;
508 auto *script = cast<UiScriptBinding *>(member);
510 addWarning(member->firstSourceLocation(), tr(
"Expected script binding."));
514 const QString id = toString(script->qualifiedId);
515 if (id == QLatin1String(
"name")) {
516 name = readStringBinding(script);
517 }
else if (id == QLatin1String(
"type")) {
518 type = readStringBinding(script);
519 }
else if (id == QLatin1String(
"isPointer")) {
520 isPointer = readBoolBinding(script);
521 }
else if (id == QLatin1String(
"isTypeConstant") || id == QLatin1String(
"isConstant")) {
523 isConstant = readBoolBinding(script);
524 }
else if (id == QLatin1String(
"isReadonly")) {
526 }
else if (id == QLatin1String(
"isList")) {
527 isList = readBoolBinding(script);
529 addWarning(script->firstSourceLocation(),
530 tr(
"Expected only name, type, isPointer, isTypeConstant, isReadonly, "
531 "or IsList script bindings."));
535 QQmlJSMetaParameter p(name, type);
536 p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
537 p.setIsPointer(isPointer);
539 metaMethod->addParameter(std::move(p));
542QString QQmlJSTypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
546 if (!ast->statement) {
547 addError(ast->colonToken, tr(
"Expected string after colon."));
551 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
553 addError(ast->statement->firstSourceLocation(), tr(
"Expected string after colon."));
557 auto *stringLit = cast<StringLiteral *>(expStmt->expression);
559 addError(expStmt->firstSourceLocation(), tr(
"Expected string after colon."));
563 return stringLit->value.toString();
566bool QQmlJSTypeDescriptionReader::readBoolBinding(UiScriptBinding *ast)
570 if (!ast->statement) {
571 addError(ast->colonToken, tr(
"Expected boolean after colon."));
575 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
577 addError(ast->statement->firstSourceLocation(), tr(
"Expected boolean after colon."));
581 auto *trueLit = cast<TrueLiteral *>(expStmt->expression);
582 auto *falseLit = cast<FalseLiteral *>(expStmt->expression);
583 if (!trueLit && !falseLit) {
584 addError(expStmt->firstSourceLocation(), tr(
"Expected true or false after colon."));
591double QQmlJSTypeDescriptionReader::readNumericBinding(UiScriptBinding *ast)
595 if (!ast->statement) {
596 addError(ast->colonToken, tr(
"Expected numeric literal after colon."));
600 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
602 addError(ast->statement->firstSourceLocation(),
603 tr(
"Expected numeric literal after colon."));
607 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
609 addError(expStmt->firstSourceLocation(), tr(
"Expected numeric literal after colon."));
613 return numericLit->value;
618 const int dotIdx = versionString.indexOf(QLatin1Char(
'.'));
620 return QTypeRevision();
622 const int maybeMajor = QStringView{versionString}.left(dotIdx).toInt(&ok);
624 return QTypeRevision();
625 const int maybeMinor = QStringView{versionString}.mid(dotIdx + 1).toInt(&ok);
627 return QTypeRevision();
628 return QTypeRevision::fromVersion(maybeMajor, maybeMinor);
631QTypeRevision QQmlJSTypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
633 QTypeRevision invalidVersion;
635 if (!ast || !ast->statement) {
636 addError((ast ? ast->colonToken : SourceLocation()),
637 tr(
"Expected numeric literal after colon."));
638 return invalidVersion;
641 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
643 addError(ast->statement->firstSourceLocation(),
644 tr(
"Expected numeric literal after colon."));
645 return invalidVersion;
648 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
650 addError(expStmt->firstSourceLocation(), tr(
"Expected numeric literal after colon."));
651 return invalidVersion;
654 return parseVersion(m_source.mid(numericLit->literalToken.begin(),
655 numericLit->literalToken.length));
658int QQmlJSTypeDescriptionReader::readIntBinding(UiScriptBinding *ast)
660 double v = readNumericBinding(ast);
661 int i =
static_cast<
int>(v);
664 addError(ast->firstSourceLocation(), tr(
"Expected integer after colon."));
671ArrayPattern* QQmlJSTypeDescriptionReader::getArray(UiScriptBinding *ast)
675 if (!ast->statement) {
676 addError(ast->colonToken, tr(
"Expected array of strings after colon."));
680 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
682 addError(ast->statement->firstSourceLocation(),
683 tr(
"Expected array of strings after colon."));
687 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
689 addError(expStmt->firstSourceLocation(), tr(
"Expected array of strings after colon."));
696QList<QQmlJSScope::Export> QQmlJSTypeDescriptionReader::readExports(UiScriptBinding *ast)
698 QList<QQmlJSScope::Export> exports;
699 auto *arrayLit = getArray(ast);
704 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
705 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
708 addError(arrayLit->firstSourceLocation(),
709 tr(
"Expected array literal with only string literal members."));
713 QString exp = stringLit->value.toString();
714 int slashIdx = exp.indexOf(QLatin1Char(
'/'));
715 int spaceIdx = exp.indexOf(QLatin1Char(
' '));
716 const QTypeRevision version = parseVersion(exp.mid(spaceIdx + 1));
718 if (spaceIdx == -1 || !version.isValid()) {
719 addError(stringLit->firstSourceLocation(),
720 tr(
"Expected string literal to contain 'Package/Name major.minor' "
721 "or 'Name major.minor'."));
726 package = exp.left(slashIdx);
727 QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
730 exports.append(QQmlJSScope::Export(package, name, version, version));
736void QQmlJSTypeDescriptionReader::readAliases(
737 QQmlJS::AST::UiScriptBinding *ast,
const QQmlJSScope::Ptr &scope)
739 scope->setAliases(readStringList(ast));
742void QQmlJSTypeDescriptionReader::readInterfaces(UiScriptBinding *ast,
const QQmlJSScope::Ptr &scope)
744 auto *arrayLit = getArray(ast);
751 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
752 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
754 addError(arrayLit->firstSourceLocation(),
755 tr(
"Expected array literal with only string literal members."));
759 list << stringLit->value.toString();
762 scope->setInterfaceNames(list);
765void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
766 UiScriptBinding *ast, QList<QQmlJSScope::Export> *exports)
770 if (!ast->statement) {
771 addError(ast->colonToken, tr(
"Expected array of numbers after colon."));
775 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
777 addError(ast->statement->firstSourceLocation(),
778 tr(
"Expected array of numbers after colon."));
782 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
784 addError(expStmt->firstSourceLocation(), tr(
"Expected array of numbers after colon."));
789 const int exportCount = exports->size();
790 for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
791 auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
793 addError(arrayLit->firstSourceLocation(),
794 tr(
"Expected array literal with only number literal members."));
798 if (exportIndex >= exportCount) {
799 addError(numberLit->firstSourceLocation(),
800 tr(
"Meta object revision without matching export."));
804 const double v = numberLit->value;
805 const int metaObjectRevision =
static_cast<
int>(v);
806 if (metaObjectRevision != v) {
807 addError(numberLit->firstSourceLocation(), tr(
"Expected integer."));
811 const QTypeRevision metaObjectVersion
812 = QTypeRevision::fromEncodedVersion(metaObjectRevision);
813 const QQmlJSScope::Export &entry = exports->at(exportIndex);
814 const QTypeRevision exportVersion = entry.version();
815 if (metaObjectVersion != exportVersion) {
816 addWarning(numberLit->firstSourceLocation(),
817 tr(
"Meta object revision and export version differ.\n"
818 "Revision %1 corresponds to version %2.%3; it should be %4.%5.")
819 .arg(metaObjectRevision)
820 .arg(metaObjectVersion.majorVersion()).arg(metaObjectVersion.minorVersion())
821 .arg(exportVersion.majorVersion()).arg(exportVersion.minorVersion()));
822 (*exports)[exportIndex] = QQmlJSScope::Export(entry.package(), entry.type(),
823 exportVersion, metaObjectVersion);
828QStringList QQmlJSTypeDescriptionReader::readStringList(UiScriptBinding *ast)
830 auto *arrayLit = getArray(ast);
836 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
837 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
839 addError(arrayLit->firstSourceLocation(),
840 tr(
"Expected array literal with only string literal members."));
844 list << stringLit->value.toString();
850void QQmlJSTypeDescriptionReader::readDeferredNames(UiScriptBinding *ast,
851 const QQmlJSScope::Ptr &scope)
853 scope->setOwnDeferredNames(readStringList(ast));
856void QQmlJSTypeDescriptionReader::readImmediateNames(UiScriptBinding *ast,
857 const QQmlJSScope::Ptr &scope)
859 scope->setOwnImmediateNames(readStringList(ast));
862void QQmlJSTypeDescriptionReader::readEnumValues(UiScriptBinding *ast, QQmlJSMetaEnum *metaEnum)
866 if (!ast->statement) {
867 addError(ast->colonToken, tr(
"Expected object literal after colon."));
871 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
873 addError(ast->statement->firstSourceLocation(), tr(
"Expected expression after colon."));
877 if (
auto *objectLit = cast<ObjectPattern *>(expStmt->expression)) {
878 int currentValue = -1;
879 for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
880 if (PatternProperty *assignement = it->property) {
881 if (
auto *name = cast<StringLiteralPropertyName *>(assignement->name)) {
882 metaEnum->addKey(name->id.toString());
884 if (
auto *value = AST::cast<NumericLiteral *>(assignement->initializer)) {
885 currentValue =
int(value->value);
886 }
else if (
auto *minus = AST::cast<UnaryMinusExpression *>(
887 assignement->initializer)) {
888 if (
auto *value = AST::cast<NumericLiteral *>(minus->expression))
889 currentValue = -
int(value->value);
896 metaEnum->addValue(currentValue);
900 addError(it->firstSourceLocation(), tr(
"Expected strings as enum keys."));
902 }
else if (
auto *arrayLit = cast<ArrayPattern *>(expStmt->expression)) {
903 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
904 if (PatternElement *element = it->element) {
905 if (
auto *name = cast<StringLiteral *>(element->initializer)) {
906 metaEnum->addKey(name->value.toString());
910 addError(it->firstSourceLocation(), tr(
"Expected strings as enum keys."));
913 addError(ast->statement->firstSourceLocation(),
914 tr(
"Expected either array or object literal as enum definition."));
Combined button and popup list for selecting options.
static QTypeRevision parseVersion(const QString &versionString)
QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))