diff options
Diffstat (limited to 'src/libs/qmljs/qmljslink.cpp')
-rw-r--r-- | src/libs/qmljs/qmljslink.cpp | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index e505a9e4c5..2d91324f64 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -93,7 +93,7 @@ public: bool importLibrary(const Document::Ptr &doc, const QString &libraryPath, - Import *import, + Import *import, ObjectValue *targetObject, const QString &importPath = QString()); void loadQmldirComponents(ObjectValue *import, LanguageUtils::ComponentVersion version, @@ -239,6 +239,32 @@ Context::ImportsPerDocument LinkPrivate::linkImports() return importsPerDocument; } +/** + * A workaround for prototype issues with QEasingCurve in Qt 5.15. + * + * In this Qt version, QEasingCurve is declared in builtins.qmltypes, but its + * prototype, QQmlEasingValueType, is only contained in the QtQml module. + * + * This code attempts to resolve QEasingCurve's prototype if it hasn't been set + * already. It's intended to be called after all CppQmlTypes have been loaded. + */ +static void workaroundQEasingCurve(CppQmlTypes &cppTypes) +{ + const CppComponentValue *easingCurve = cppTypes.objectByCppName("QEasingCurve"); + if (!easingCurve || easingCurve->prototype()) + return; + + const QString superclassName = easingCurve->metaObject()->superclassName(); + if (superclassName.isEmpty()) + return; + + const CppComponentValue *prototype = cppTypes.objectByCppName(superclassName); + if (!prototype) + return; + + const_cast<CppComponentValue *>(easingCurve)->setPrototype(prototype); +} + void LinkPrivate::populateImportedTypes(Imports *imports, const Document::Ptr &doc) { importableModuleApis.clear(); @@ -287,6 +313,8 @@ void LinkPrivate::populateImportedTypes(Imports *imports, const Document::Ptr &d if (import.object) imports->append(import); } + + workaroundQEasingCurve(m_valueOwner->cppQmlTypes()); } /* @@ -312,7 +340,7 @@ Import LinkPrivate::importFileOrDirectory(const Document::Ptr &doc, const Import || importInfo.type() == ImportType::ImplicitDirectory) { import.object = new ObjectValue(m_valueOwner); - importLibrary(doc, path, &import); + importLibrary(doc, path, &import, import.object); const QList<Document::Ptr> documentsInDirectory = m_snapshot.documentsInDirectory(path); for (const Document::Ptr &importedDoc : documentsInDirectory) { @@ -337,7 +365,7 @@ Import LinkPrivate::importFileOrDirectory(const Document::Ptr &doc, const Import } else if (importInfo.type() == ImportType::QrcDirectory){ import.object = new ObjectValue(m_valueOwner); - importLibrary(doc, path, &import); + importLibrary(doc, path, &import, import.object); const QMap<QString, QStringList> paths = ModelManagerInterface::instance()->filesInQrcPath(path); @@ -382,7 +410,7 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im const ComponentVersion version = importInfo.version(); QString libraryPath = modulePath(packageName, version.toString(), m_importPaths); - bool importFound = !libraryPath.isEmpty() && importLibrary(doc, libraryPath, &import); + bool importFound = !libraryPath.isEmpty() && importLibrary(doc, libraryPath, &import, import.object); if (!importFound) { for (const QString &dir : qAsConst(m_applicationDirectories)) { @@ -390,7 +418,7 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im // This adds the types to the C++ types, to be found below if applicable. if (it.hasNext()) - importLibrary(doc, dir, &import); + importLibrary(doc, dir, &import, import.object); } } @@ -436,6 +464,7 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im bool LinkPrivate::importLibrary(const Document::Ptr &doc, const QString &libraryPath, Import *import, + ObjectValue *targetObject, const QString &importPath) { const ImportInfo &importInfo = import->info; @@ -451,6 +480,38 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc, if (const UiImport *ast = importInfo.ast()) errorLoc = locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()); + // Load imports that are mentioned by the "import" command in a qmldir + // file into the same targetObject, using the same version and "as". + // + // Note: Since this works on the same targetObject, the ModuleApi setPrototype() + // logic will not work. But ModuleApi isn't used in Qt versions that use import + // commands in qmldir files, and is pending removal in Qt 6. + for (const auto &importName : libraryInfo.imports()) { + Import subImport; + subImport.valid = true; + subImport.info = ImportInfo::moduleImport(importName, version, importInfo.as(), importInfo.ast()); + subImport.libraryPath = modulePath(importName, version.toString(), m_importPaths); + bool subImportFound = importLibrary(doc, subImport.libraryPath, &subImport, targetObject, importPath); + + if (!subImportFound && errorLoc.isValid()) { + import->valid = false; + error(doc, errorLoc, + Link::tr( + "Implicit import '%1' of QML module '%2' not found.\n\n" + "Import paths:\n" + "%3\n\n" + "For qmake projects, use the QML_IMPORT_PATH variable to add import paths.\n" + "For Qbs projects, declare and set a qmlImportPaths property in your product " + "to add import paths.\n" + "For qmlproject projects, use the importPaths property to add import paths.\n" + "For CMake projects, make sure QML_IMPORT_PATH variable is in CMakeCache.txt.\n") + .arg(importName, importInfo.name(), m_importPaths.join(QLatin1Char('\n')))); + } else if (!subImport.valid) { + import->valid = false; + } + } + + // Load types from qmltypes or plugins if (!libraryInfo.plugins().isEmpty() || !libraryInfo.typeInfos().isEmpty()) { if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::NoTypeInfo) { ModelManagerInterface *modelManager = ModelManagerInterface::instance(); @@ -493,7 +554,7 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc, const auto objects = m_valueOwner->cppQmlTypes().createObjectsForImport(packageName, version); for (const CppComponentValue *object : objects) - import->object->setMember(object->className(), object); + targetObject->setMember(object->className(), object); // all but no-uri module apis become available for import QList<ModuleApiInfo> noUriModuleApis; @@ -508,13 +569,14 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc, // if a module api has no uri, it shares the same name ModuleApiInfo sameUriModuleApi = findBestModuleApi(noUriModuleApis, version); if (sameUriModuleApi.version.isValid()) { - import->object->setPrototype(m_valueOwner->cppQmlTypes() + targetObject->setPrototype(m_valueOwner->cppQmlTypes() .objectByCppName(sameUriModuleApi.cppName)); } } } - loadQmldirComponents(import->object, version, libraryInfo, libraryPath); + // Load types that are mentioned explicitly in the qmldir + loadQmldirComponents(targetObject, version, libraryInfo, libraryPath); return true; } |