diff --git a/src/libs/languageutils/componentversion.cpp b/src/libs/languageutils/componentversion.cpp index 7811bb438cada43312f4ccde587aa91a5cb873e3..4368d5f94f8fd5b0b3d26944fcf885b08bc02e8e 100644 --- a/src/libs/languageutils/componentversion.cpp +++ b/src/libs/languageutils/componentversion.cpp @@ -34,9 +34,12 @@ #include <QtCore/QString> +#include <limits> + using namespace LanguageUtils; const int ComponentVersion::NoVersion = -1; +const int ComponentVersion::MaxVersion = std::numeric_limits<int>::max(); ComponentVersion::ComponentVersion() : _major(NoVersion), _minor(NoVersion) diff --git a/src/libs/languageutils/componentversion.h b/src/libs/languageutils/componentversion.h index 5f8e413fb66a60dc7785c4d641efd66dfbedd0a9..baa8d4e1878ca068974272346f49a17c26ff95fa 100644 --- a/src/libs/languageutils/componentversion.h +++ b/src/libs/languageutils/componentversion.h @@ -44,6 +44,7 @@ class LANGUAGEUTILS_EXPORT ComponentVersion public: static const int NoVersion; + static const int MaxVersion; ComponentVersion(); ComponentVersion(int major, int minor); diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 467c522c74c42c579e8f67e95f3275c63631ba50..2cfeb1d6ee0521bbfb91d15103dce20fd6b96089 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -357,14 +357,14 @@ void Document::extractPragmas(QString *source) } } -LibraryInfo::LibraryInfo() - : _valid(false) +LibraryInfo::LibraryInfo(Status status) + : _status(status) , _dumpStatus(DumpNotStartedOrRunning) { } LibraryInfo::LibraryInfo(const QmlDirParser &parser) - : _valid(true) + : _status(Found) , _components(parser.components()) , _plugins(parser.plugins()) , _dumpStatus(DumpNotStartedOrRunning) diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index 2c1a516cac9ff312074d4189e9ed373e823db62f..b1aaadaa32f62c63944e9129f0be23011d388f42 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -127,8 +127,14 @@ public: DumpError }; + enum Status { + NotScanned, + NotFound, + Found + }; + private: - bool _valid; + Status _status; QList<QmlDirParser::Component> _components; QList<QmlDirParser::Plugin> _plugins; typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList; @@ -138,8 +144,8 @@ private: QString _dumpError; public: - LibraryInfo(); - LibraryInfo(const QmlDirParser &parser); + explicit LibraryInfo(Status status = NotScanned); + explicit LibraryInfo(const QmlDirParser &parser); ~LibraryInfo(); QList<QmlDirParser::Component> components() const @@ -155,7 +161,10 @@ public: { _metaObjects = objects; } bool isValid() const - { return _valid; } + { return _status == Found; } + + bool wasScanned() const + { return _status != NotScanned; } DumpStatus dumpStatus() const { return _dumpStatus; } diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 8f20b447d22488268af525341c366f18d760e85f..c9c1bb8e92628079a8475f039c3d03f396bd2e74 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -43,8 +43,6 @@ #include <QtCore/QDir> #include <QtCore/QDebug> -#include <limits> - using namespace LanguageUtils; using namespace QmlJS; using namespace QmlJS::Interpreter; @@ -276,18 +274,37 @@ ObjectValue *Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo bool importFound = false; - // check the filesystem const QString &packagePath = importInfo.name(); + // check the filesystem with full version foreach (const QString &importPath, d->importPaths) { - QString libraryPath = importPath; - libraryPath += QDir::separator(); - libraryPath += packagePath; + QString libraryPath = QString("%1/%2.%3").arg(importPath, packagePath, version.toString()); if (importLibrary(doc, import, libraryPath, importInfo, importPath)) { importFound = true; break; } } + if (!importFound) { + // check the filesystem with major version + foreach (const QString &importPath, d->importPaths) { + QString libraryPath = QString("%1/%2.%3").arg(importPath, packagePath, + QString::number(version.majorVersion())); + if (importLibrary(doc, import, libraryPath, importInfo, importPath)) { + importFound = true; + break; + } + } + } + if (!importFound) { + // check the filesystem with no version + foreach (const QString &importPath, d->importPaths) { + QString libraryPath = QString("%1/%2").arg(importPath, packagePath); + if (importLibrary(doc, import, libraryPath, importInfo, importPath)) { + importFound = true; + break; + } + } + } // if there are cpp-based types for this package, use them too if (engine()->cppQmlTypes().hasPackage(packageName)) { @@ -406,8 +423,7 @@ void Link::loadQmldirComponents(Interpreter::ObjectValue *import, ComponentVersi // if the version isn't valid, import the latest if (!version.isValid()) { - const int maxVersion = std::numeric_limits<int>::max(); - version = ComponentVersion(maxVersion, maxVersion); + version = ComponentVersion(ComponentVersion::MaxVersion, ComponentVersion::MaxVersion); } diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 08f943e055444de4ab26e48e9e1167493967b87a..5cb426e2c2e98f7ee1867fbcab36ddc926abbbbf 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -285,7 +285,9 @@ void ModelManager::updateLibraryInfo(const QString &path, const LibraryInfo &inf QMutexLocker locker(&m_mutex); _snapshot.insertLibraryInfo(path, info); } - emit libraryInfoUpdated(path, info); + // only emit if we got new useful information + if (info.isValid()) + emit libraryInfoUpdated(path, info); } static QStringList qmlFilesInDirectory(const QString &path) @@ -356,15 +358,22 @@ static bool findNewQmlLibraryInPath(const QString &path, QSet<QString> *newLibraries) { // if we know there is a library, done - if (snapshot.libraryInfo(path).isValid()) + const LibraryInfo &existingInfo = snapshot.libraryInfo(path); + if (existingInfo.isValid()) return true; if (newLibraries->contains(path)) return true; + // if we looked at the path before, done + if (existingInfo.wasScanned()) + return false; const QDir dir(path); QFile qmldirFile(dir.filePath(QLatin1String("qmldir"))); - if (!qmldirFile.exists()) + if (!qmldirFile.exists()) { + LibraryInfo libraryInfo(LibraryInfo::NotFound); + modelManager->updateLibraryInfo(path, libraryInfo); return false; + } #ifdef Q_OS_WIN // QTCREATORBUG-3402 - be case sensitive even here? @@ -380,8 +389,7 @@ static bool findNewQmlLibraryInPath(const QString &path, const QString libraryPath = QFileInfo(qmldirFile).absolutePath(); newLibraries->insert(libraryPath); - modelManager->updateLibraryInfo(libraryPath, - LibraryInfo(qmldirParser)); + modelManager->updateLibraryInfo(libraryPath, LibraryInfo(qmldirParser)); // scan the qml files in the library foreach (const QmlDirParser::Component &component, qmldirParser.components()) { @@ -398,30 +406,62 @@ static bool findNewQmlLibraryInPath(const QString &path, return true; } +static void findNewQmlLibrary( + const QString &path, + const LanguageUtils::ComponentVersion &version, + const Snapshot &snapshot, + ModelManager *modelManager, + QStringList *importedFiles, + QSet<QString> *scannedPaths, + QSet<QString> *newLibraries) +{ + QString libraryPath = QString("%1.%2.%3").arg( + path, + QString::number(version.majorVersion()), + QString::number(version.minorVersion())); + findNewQmlLibraryInPath( + libraryPath, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); + + libraryPath = QString("%1.%2").arg( + path, + QString::number(version.majorVersion())); + findNewQmlLibraryInPath( + libraryPath, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); + + findNewQmlLibraryInPath( + path, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); +} + static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot, ModelManager *modelManager, QStringList *importedFiles, QSet<QString> *scannedPaths, QSet<QString> *newLibraries) { - // scan library imports + // scan current dir + findNewQmlLibraryInPath(doc->path(), snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); + + // scan dir and lib imports const QStringList importPaths = modelManager->importPaths(); foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) { + if (import.type() == Interpreter::ImportInfo::DirectoryImport) { + const QString targetPath = import.name(); + findNewQmlLibraryInPath(targetPath, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); + } + if (import.type() == Interpreter::ImportInfo::LibraryImport) { + if (!import.version().isValid()) + continue; foreach (const QString &importPath, importPaths) { const QString targetPath = QDir(importPath).filePath(import.name()); - - if (findNewQmlLibraryInPath(targetPath, snapshot, modelManager, - importedFiles, scannedPaths, newLibraries)) - break; + findNewQmlLibrary(targetPath, import.version(), snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); } - } else if (import.type() == Interpreter::ImportInfo::DirectoryImport) { - const QString targetPath = import.name(); - findNewQmlLibraryInPath(targetPath, snapshot, modelManager, - importedFiles, scannedPaths, newLibraries); } } - - findNewQmlLibraryInPath(doc->path(), snapshot, modelManager, - importedFiles, scannedPaths, newLibraries); } static bool suffixMatches(const QString &fileName, const Core::MimeType &mimeType) @@ -451,8 +491,6 @@ void ModelManager::parse(QFutureInterface<void> &future, int progressRange = files.size(); future.setProgressRange(0, progressRange); - Snapshot snapshot = modelManager->_snapshot; - // paths we have scanned for files and added to the files list QSet<QString> scannedPaths; // libraries we've found while scanning imports @@ -499,6 +537,10 @@ void ModelManager::parse(QFutureInterface<void> &future, doc->setSource(contents); doc->parse(); + // update snapshot. requires synchronization, but significantly reduces amount of file + // system queries for library imports because queries are cached in libraryInfo + const Snapshot snapshot = modelManager->snapshot(); + // get list of referenced files not yet in snapshot or in directories already scanned QStringList importedFiles; findNewImplicitImports(doc, snapshot, &importedFiles, &scannedPaths);