forked from qt-creator/qt-creator
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: Ie1efc5be2ca2ed3ccc130e8a662f94aed11bec1a Reviewed-on: http://codereview.qt.nokia.com/194 Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
@@ -34,9 +34,12 @@
|
|||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
using namespace LanguageUtils;
|
using namespace LanguageUtils;
|
||||||
|
|
||||||
const int ComponentVersion::NoVersion = -1;
|
const int ComponentVersion::NoVersion = -1;
|
||||||
|
const int ComponentVersion::MaxVersion = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
ComponentVersion::ComponentVersion()
|
ComponentVersion::ComponentVersion()
|
||||||
: _major(NoVersion), _minor(NoVersion)
|
: _major(NoVersion), _minor(NoVersion)
|
||||||
|
@@ -44,6 +44,7 @@ class LANGUAGEUTILS_EXPORT ComponentVersion
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static const int NoVersion;
|
static const int NoVersion;
|
||||||
|
static const int MaxVersion;
|
||||||
|
|
||||||
ComponentVersion();
|
ComponentVersion();
|
||||||
ComponentVersion(int major, int minor);
|
ComponentVersion(int major, int minor);
|
||||||
|
@@ -363,14 +363,14 @@ void Document::extractPragmas(QString *source)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryInfo::LibraryInfo()
|
LibraryInfo::LibraryInfo(Status status)
|
||||||
: _valid(false)
|
: _status(status)
|
||||||
, _dumpStatus(NoTypeInfo)
|
, _dumpStatus(NoTypeInfo)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryInfo::LibraryInfo(const QmlDirParser &parser)
|
LibraryInfo::LibraryInfo(const QmlDirParser &parser)
|
||||||
: _valid(true)
|
: _status(Found)
|
||||||
, _components(parser.components())
|
, _components(parser.components())
|
||||||
, _plugins(parser.plugins())
|
, _plugins(parser.plugins())
|
||||||
, _dumpStatus(NoTypeInfo)
|
, _dumpStatus(NoTypeInfo)
|
||||||
|
@@ -132,8 +132,14 @@ public:
|
|||||||
TypeInfoFileError
|
TypeInfoFileError
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
NotScanned,
|
||||||
|
NotFound,
|
||||||
|
Found
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _valid;
|
Status _status;
|
||||||
QList<QmlDirParser::Component> _components;
|
QList<QmlDirParser::Component> _components;
|
||||||
QList<QmlDirParser::Plugin> _plugins;
|
QList<QmlDirParser::Plugin> _plugins;
|
||||||
typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList;
|
typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList;
|
||||||
@@ -143,8 +149,8 @@ private:
|
|||||||
QString _dumpError;
|
QString _dumpError;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LibraryInfo();
|
explicit LibraryInfo(Status status = NotScanned);
|
||||||
LibraryInfo(const QmlDirParser &parser);
|
explicit LibraryInfo(const QmlDirParser &parser);
|
||||||
~LibraryInfo();
|
~LibraryInfo();
|
||||||
|
|
||||||
QList<QmlDirParser::Component> components() const
|
QList<QmlDirParser::Component> components() const
|
||||||
@@ -160,7 +166,10 @@ public:
|
|||||||
{ _metaObjects = objects; }
|
{ _metaObjects = objects; }
|
||||||
|
|
||||||
bool isValid() const
|
bool isValid() const
|
||||||
{ return _valid; }
|
{ return _status == Found; }
|
||||||
|
|
||||||
|
bool wasScanned() const
|
||||||
|
{ return _status != NotScanned; }
|
||||||
|
|
||||||
PluginTypeInfoStatus pluginTypeInfoStatus() const
|
PluginTypeInfoStatus pluginTypeInfoStatus() const
|
||||||
{ return _dumpStatus; }
|
{ return _dumpStatus; }
|
||||||
|
@@ -42,8 +42,6 @@
|
|||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
using namespace LanguageUtils;
|
using namespace LanguageUtils;
|
||||||
using namespace QmlJS;
|
using namespace QmlJS;
|
||||||
using namespace QmlJS::Interpreter;
|
using namespace QmlJS::Interpreter;
|
||||||
@@ -278,18 +276,36 @@ Import Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo)
|
|||||||
|
|
||||||
bool importFound = false;
|
bool importFound = false;
|
||||||
|
|
||||||
// check the filesystem
|
|
||||||
const QString &packagePath = importInfo.name();
|
const QString &packagePath = importInfo.name();
|
||||||
|
// check the filesystem with full version
|
||||||
foreach (const QString &importPath, d->importPaths) {
|
foreach (const QString &importPath, d->importPaths) {
|
||||||
QString libraryPath = importPath;
|
QString libraryPath = QString("%1/%2.%3").arg(importPath, packagePath, version.toString());
|
||||||
libraryPath += QDir::separator();
|
|
||||||
libraryPath += packagePath;
|
|
||||||
|
|
||||||
if (importLibrary(doc, libraryPath, &import, importPath)) {
|
if (importLibrary(doc, libraryPath, &import, importPath)) {
|
||||||
importFound = true;
|
importFound = true;
|
||||||
break;
|
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, libraryPath, &import, 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, libraryPath, &import, importPath)) {
|
||||||
|
importFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if there are cpp-based types for this package, use them too
|
// if there are cpp-based types for this package, use them too
|
||||||
if (engine()->cppQmlTypes().hasPackage(packageName)) {
|
if (engine()->cppQmlTypes().hasPackage(packageName)) {
|
||||||
@@ -417,8 +433,7 @@ void Link::loadQmldirComponents(Interpreter::ObjectValue *import, ComponentVersi
|
|||||||
|
|
||||||
// if the version isn't valid, import the latest
|
// if the version isn't valid, import the latest
|
||||||
if (!version.isValid()) {
|
if (!version.isValid()) {
|
||||||
const int maxVersion = std::numeric_limits<int>::max();
|
version = ComponentVersion(ComponentVersion::MaxVersion, ComponentVersion::MaxVersion);
|
||||||
version = ComponentVersion(maxVersion, maxVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -287,6 +287,8 @@ void ModelManager::updateLibraryInfo(const QString &path, const LibraryInfo &inf
|
|||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
_snapshot.insertLibraryInfo(path, info);
|
_snapshot.insertLibraryInfo(path, info);
|
||||||
}
|
}
|
||||||
|
// only emit if we got new useful information
|
||||||
|
if (info.isValid())
|
||||||
emit libraryInfoUpdated(path, info);
|
emit libraryInfoUpdated(path, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,15 +360,22 @@ static bool findNewQmlLibraryInPath(const QString &path,
|
|||||||
QSet<QString> *newLibraries)
|
QSet<QString> *newLibraries)
|
||||||
{
|
{
|
||||||
// if we know there is a library, done
|
// if we know there is a library, done
|
||||||
if (snapshot.libraryInfo(path).isValid())
|
const LibraryInfo &existingInfo = snapshot.libraryInfo(path);
|
||||||
|
if (existingInfo.isValid())
|
||||||
return true;
|
return true;
|
||||||
if (newLibraries->contains(path))
|
if (newLibraries->contains(path))
|
||||||
return true;
|
return true;
|
||||||
|
// if we looked at the path before, done
|
||||||
|
if (existingInfo.wasScanned())
|
||||||
|
return false;
|
||||||
|
|
||||||
const QDir dir(path);
|
const QDir dir(path);
|
||||||
QFile qmldirFile(dir.filePath(QLatin1String("qmldir")));
|
QFile qmldirFile(dir.filePath(QLatin1String("qmldir")));
|
||||||
if (!qmldirFile.exists())
|
if (!qmldirFile.exists()) {
|
||||||
|
LibraryInfo libraryInfo(LibraryInfo::NotFound);
|
||||||
|
modelManager->updateLibraryInfo(path, libraryInfo);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// QTCREATORBUG-3402 - be case sensitive even here?
|
// QTCREATORBUG-3402 - be case sensitive even here?
|
||||||
@@ -382,8 +391,7 @@ static bool findNewQmlLibraryInPath(const QString &path,
|
|||||||
|
|
||||||
const QString libraryPath = QFileInfo(qmldirFile).absolutePath();
|
const QString libraryPath = QFileInfo(qmldirFile).absolutePath();
|
||||||
newLibraries->insert(libraryPath);
|
newLibraries->insert(libraryPath);
|
||||||
modelManager->updateLibraryInfo(libraryPath,
|
modelManager->updateLibraryInfo(libraryPath, LibraryInfo(qmldirParser));
|
||||||
LibraryInfo(qmldirParser));
|
|
||||||
|
|
||||||
// scan the qml files in the library
|
// scan the qml files in the library
|
||||||
foreach (const QmlDirParser::Component &component, qmldirParser.components()) {
|
foreach (const QmlDirParser::Component &component, qmldirParser.components()) {
|
||||||
@@ -400,30 +408,62 @@ static bool findNewQmlLibraryInPath(const QString &path,
|
|||||||
return true;
|
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,
|
static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot,
|
||||||
ModelManager *modelManager,
|
ModelManager *modelManager,
|
||||||
QStringList *importedFiles, QSet<QString> *scannedPaths, QSet<QString> *newLibraries)
|
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();
|
const QStringList importPaths = modelManager->importPaths();
|
||||||
foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) {
|
foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) {
|
||||||
if (import.type() == Interpreter::ImportInfo::LibraryImport) {
|
if (import.type() == Interpreter::ImportInfo::DirectoryImport) {
|
||||||
foreach (const QString &importPath, importPaths) {
|
|
||||||
const QString targetPath = QDir(importPath).filePath(import.name());
|
|
||||||
|
|
||||||
if (findNewQmlLibraryInPath(targetPath, snapshot, modelManager,
|
|
||||||
importedFiles, scannedPaths, newLibraries))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (import.type() == Interpreter::ImportInfo::DirectoryImport) {
|
|
||||||
const QString targetPath = import.name();
|
const QString targetPath = import.name();
|
||||||
findNewQmlLibraryInPath(targetPath, snapshot, modelManager,
|
findNewQmlLibraryInPath(targetPath, snapshot, modelManager,
|
||||||
importedFiles, scannedPaths, newLibraries);
|
importedFiles, scannedPaths, newLibraries);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
findNewQmlLibraryInPath(doc->path(), snapshot, modelManager,
|
if (import.type() == Interpreter::ImportInfo::LibraryImport) {
|
||||||
|
if (!import.version().isValid())
|
||||||
|
continue;
|
||||||
|
foreach (const QString &importPath, importPaths) {
|
||||||
|
const QString targetPath = QDir(importPath).filePath(import.name());
|
||||||
|
findNewQmlLibrary(targetPath, import.version(), snapshot, modelManager,
|
||||||
importedFiles, scannedPaths, newLibraries);
|
importedFiles, scannedPaths, newLibraries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool suffixMatches(const QString &fileName, const Core::MimeType &mimeType)
|
static bool suffixMatches(const QString &fileName, const Core::MimeType &mimeType)
|
||||||
@@ -453,8 +493,6 @@ void ModelManager::parse(QFutureInterface<void> &future,
|
|||||||
int progressRange = files.size();
|
int progressRange = files.size();
|
||||||
future.setProgressRange(0, progressRange);
|
future.setProgressRange(0, progressRange);
|
||||||
|
|
||||||
Snapshot snapshot = modelManager->_snapshot;
|
|
||||||
|
|
||||||
// paths we have scanned for files and added to the files list
|
// paths we have scanned for files and added to the files list
|
||||||
QSet<QString> scannedPaths;
|
QSet<QString> scannedPaths;
|
||||||
// libraries we've found while scanning imports
|
// libraries we've found while scanning imports
|
||||||
@@ -501,6 +539,10 @@ void ModelManager::parse(QFutureInterface<void> &future,
|
|||||||
doc->setSource(contents);
|
doc->setSource(contents);
|
||||||
doc->parse();
|
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
|
// get list of referenced files not yet in snapshot or in directories already scanned
|
||||||
QStringList importedFiles;
|
QStringList importedFiles;
|
||||||
findNewImplicitImports(doc, snapshot, &importedFiles, &scannedPaths);
|
findNewImplicitImports(doc, snapshot, &importedFiles, &scannedPaths);
|
||||||
|
Reference in New Issue
Block a user