Commit 2fc150b9 authored by Fawzi Mohamed's avatar Fawzi Mohamed
Browse files

qmljs: scan imports



Change-Id: Ied59f5d56c5816d9da57f23a619d604acec76000
Reviewed-by: default avatarThomas Hartmann <Thomas.Hartmann@digia.com>
parent 7fb87fbb
...@@ -212,7 +212,7 @@ void Document::setLanguage(Language::Enum l) ...@@ -212,7 +212,7 @@ void Document::setLanguage(Language::Enum l)
QString Document::importId() const QString Document::importId() const
{ {
return path(); return _fileName;
} }
QByteArray Document::fingerprint() const QByteArray Document::fingerprint() const
...@@ -501,7 +501,7 @@ void Snapshot::insert(const Document::Ptr &document, bool allowInvalid) ...@@ -501,7 +501,7 @@ void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
CoreImport cImport; CoreImport cImport;
cImport.importId = document->importId(); cImport.importId = document->importId();
cImport.language = document->language(); cImport.language = document->language();
cImport.possibleExports << Export(ImportKey(ImportType::File, document->path()), cImport.possibleExports << Export(ImportKey(ImportType::File, fileName),
QString(), true); QString(), true);
cImport.fingerprint = document->fingerprint(); cImport.fingerprint = document->fingerprint();
_dependencies.addCoreImport(cImport); _dependencies.addCoreImport(cImport);
...@@ -512,13 +512,34 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info) ...@@ -512,13 +512,34 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info)
{ {
QTC_CHECK(info.fingerprint() == info.calculateFingerprint()); QTC_CHECK(info.fingerprint() == info.calculateFingerprint());
_libraries.insert(QDir::cleanPath(path), info); _libraries.insert(QDir::cleanPath(path), info);
if (!info.wasFound()) return;
CoreImport cImport; CoreImport cImport;
cImport.importId = path; cImport.importId = path;
cImport.language = Language::Unknown; cImport.language = Language::Unknown;
QSet<ImportKey> packages;
foreach (const ModuleApiInfo &moduleInfo, info.moduleApis()) { foreach (const ModuleApiInfo &moduleInfo, info.moduleApis()) {
ImportKey iKey(ImportType::Library, moduleInfo.uri, moduleInfo.version.majorVersion(), ImportKey iKey(ImportType::Library, moduleInfo.uri, moduleInfo.version.majorVersion(),
moduleInfo.version.minorVersion()); moduleInfo.version.minorVersion());
cImport.possibleExports << Export(iKey, path, true); packages.insert(iKey);
}
foreach (const LanguageUtils::FakeMetaObject::ConstPtr &metaO, info.metaObjects()) {
foreach (const LanguageUtils::FakeMetaObject::Export &e, metaO->exports()) {
ImportKey iKey(ImportType::Library, e.package, e.version.majorVersion(),
e.version.minorVersion());
packages.insert(iKey);
}
}
QStringList splitPath = path.split(QLatin1Char('/'));
foreach (const ImportKey &importKey, packages) {
QString requiredPath = QStringList(splitPath.mid(0, splitPath.size() - importKey.splitPath.size()))
.join(QLatin1Char('/'));
cImport.possibleExports << Export(importKey, requiredPath, true);
}
foreach (const QmlDirParser::Component &component, info.components()) {
foreach (const Export &e, cImport.possibleExports)
// renaming of type name not really represented here... fix?
_dependencies.addExport(component.fileName, e.exportName, e.pathRequired);
} }
cImport.fingerprint = info.fingerprint(); cImport.fingerprint = info.fingerprint();
_dependencies.addCoreImport(cImport); _dependencies.addCoreImport(cImport);
......
...@@ -201,6 +201,9 @@ public: ...@@ -201,6 +201,9 @@ public:
bool wasScanned() const bool wasScanned() const
{ return _status != NotScanned; } { return _status != NotScanned; }
bool wasFound() const
{ return _status != NotFound; }
PluginTypeInfoStatus pluginTypeInfoStatus() const PluginTypeInfoStatus pluginTypeInfoStatus() const
{ return _dumpStatus; } { return _dumpStatus; }
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
namespace QmlJS { namespace QmlJS {
static bool debugImportDependencies = false;
ImportKind::Enum toImportKind(ImportType::Enum type) ImportKind::Enum toImportKind(ImportType::Enum type)
{ {
switch (type) { switch (type) {
...@@ -408,6 +410,40 @@ ImportKey::DirCompareInfo ImportKey::compareDir(const ImportKey &superDir) const ...@@ -408,6 +410,40 @@ ImportKey::DirCompareInfo ImportKey::compareDir(const ImportKey &superDir) const
return SameDir; return SameDir;
} }
QString ImportKey::toString() const
{
QString res;
switch (type) {
case ImportType::UnknownFile:
case ImportType::File:
res = path();
break;
case ImportType::Directory:
case ImportType::ImplicitDirectory:
res = path() + QLatin1Char('/');
break;
case ImportType::QrcDirectory:
res = QLatin1String("qrc:") + path() + QLatin1Char('/');
break;
case ImportType::QrcFile:
res = QLatin1String("qrc:") + path() + QLatin1Char('/');
break;
case ImportType::Invalid:
res = path();
break;
case ImportType::Library:
res = splitPath.join(QLatin1Char('.'));
break;
}
if (majorVersion != LanguageUtils::ComponentVersion::NoVersion
|| minorVersion != LanguageUtils::ComponentVersion::NoVersion)
return res + QLatin1Char(' ') + QString::number(majorVersion)
+ QLatin1Char('.') + QString::number(minorVersion);
return res;
}
uint qHash(const ImportKey &info) uint qHash(const ImportKey &info)
{ {
uint res = ::qHash(info.type) ^ uint res = ::qHash(info.type) ^
...@@ -688,6 +724,12 @@ void ImportDependencies::addCoreImport(const CoreImport &import) ...@@ -688,6 +724,12 @@ void ImportDependencies::addCoreImport(const CoreImport &import)
newImport.possibleExports.append(e); newImport.possibleExports.append(e);
} }
m_coreImports.insert(newImport.importId, newImport); m_coreImports.insert(newImport.importId, newImport);
if (debugImportDependencies) {
QDebug dbg(qDebug());
dbg << "added import "<< newImport.importId << " for";
foreach (const Export &e, newImport.possibleExports)
dbg << " " << e.exportName.toString() << "(" << e.pathRequired << ")";
}
} }
void ImportDependencies::removeCoreImport(const QString &importId) void ImportDependencies::removeCoreImport(const QString &importId)
...@@ -705,6 +747,8 @@ void ImportDependencies::removeCoreImport(const QString &importId) ...@@ -705,6 +747,8 @@ void ImportDependencies::removeCoreImport(const QString &importId)
cImport.possibleExports = newExports; cImport.possibleExports = newExports;
else else
m_coreImports.remove(importId); m_coreImports.remove(importId);
if (debugImportDependencies)
qDebug() << "removed import with id:"<< importId;
} }
void ImportDependencies::addExport(const QString &importId, const ImportKey &importKey, void ImportDependencies::addExport(const QString &importId, const ImportKey &importKey,
...@@ -719,6 +763,9 @@ void ImportDependencies::addExport(const QString &importId, const ImportKey &imp ...@@ -719,6 +763,9 @@ void ImportDependencies::addExport(const QString &importId, const ImportKey &imp
} }
CoreImport &importValue = m_coreImports[importId]; CoreImport &importValue = m_coreImports[importId];
importValue.possibleExports.append(Export(importKey, requiredPath, false)); importValue.possibleExports.append(Export(importKey, requiredPath, false));
if (debugImportDependencies)
qDebug() << "added export "<< importKey.toString() << " for id " <<importId
<< " (" << requiredPath << ")";
} }
void ImportDependencies::removeExport(const QString &importId, const ImportKey &importKey, void ImportDependencies::removeExport(const QString &importId, const ImportKey &importKey,
...@@ -726,28 +773,31 @@ void ImportDependencies::removeExport(const QString &importId, const ImportKey & ...@@ -726,28 +773,31 @@ void ImportDependencies::removeExport(const QString &importId, const ImportKey &
{ {
if (!m_coreImports.contains(importId)) { if (!m_coreImports.contains(importId)) {
qDebug() << "non existing core import for removeExport(" << importId << ", " qDebug() << "non existing core import for removeExport(" << importId << ", "
<< importKey.path() << ")"; << importKey.toString() << ")";
} else { } else {
CoreImport &importValue = m_coreImports[importId]; CoreImport &importValue = m_coreImports[importId];
if (!importValue.possibleExports.removeOne(Export(importKey, requiredPath, false))) { if (!importValue.possibleExports.removeOne(Export(importKey, requiredPath, false))) {
qDebug() << "non existing export for removeExport(" << importId << ", " qDebug() << "non existing export for removeExport(" << importId << ", "
<< importKey.path() << ")"; << importKey.toString() << ")";
} }
if (importValue.possibleExports.isEmpty() && importValue.fingerprint.isEmpty()) if (importValue.possibleExports.isEmpty() && importValue.fingerprint.isEmpty())
m_coreImports.remove(importId); m_coreImports.remove(importId);
} }
if (!m_importCache.contains(importKey)) { if (!m_importCache.contains(importKey)) {
qDebug() << "missing possibleExport for " << importKey.path() << " when removing export of " qDebug() << "missing possibleExport for " << importKey.toString() << " when removing export of "
<< importId; << importId;
} else { } else {
QStringList &cImp = m_importCache[importKey]; QStringList &cImp = m_importCache[importKey];
if (!cImp.removeOne(importId)) { if (!cImp.removeOne(importId)) {
qDebug() << "missing possibleExport backpointer for " << importKey.path() << " to " qDebug() << "missing possibleExport backpointer for " << importKey.toString() << " to "
<< importId; << importId;
} }
if (cImp.isEmpty()) if (cImp.isEmpty())
m_importCache.remove(importKey); m_importCache.remove(importKey);
} }
if (debugImportDependencies)
qDebug() << "removed export "<< importKey.toString() << " for id " << importId
<< " (" << requiredPath << ")";
} }
void ImportDependencies::iterateOnCoreImports( void ImportDependencies::iterateOnCoreImports(
...@@ -774,6 +824,8 @@ void ImportDependencies::iterateOnLibraryImports( ...@@ -774,6 +824,8 @@ void ImportDependencies::iterateOnLibraryImports(
iter_t i = m_importCache.lowerBound(firstLib); iter_t i = m_importCache.lowerBound(firstLib);
iter_t end = m_importCache.constEnd(); iter_t end = m_importCache.constEnd();
while (i != end && i.key().type == ImportType::Library) { while (i != end && i.key().type == ImportType::Library) {
if (debugImportDependencies)
qDebug() << "libloop:" << i.key().toString() << i.value();
foreach (const QString &cImportName, i.value()) { foreach (const QString &cImportName, i.value()) {
CoreImport cImport = coreImport(cImportName); CoreImport cImport = coreImport(cImportName);
if (vContext.languageIsCompatible(cImport.language)) { if (vContext.languageIsCompatible(cImport.language)) {
...@@ -781,6 +833,9 @@ void ImportDependencies::iterateOnLibraryImports( ...@@ -781,6 +833,9 @@ void ImportDependencies::iterateOnLibraryImports(
if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) { if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) {
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext); ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
if (m.hasMatch()) { if (m.hasMatch()) {
if (debugImportDependencies)
qDebug() << "import iterate:" << e.exportName.toString()
<< " (" << e.pathRequired << "), id:" << cImport.importId;
if (!iterF(m, e, cImport)) if (!iterF(m, e, cImport))
return; return;
} }
......
...@@ -118,6 +118,7 @@ public: ...@@ -118,6 +118,7 @@ public:
int compare(const ImportKey &other) const; int compare(const ImportKey &other) const;
bool isDirectoryLike() const; bool isDirectoryLike() const;
DirCompareInfo compareDir(const ImportKey &other) const; DirCompareInfo compareDir(const ImportKey &other) const;
QString toString() const;
}; };
uint qHash(const ImportKey &info); uint qHash(const ImportKey &info);
......
...@@ -64,6 +64,7 @@ public: ...@@ -64,6 +64,7 @@ public:
attachPID(-1), attachPID(-1),
useTerminal(false), useTerminal(false),
breakOnMain(false), breakOnMain(false),
continueAfterAttach(false),
multiProcess(false), multiProcess(false),
languages(AnyLanguage), languages(AnyLanguage),
qmlServerAddress(QLatin1String("127.0.0.1")), qmlServerAddress(QLatin1String("127.0.0.1")),
...@@ -102,6 +103,7 @@ public: ...@@ -102,6 +103,7 @@ public:
qint64 attachPID; qint64 attachPID;
bool useTerminal; bool useTerminal;
bool breakOnMain; bool breakOnMain;
bool continueAfterAttach;
bool multiProcess; bool multiProcess;
DebuggerLanguages languages; DebuggerLanguages languages;
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <qtsupport/qmldumptool.h> #include <qtsupport/qmldumptool.h>
#include <qtsupport/qtsupportconstants.h> #include <qtsupport/qtsupportconstants.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/function.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <QDir> #include <QDir>
...@@ -360,7 +361,7 @@ QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles, ...@@ -360,7 +361,7 @@ QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles,
QFuture<void> result = QtConcurrent::run(&ModelManager::parse, QFuture<void> result = QtConcurrent::run(&ModelManager::parse,
workingCopy(), sourceFiles, workingCopy(), sourceFiles,
this, this, Language::Qml,
emitDocumentOnDiskChanged); emitDocumentOnDiskChanged);
if (m_synchronizer.futures().size() > 10) { if (m_synchronizer.futures().size() > 10) {
...@@ -386,7 +387,7 @@ void ModelManager::fileChangedOnDisk(const QString &path) ...@@ -386,7 +387,7 @@ void ModelManager::fileChangedOnDisk(const QString &path)
{ {
QtConcurrent::run(&ModelManager::parse, QtConcurrent::run(&ModelManager::parse,
workingCopy(), QStringList() << path, workingCopy(), QStringList() << path,
this, true); this, Language::Unknown, true);
} }
void ModelManager::removeFiles(const QStringList &files) void ModelManager::removeFiles(const QStringList &files)
...@@ -700,7 +701,8 @@ static bool findNewQmlLibraryInPath(const QString &path, ...@@ -700,7 +701,8 @@ static bool findNewQmlLibraryInPath(const QString &path,
ModelManager *modelManager, ModelManager *modelManager,
QStringList *importedFiles, QStringList *importedFiles,
QSet<QString> *scannedPaths, QSet<QString> *scannedPaths,
QSet<QString> *newLibraries) QSet<QString> *newLibraries,
bool ignoreMissing)
{ {
// if we know there is a library, done // if we know there is a library, done
const LibraryInfo &existingInfo = snapshot.libraryInfo(path); const LibraryInfo &existingInfo = snapshot.libraryInfo(path);
...@@ -715,8 +717,10 @@ static bool findNewQmlLibraryInPath(const QString &path, ...@@ -715,8 +717,10 @@ static bool findNewQmlLibraryInPath(const QString &path,
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); if (!ignoreMissing) {
modelManager->updateLibraryInfo(path, libraryInfo); LibraryInfo libraryInfo(LibraryInfo::NotFound);
modelManager->updateLibraryInfo(path, libraryInfo);
}
return false; return false;
} }
...@@ -765,18 +769,18 @@ static void findNewQmlLibrary( ...@@ -765,18 +769,18 @@ static void findNewQmlLibrary(
QString::number(version.minorVersion())); QString::number(version.minorVersion()));
findNewQmlLibraryInPath( findNewQmlLibraryInPath(
libraryPath, snapshot, modelManager, libraryPath, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries); importedFiles, scannedPaths, newLibraries, false);
libraryPath = QString::fromLatin1("%1.%2").arg( libraryPath = QString::fromLatin1("%1.%2").arg(
path, path,
QString::number(version.majorVersion())); QString::number(version.majorVersion()));
findNewQmlLibraryInPath( findNewQmlLibraryInPath(
libraryPath, snapshot, modelManager, libraryPath, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries); importedFiles, scannedPaths, newLibraries, false);
findNewQmlLibraryInPath( findNewQmlLibraryInPath(
path, snapshot, modelManager, path, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries); importedFiles, scannedPaths, newLibraries, false);
} }
static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot, static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot,
...@@ -785,7 +789,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap ...@@ -785,7 +789,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
{ {
// scan current dir // scan current dir
findNewQmlLibraryInPath(doc->path(), snapshot, modelManager, findNewQmlLibraryInPath(doc->path(), snapshot, modelManager,
importedFiles, scannedPaths, newLibraries); importedFiles, scannedPaths, newLibraries, false);
// scan dir and lib imports // scan dir and lib imports
const QStringList importPaths = modelManager->importPaths(); const QStringList importPaths = modelManager->importPaths();
...@@ -793,7 +797,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap ...@@ -793,7 +797,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
if (import.type() == ImportType::Directory) { if (import.type() == ImportType::Directory) {
const QString targetPath = import.path(); const QString targetPath = import.path();
findNewQmlLibraryInPath(targetPath, snapshot, modelManager, findNewQmlLibraryInPath(targetPath, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries); importedFiles, scannedPaths, newLibraries, false);
} }
if (import.type() == ImportType::Library) { if (import.type() == ImportType::Library) {
...@@ -808,24 +812,18 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap ...@@ -808,24 +812,18 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
} }
} }
void ModelManager::parse(QFutureInterface<void> &future, void ModelManager::parseLoop(QSet<QString> &scannedPaths,
WorkingCopy workingCopy, QSet<QString> &newLibraries,
QStringList files, WorkingCopy workingCopy,
ModelManager *modelManager, QStringList files,
bool emitDocChangedOnDisk) ModelManager *modelManager,
Language::Enum mainLanguage,
bool emitDocChangedOnDisk,
Utils::function<bool(qreal)> reportProgress)
{ {
int progressRange = files.size();
future.setProgressRange(0, progressRange);
// paths we have scanned for files and added to the files list
QSet<QString> scannedPaths;
// libraries we've found while scanning imports
QSet<QString> newLibraries;
for (int i = 0; i < files.size(); ++i) { for (int i = 0; i < files.size(); ++i) {
if (future.isCanceled()) if (!reportProgress(qreal(i) / files.size()))
break; return;
future.setProgressValue(qreal(i) / files.size() * progressRange);
const QString fileName = files.at(i); const QString fileName = files.at(i);
...@@ -835,7 +833,9 @@ void ModelManager::parse(QFutureInterface<void> &future, ...@@ -835,7 +833,9 @@ void ModelManager::parse(QFutureInterface<void> &future,
modelManager->updateQrcFile(fileName); modelManager->updateQrcFile(fileName);
continue; continue;
} }
if (language == Language::Qml
&& (mainLanguage == Language::QmlQtQuick1 || Language::QmlQtQuick2))
language = mainLanguage;
QString contents; QString contents;
int documentRevision = 0; int documentRevision = 0;
...@@ -878,7 +878,116 @@ void ModelManager::parse(QFutureInterface<void> &future, ...@@ -878,7 +878,116 @@ void ModelManager::parse(QFutureInterface<void> &future,
if (emitDocChangedOnDisk) if (emitDocChangedOnDisk)
modelManager->emitDocumentChangedOnDisk(doc); modelManager->emitDocumentChangedOnDisk(doc);
} }
}
class FutureReporter
{
public:
FutureReporter(QFutureInterface<void> &future, int multiplier = 100, int base = 0)
:future(future), multiplier(multiplier), base(base)
{ }
bool operator()(qreal val)
{
if (future.isCanceled())
return false;
future.setProgressValue(int(base + multiplier * val));
return true;
}
private:
QFutureInterface<void> &future;
int multiplier;
int base;
};
void ModelManager::parse(QFutureInterface<void> &future,
WorkingCopy workingCopy,
QStringList files,
ModelManager *modelManager,
Language::Enum mainLanguage,
bool emitDocChangedOnDisk)
{
FutureReporter reporter(future);
future.setProgressRange(0, 100);
// paths we have scanned for files and added to the files list
QSet<QString> scannedPaths;
// libraries we've found while scanning imports
QSet<QString> newLibraries;
parseLoop(scannedPaths, newLibraries, workingCopy, files, modelManager, mainLanguage,
emitDocChangedOnDisk, reporter);
future.setProgressValue(100);
}
struct ScanItem {
QString path;
int depth;
ScanItem(QString path = QString(), int depth = 0)
: path(path), depth(depth)
{ }
};
void ModelManager::importScan(QFutureInterface<void> &future,
ModelManagerInterface::WorkingCopy workingCopy,
QStringList paths, ModelManager *modelManager,
Language::Enum language,
bool emitDocChangedOnDisk)
{
// paths we have scanned for files and added to the files list
QSet<QString> scannedPaths = modelManager->m_scannedPaths;
// libraries we've found while scanning imports
QSet<QString> newLibraries;
QVector<ScanItem> pathsToScan;
pathsToScan.reserve(paths.size());
foreach (const QString &path, paths) {
QString cPath = QDir::cleanPath(path);
if (modelManager->m_scannedPaths.contains(cPath))
continue;
pathsToScan.append(ScanItem(cPath));
}
const int maxScanDepth = 5;
int progressRange = pathsToScan.size() * (1 << (2 + maxScanDepth));
int totalWork(progressRange), workDone(0);
future.setProgressRange(0, progressRange); // update max length while iterating?
const bool libOnly = true; // FIXME remove when tested more
while (!pathsToScan.isEmpty() && !future.isCanceled()) {
ScanItem toScan = pathsToScan.last();
pathsToScan.removeLast();
int pathBudget = (maxScanDepth + 2 - toScan.depth);
if (!scannedPaths.contains(toScan.path)) {
QStringList importedFiles;
const Snapshot snapshot = modelManager->snapshot();
if (!findNewQmlLibraryInPath(toScan.path, snapshot, modelManager, &importedFiles,
&scannedPaths, &newLibraries, true)
&& !libOnly && snapshot.documentsInDirectory(toScan.path).isEmpty())
importedFiles += qmlFilesInDirectory(toScan.path);