QmlJS: Fix handling multiple import paths into same module

It is possible to import components of different paths to fill
a module.
Take further paths into account when looking up types.

Fixes: QTCREATORBUG-24405
Change-Id: I8d6bf0a324ea9c0d1fe9d91b40857f91f00dd662
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@qt.io>
This commit is contained in:
Christian Stenger
2021-01-11 14:09:51 +01:00
parent 7dc72c533e
commit 6ea088c02f
5 changed files with 30 additions and 18 deletions

View File

@@ -410,8 +410,13 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im
const QString packageName = importInfo.name();
const ComponentVersion version = importInfo.version();
QString libraryPath = modulePath(packageName, version.toString(), m_importPaths);
bool importFound = !libraryPath.isEmpty() && importLibrary(doc, libraryPath, &import, import.object);
QStringList libraryPaths = modulePaths(packageName, version.toString(), m_importPaths);
bool importFound = false;
for (const QString &libPath : libraryPaths) {
importFound = !libPath.isEmpty() && importLibrary(doc, libPath, &import, import.object);
if (importFound)
break;
}
if (!importFound) {
for (const QString &dir : qAsConst(m_applicationDirectories)) {
@@ -501,7 +506,10 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
Import subImport;
subImport.valid = true;
subImport.info = ImportInfo::moduleImport(importName, vNow, importInfo.as(), importInfo.ast());
subImport.libraryPath = modulePath(importName, vNow.toString(), m_importPaths);
const QStringList libraryPaths = modulePaths(importName, vNow.toString(), m_importPaths);
subImport.libraryPath = libraryPaths.value(0); // first is the best match
bool subImportFound = importLibrary(doc, subImport.libraryPath, &subImport, targetObject, importPath, true);
if (!subImportFound && errorLoc.isValid()) {

View File

@@ -869,7 +869,9 @@ static QString modulePath(const ImportInfo &import, const QStringList &paths)
{
if (!import.version().isValid())
return QString();
return modulePath(import.name(), import.version().toString(), paths);
const QStringList modPaths = modulePaths(import.name(), import.version().toString(), paths);
return modPaths.value(0); // first is best match
}
static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot,

View File

@@ -421,16 +421,17 @@ QString PluginDumper::buildQmltypesPath(const QString &name) const
version = m.captured("major") + QLatin1Char('.') + m.captured("minor");
}
const QString path = modulePath(qualifiedName, version, m_modelManager->importPathsNames());
const QStringList paths = modulePaths(qualifiedName, version, m_modelManager->importPathsNames());
if (path.isEmpty())
if (paths.isEmpty())
return QString();
QDirIterator it(path, QStringList { "*.qmltypes" }, QDir::Files);
if (it.hasNext())
return it.next();
for (const QString &path : paths) {
QDirIterator it(path, QStringList { "*.qmltypes" }, QDir::Files);
if (it.hasNext())
return it.next();
}
return QString();
}

View File

@@ -233,12 +233,12 @@ bool QmlJS::maybeModuleVersion(const QString &version) {
* \return The module paths if found, an empty string otherwise
* \see qmlimportscanner in qtdeclarative/tools
*/
QString QmlJS::modulePath(const QString &name, const QString &version,
const QStringList &importPaths)
QStringList QmlJS::modulePaths(const QString &name, const QString &version,
const QStringList &importPaths)
{
Q_ASSERT(maybeModuleVersion(version));
if (importPaths.isEmpty())
return QString();
return {};
const QString sanitizedVersion = version == undefinedVersion ? QString() : version;
const QStringList parts = name.split('.', Qt::SkipEmptyParts);
@@ -249,6 +249,7 @@ QString QmlJS::modulePath(const QString &name, const QString &version,
// sanitized version.
const QRegularExpression re("\\.?\\d+$");
QStringList result;
QString candidate;
for (QString ver = sanitizedVersion; !ver.isEmpty(); ver.remove(re)) {
@@ -260,7 +261,7 @@ QString QmlJS::modulePath(const QString &name, const QString &version,
ver,
mkpath(parts.mid(i + 1))));
if (QDir(candidate).exists())
return candidate;
result << candidate;
}
}
}
@@ -269,10 +270,10 @@ QString QmlJS::modulePath(const QString &name, const QString &version,
for (const QString &path: importPaths) {
candidate = QDir::cleanPath(QString::fromLatin1("%1/%2").arg(path, mkpath(parts)));
if (QDir(candidate).exists())
return candidate;
result << candidate;
}
return QString();
return result;
}
bool QmlJS::isValidBuiltinPropertyType(const QString &name)

View File

@@ -57,8 +57,8 @@ QMLJS_EXPORT DiagnosticMessage errorMessage(const SourceLocation &loc,
QMLJS_EXPORT bool maybeModuleVersion(const QString &version);
QMLJS_EXPORT QString modulePath(const QString &moduleImportName, const QString &version,
const QStringList &importPaths);
QMLJS_EXPORT QStringList modulePaths(const QString &moduleImportName, const QString &version,
const QStringList &importPaths);
template <class T>
SourceLocation locationFromRange(const T *node)