Commit 8b95ca89 authored by Christian Kamm's avatar Christian Kamm Committed by hjk

QmlJS: Allow for QML modules with version subdirectories.

That means
import Foo 2.1
can resolve to
/path/Foo.2.1 or
/path/Foo.2 or
/path/Foo

Task-number: QTCREATORBUG-4607
Change-Id: Ie1efc5be2ca2ed3ccc130e8a662f94aed11bec1ax
Reviewed-on: http://codereview.qt.nokia.com/194Reviewed-by: default avatarRoberto Raggi <roberto.raggi@nokia.com>
(cherry picked from commit 87420263)
Reviewed-on: http://codereview.qt.nokia.com/380Reviewed-by: default avatarQt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: default avatarhjk <qthjk@ovi.com>
parent 7b9ef792
......@@ -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)
......
......@@ -44,6 +44,7 @@ class LANGUAGEUTILS_EXPORT ComponentVersion
public:
static const int NoVersion;
static const int MaxVersion;
ComponentVersion();
ComponentVersion(int major, int minor);
......
......@@ -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)
......
......@@ -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; }
......
......@@ -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);
}
......
......@@ -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);
......
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