Commit c054dd2c authored by Marco Benelli's avatar Marco Benelli

QmlJs: fix bug in resolving qml imports

The introduction of Controls.2 changed the way in which imports are
resolved. This patch fix some leftovers of the old resolution scheme.
Such leftovers caused false positives in import declaration to happen
when resetting the QML/JS code model.
The code has also been simplified a little, by the removal of
duplicate code and of unused methods.

Change-Id: I90bdf7ed47fdfea7cbd8259acd7a9a968f27301b
Reviewed-by: Tim Jenssen's avatarTim Jenssen <>
parent 79bdd7e1
......@@ -32,6 +32,7 @@
#include "qmljstypedescriptionreader.h"
#include "qmljsdialect.h"
#include "qmljsviewercontext.h"
#include "qmljsutils.h"
#include <cplusplus/cppmodelmanagerbase.h>
#include <utils/algorithm.h>
......@@ -811,33 +812,11 @@ static bool findNewQmlLibraryInPath(const QString &path,
return true;
static void findNewQmlLibrary(
const QString &path,
const LanguageUtils::ComponentVersion &version,
const Snapshot &snapshot,
ModelManagerInterface *modelManager,
QStringList *importedFiles,
QSet<QString> *scannedPaths,
QSet<QString> *newLibraries)
static QString modulePath(const ImportInfo &import, const QStringList &paths)
QString libraryPath = QString::fromLatin1("%1.%2.%3").arg(
libraryPath, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries, false);
libraryPath = QString::fromLatin1("%1.%2").arg(
libraryPath, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries, false);
path, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries, false);
if (!import.version().isValid())
return QString();
return modulePath(, import.version().toString(), paths);
static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot,
......@@ -849,7 +828,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
importedFiles, scannedPaths, newLibraries, false);
// scan dir and lib imports
const PathsAndLanguages importPaths = modelManager->importPaths();
const QStringList importPaths = modelManager->importPathsNames();
foreach (const ImportInfo &import, doc->bind()->imports()) {
if (import.type() == ImportType::Directory) {
const QString targetPath = import.path();
......@@ -858,13 +837,11 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
if (import.type() == ImportType::Library) {
if (!import.version().isValid())
const QString libraryPath = modulePath(import, importPaths);
if (libraryPath.isEmpty())
foreach (const PathAndLanguage &importPath, importPaths) {
const QString targetPath = importPath.path().appendPath(import.path()).toString();
findNewQmlLibrary(targetPath, import.version(), snapshot, modelManager,
importedFiles, scannedPaths, newLibraries);
findNewQmlLibraryInPath(libraryPath, snapshot, modelManager, importedFiles,
scannedPaths, newLibraries, false);
......@@ -1071,10 +1048,14 @@ void ModelManagerInterface::importScan(QFutureInterface<void> &future,
PathsAndLanguages ModelManagerInterface::importPaths() const
QStringList ModelManagerInterface::importPathsNames() const
QStringList names;
QMutexLocker l(&m_mutex);
return m_allImportPaths;
for (const PathAndLanguage &x: m_allImportPaths)
names << x.path().toString();
return names;
QmlLanguageBundles ModelManagerInterface::activeBundles() const
......@@ -178,7 +178,7 @@ public:
QList<ProjectInfo> allProjectInfosForPath(const QString &path) const;
bool isIdle() const ;
PathsAndLanguages importPaths() const;
QStringList importPathsNames() const;
QmlJS::QmlLanguageBundles activeBundles() const;
QmlJS::QmlLanguageBundles extendedBundles() const;
......@@ -25,6 +25,7 @@
#include "qmljsplugindumper.h"
#include "qmljsmodelmanagerinterface.h"
#include "qmljsutils.h"
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljsviewercontext.h>
......@@ -401,48 +402,35 @@ void PluginDumper::loadQmlTypeDescription(const QStringList &paths,
* \brief Build the path of an existing qmltypes file from a module name.
* \param name
* \return the module's qmltypes file path
* \return the module's qmltypes file path or an empty string if not found
* Look for \a name qmltypes file in model manager's import paths.
* For each import path the following files are searched, in this order:
* - <name>.<major>.<minor>/plugins.qmltypes
* - <name>.<major>/plugins.qmltypes
* - <name>/plugins.qmltypes
* That means that a more qualified directory name has precedence over a
* less qualified one. Be aware that the import paths order has a stronger
* precedence, so a less qualified name could shadow a more qualified one if
* it resides in a different import path.
* \sa QmlJs::modulePath
* \sa LinkPrivate::importNonFile
QString PluginDumper::buildQmltypesPath(const QString &name) const
QString qualifiedName;
QString majorVersion;
QString minorVersion;
QString version;
QRegularExpression import("^(?<name>[\\w|\\.]+)\\s+(?<major>\\d+)\\.(?<minor>\\d+)$");
QRegularExpressionMatch m = import.match(name);
if (m.hasMatch()) {
qualifiedName = m.captured("name");
majorVersion = m.captured("major");
minorVersion = m.captured("minor");
version = m.captured("major") + QLatin1Char('.') + m.captured("minor");
for (const PathAndLanguage &p: m_modelManager->importPaths()) {
QString moduleName = qualifiedName.replace(QLatin1Char('.'), QLatin1Char('/'));
QString moduleNameMajor = moduleName + QLatin1Char('.') + majorVersion;
QString moduleNameMajorMinor = moduleNameMajor + QLatin1Char('.') + minorVersion;
const QString path = modulePath(qualifiedName, version, m_modelManager->importPathsNames());
if (path.isEmpty())
return QString();
const QString filename = path + QLatin1String("/plugins.qmltypes");
if (QFile::exists(filename))
return filename;
for (const auto n: QStringList{moduleNameMajorMinor, moduleNameMajor, moduleName}) {
QString filename(p.path().toString() + QLatin1Char('/') + n
+ QLatin1String("/plugins.qmltypes"));
if (QFile::exists(filename))
return filename;
return QString();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment