diff options
Diffstat (limited to 'src')
28 files changed, 1505 insertions, 1309 deletions
diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri index bd77b940bf..7d2a3c9aca 100644 --- a/src/libs/cplusplus/cplusplus-lib.pri +++ b/src/libs/cplusplus/cplusplus-lib.pri @@ -57,7 +57,8 @@ HEADERS += \ $$PWD/pp-scanner.h \ $$PWD/findcdbbreakpoint.h \ $$PWD/PPToken.h \ - $$PWD/Dumpers.h + $$PWD/Dumpers.h \ + $$PWD/cppmodelmanagerbase.h SOURCES += \ $$PWD/SimpleLexer.cpp \ @@ -85,6 +86,7 @@ SOURCES += \ $$PWD/pp-scanner.cpp \ $$PWD/findcdbbreakpoint.cpp \ $$PWD/PPToken.cpp \ - $$PWD/Dumpers.cpp + $$PWD/Dumpers.cpp \ + $$PWD/cppmodelmanagerbase.cpp RESOURCES += $$PWD/cplusplus.qrc diff --git a/src/libs/cplusplus/cplusplus.qbs b/src/libs/cplusplus/cplusplus.qbs index 2331804a55..09dfe63cec 100644 --- a/src/libs/cplusplus/cplusplus.qbs +++ b/src/libs/cplusplus/cplusplus.qbs @@ -94,6 +94,7 @@ QtcLibrary { "BackwardsScanner.cpp", "BackwardsScanner.h", "CppDocument.cpp", "CppDocument.h", "CppRewriter.cpp", "CppRewriter.h", + "cppmodelmanagerbase.cpp", "cppmodelmanagerbase.h", "DependencyTable.cpp", "DependencyTable.h", "DeprecatedGenTemplateInstance.cpp", "DeprecatedGenTemplateInstance.h", "ExpressionUnderCursor.cpp", "ExpressionUnderCursor.h", diff --git a/src/libs/cplusplus/cppmodelmanagerbase.cpp b/src/libs/cplusplus/cppmodelmanagerbase.cpp new file mode 100644 index 0000000000..6ad44b5bc4 --- /dev/null +++ b/src/libs/cplusplus/cppmodelmanagerbase.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cppmodelmanagerbase.h" + +namespace CPlusPlus { + +static CppModelManagerBase *g_instance = 0; + +CppModelManagerBase::CppModelManagerBase(QObject *parent) + : QObject(parent) +{ + Q_ASSERT(!g_instance); + g_instance = this; +} + +CppModelManagerBase::~CppModelManagerBase() +{ + Q_ASSERT(g_instance == this); + g_instance = 0; +} + +CppModelManagerBase *CppModelManagerBase::instance() +{ + return g_instance; +} + +bool CppModelManagerBase::trySetExtraDiagnostics(const QString &fileName, const QString &kind, + const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics) +{ + if (CppModelManagerBase *mm = instance()) + return mm->setExtraDiagnostics(fileName, kind, diagnostics); + return false; +} + +bool CppModelManagerBase::setExtraDiagnostics(const QString &fileName, const QString &kind, + const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics) +{ + Q_UNUSED(fileName); + Q_UNUSED(kind); + Q_UNUSED(diagnostics); + return false; +} + +CPlusPlus::Snapshot CppModelManagerBase::snapshot() const +{ + return CPlusPlus::Snapshot(); +} + +} // namespace CPlusPlus diff --git a/src/libs/cplusplus/cppmodelmanagerbase.h b/src/libs/cplusplus/cppmodelmanagerbase.h new file mode 100644 index 0000000000..f76c80a3ed --- /dev/null +++ b/src/libs/cplusplus/cppmodelmanagerbase.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CPPMODELMANAGERBASE_H +#define CPPMODELMANAGERBASE_H + +#include <cplusplus/CppDocument.h> + +#include <QObject> +#include <QList> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +namespace CPlusPlus { + +class CPLUSPLUS_EXPORT CppModelManagerBase : public QObject +{ + Q_OBJECT +public: + CppModelManagerBase(QObject *parent = 0); + ~CppModelManagerBase(); + + static CppModelManagerBase *instance(); + static bool trySetExtraDiagnostics(const QString &fileName, const QString &kind, + const QList<Document::DiagnosticMessage> &diagnostics); + + virtual bool setExtraDiagnostics(const QString &fileName, const QString &kind, + const QList<Document::DiagnosticMessage> &diagnostics); + virtual CPlusPlus::Snapshot snapshot() const; +}; + +} // namespace CPlusPlus + +#endif // CPPMODELMANAGERBASE_H diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri index 6324d83e32..47c4a9ecf6 100644 --- a/src/libs/qmljs/qmljs-lib.pri +++ b/src/libs/qmljs/qmljs-lib.pri @@ -11,6 +11,7 @@ HEADERS += \ $$PWD/qmljsbind.h \ $$PWD/qmljsbundle.h \ $$PWD/qmljsevaluate.h \ + $$PWD/qmljsfindexportedcpptypes.h \ $$PWD/qmljsdocument.h \ $$PWD/qmljsscanner.h \ $$PWD/qmljsinterpreter.h \ @@ -25,6 +26,7 @@ HEADERS += \ $$PWD/qmljsrewriter.h \ $$PWD/qmljsicons.h \ $$PWD/qmljsdelta.h \ + $$PWD/qmljsplugindumper.h \ $$PWD/qmljstypedescriptionreader.h \ $$PWD/qmljsscopeastpath.h \ $$PWD/qmljsvalueowner.h \ @@ -47,6 +49,7 @@ SOURCES += \ $$PWD/qmljsbind.cpp \ $$PWD/qmljsbundle.cpp \ $$PWD/qmljsevaluate.cpp \ + $$PWD/qmljsfindexportedcpptypes.cpp \ $$PWD/qmljsdocument.cpp \ $$PWD/qmljsscanner.cpp \ $$PWD/qmljsinterpreter.cpp \ @@ -60,6 +63,7 @@ SOURCES += \ $$PWD/qmljsrewriter.cpp \ $$PWD/qmljsicons.cpp \ $$PWD/qmljsdelta.cpp \ + $$PWD/qmljsplugindumper.cpp \ $$PWD/qmljstypedescriptionreader.cpp \ $$PWD/qmljsscopeastpath.cpp \ $$PWD/qmljsvalueowner.cpp \ diff --git a/src/libs/qmljs/qmljs.qbs b/src/libs/qmljs/qmljs.qbs index 94968cf313..0016128545 100644 --- a/src/libs/qmljs/qmljs.qbs +++ b/src/libs/qmljs/qmljs.qbs @@ -11,6 +11,7 @@ QtcLibrary { Depends { name: "Utils" } Depends { name: "LanguageUtils" } + Depends { name: "CPlusPlus" } Depends { name: "Qt"; submodules: ["widgets", "script", "xml"] } Group { @@ -33,6 +34,7 @@ QtcLibrary { "qmljsdelta.cpp", "qmljsdelta.h", "qmljsdocument.cpp", "qmljsdocument.h", "qmljsevaluate.cpp", "qmljsevaluate.h", + "qmljsfindexportedcpptypes.cpp", "qmljsfindexportedcpptypes.h", "qmljsicons.cpp", "qmljsicons.h", "qmljsicontextpane.h", "qmljsimportdependencies.cpp", "qmljsimportdependencies.h", @@ -41,6 +43,7 @@ QtcLibrary { "qmljslineinfo.cpp", "qmljslineinfo.h", "qmljslink.cpp", "qmljslink.h", "qmljsmodelmanagerinterface.cpp", "qmljsmodelmanagerinterface.h", + "qmljsplugindumper.cpp", "qmljsplugindumper.h", "qmljspropertyreader.cpp", "qmljspropertyreader.h", "qmljsqrcparser.cpp", "qmljsqrcparser.h", "qmljsreformatter.cpp", "qmljsreformatter.h", diff --git a/src/libs/qmljs/qmljs_dependencies.pri b/src/libs/qmljs/qmljs_dependencies.pri index e1d1204148..3686f2e628 100644 --- a/src/libs/qmljs/qmljs_dependencies.pri +++ b/src/libs/qmljs/qmljs_dependencies.pri @@ -1,4 +1,5 @@ QTC_LIB_NAME = QmlJS QTC_LIB_DEPENDS += \ utils \ - languageutils + languageutils \ + cplusplus diff --git a/src/libs/qmljs/qmljsconstants.h b/src/libs/qmljs/qmljsconstants.h index 3ddb014754..377f282ea4 100644 --- a/src/libs/qmljs/qmljsconstants.h +++ b/src/libs/qmljs/qmljsconstants.h @@ -80,5 +80,11 @@ enum Enum }; } +namespace Constants { + +const char TASK_INDEX[] = "QmlJSEditor.TaskIndex"; +const char TASK_IMPORT_SCAN[] = "QmlJSEditor.TaskImportScan"; + +} // namespace Constants } // namespace QmlJS #endif // QMLJSCONSTANTS_H diff --git a/src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp index 4b9f819fd7..7034ea64b9 100644 --- a/src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp +++ b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp @@ -30,13 +30,16 @@ #include "qmljsfindexportedcpptypes.h" #include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljsdocument.h> #include <cplusplus/Overview.h> #include <cplusplus/TypeOfExpression.h> -#include <cpptools/cppmodelmanagerinterface.h> +#include <cplusplus/cppmodelmanagerbase.h> +#include <cplusplus/CppDocument.h> #include <QDebug> +#include <QList> -using namespace QmlJSTools; +//using namespace QmlJS; namespace { using namespace CPlusPlus; @@ -66,7 +69,7 @@ class FindExportsVisitor : protected ASTVisitor ASTMatcher _matcher; ASTPatternBuilder _builder; Overview _overview; - QList<Document::DiagnosticMessage> _messages; + QList<CPlusPlus::Document::DiagnosticMessage> _messages; public: FindExportsVisitor(CPlusPlus::Document::Ptr doc) @@ -82,7 +85,7 @@ public: accept(translationUnit()->ast()); } - QList<Document::DiagnosticMessage> messages() const + QList<CPlusPlus::Document::DiagnosticMessage> messages() const { return _messages; } @@ -181,7 +184,7 @@ protected: Document::DiagnosticMessage::Warning, _doc->fileName(), line, column, - FindExportedCppTypes::tr( + QmlJS::FindExportedCppTypes::tr( "The type will only be available in Qt Creator's QML editors when the type name is a string literal")); return false; } @@ -239,7 +242,7 @@ protected: Document::DiagnosticMessage::Warning, _doc->fileName(), line, column, - FindExportedCppTypes::tr( + QmlJS::FindExportedCppTypes::tr( "The module URI cannot be determined by static analysis. The type will be available\n" "globally in the QML editor. You can add a \"// @uri My.Module.Uri\" annotation to let\n" "Qt Creator know about a likely URI.")); @@ -370,7 +373,7 @@ protected: Document::DiagnosticMessage::Warning, _doc->fileName(), line, column, - FindExportedCppTypes::tr( + QmlJS::FindExportedCppTypes::tr( "must be a string literal to be available in the QML editor")); return false; } @@ -389,7 +392,7 @@ protected: } private: - QString stringOf(AST *ast) + QString stringOf(CPlusPlus::AST *ast) { return stringOf(ast->firstToken(), ast->lastToken() - 1); } @@ -681,6 +684,8 @@ static void buildContextProperties( } // anonymous namespace +namespace QmlJS { + FindExportedCppTypes::FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot) : m_snapshot(snapshot) { @@ -699,11 +704,9 @@ void FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document) FindExportsVisitor finder(document); finder(); - if (CppTools::CppModelManagerInterface *cppModelManager = CppTools::CppModelManagerInterface::instance()) { - static const QString kindKey = QLatin1String("QmlJSTools.ExportedQmlTypesDiagnostic"); - cppModelManager->setExtraDiagnostics(document->fileName(), kindKey, - finder.messages()); - } + static const QString kindKey = QLatin1String("QmlJSTools.ExportedQmlTypesDiagnostic"); + CppModelManagerBase::trySetExtraDiagnostics(document->fileName(), kindKey, + finder.messages()); // if nothing was found, done const QList<ContextProperty> contextPropertyDescriptions = finder.contextProperties(); @@ -712,8 +715,8 @@ void FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document) return; // context properties need lookup inside function scope, and thus require a full check - Document::Ptr localDoc = document; - if (document->checkMode() != Document::FullCheck && !contextPropertyDescriptions.isEmpty()) { + CPlusPlus::Document::Ptr localDoc = document; + if (document->checkMode() != CPlusPlus::Document::FullCheck && !contextPropertyDescriptions.isEmpty()) { localDoc = m_snapshot.documentFromSource(document->utf8Source(), document->fileName()); localDoc->check(); } @@ -749,7 +752,7 @@ QHash<QString, QString> FindExportedCppTypes::contextProperties() const return m_contextProperties; } -bool FindExportedCppTypes::maybeExportsTypes(const Document::Ptr &document) +bool FindExportedCppTypes::maybeExportsTypes(const CPlusPlus::Document::Ptr &document) { if (!document->control()) return false; @@ -770,3 +773,5 @@ bool FindExportedCppTypes::maybeExportsTypes(const Document::Ptr &document) } return false; } + +} // namespace QmlJS diff --git a/src/plugins/qmljstools/qmljsfindexportedcpptypes.h b/src/libs/qmljs/qmljsfindexportedcpptypes.h index 90884d66d2..ca6508c39a 100644 --- a/src/plugins/qmljstools/qmljsfindexportedcpptypes.h +++ b/src/libs/qmljs/qmljsfindexportedcpptypes.h @@ -27,18 +27,19 @@ ** ****************************************************************************/ -#ifndef QMLJSTOOLS_QMLJSFINDEXPORTEDCPPTYPES_H -#define QMLJSTOOLS_QMLJSFINDEXPORTEDCPPTYPES_H +#ifndef QMLJS_QMLJSFINDEXPORTEDCPPTYPES_H +#define QMLJS_QMLJSFINDEXPORTEDCPPTYPES_H +#include "qmljs_global.h" #include <cplusplus/CppDocument.h> #include <languageutils/fakemetaobject.h> #include <QCoreApplication> #include <QHash> -namespace QmlJSTools { +namespace QmlJS { -class FindExportedCppTypes +class QMLJS_EXPORT FindExportedCppTypes { Q_DECLARE_TR_FUNCTIONS(QmlJSTools::FindExportedCppTypes) public: @@ -58,6 +59,6 @@ private: QHash<QString, QString> m_contextProperties; }; -} // namespace QmlJSTools +} // namespace QmlJS -#endif // QMLJSTOOLS_QMLJSFINDEXPORTEDCPPTYPES_H +#endif // QMLJS_QMLJSFINDEXPORTEDCPPTYPES_H diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index ec70d6bf65..d9aa6aa118 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -27,11 +27,33 @@ ** ****************************************************************************/ +#include "qmljsbind.h" +#include "qmljsconstants.h" +#include "qmljsfindexportedcpptypes.h" +#include "qmljsinterpreter.h" #include "qmljsmodelmanagerinterface.h" +#include "qmljsplugindumper.h" +#include "qmljstypedescriptionreader.h" +#include <cplusplus/cppmodelmanagerbase.h> +#include <utils/function.h> +#include <utils/hostosinfo.h> + +#include <QDebug> +#include <QDir> +#include <QFile> #include <QFileInfo> +#include <QMetaObject> +#include <QRegExp> +#include <QTextDocument> +#include <QTextStream> +#include <QTimer> +#include <QtAlgorithms> +#include <utils/runextensions.h> + +#include <stdio.h> -using namespace QmlJS; +namespace QmlJS { /*! \class QmlJS::ModelManagerInterface @@ -54,9 +76,45 @@ using namespace QmlJS; static ModelManagerInterface *g_instance = 0; +static QStringList environmentImportPaths() +{ + QStringList paths; + + QByteArray envImportPath = qgetenv("QML_IMPORT_PATH"); + + foreach (const QString &path, QString::fromLatin1(envImportPath) + .split(Utils::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts)) { + QString canonicalPath = QDir(path).canonicalPath(); + if (!canonicalPath.isEmpty() && !paths.contains(canonicalPath)) + paths.append(canonicalPath); + } + + return paths; +} + ModelManagerInterface::ModelManagerInterface(QObject *parent) - : QObject(parent) + : QObject(parent), + m_shouldScanImports(false), + m_pluginDumper(new PluginDumper(this)) { + m_synchronizer.setCancelOnWait(true); + + m_updateCppQmlTypesTimer = new QTimer(this); + m_updateCppQmlTypesTimer->setInterval(1000); + m_updateCppQmlTypesTimer->setSingleShot(true); + connect(m_updateCppQmlTypesTimer, SIGNAL(timeout()), SLOT(startCppQmlTypeUpdate())); + + m_asyncResetTimer = new QTimer(this); + m_asyncResetTimer->setInterval(15000); + m_asyncResetTimer->setSingleShot(true); + connect(m_asyncResetTimer, SIGNAL(timeout()), SLOT(resetCodeModel())); + + qRegisterMetaType<QmlJS::Document::Ptr>("QmlJS::Document::Ptr"); + qRegisterMetaType<QmlJS::LibraryInfo>("QmlJS::LibraryInfo"); + + m_defaultImportPaths << environmentImportPaths(); + updateImportPaths(); + Q_ASSERT(! g_instance); g_instance = this; } @@ -113,8 +171,1086 @@ ModelManagerInterface *ModelManagerInterface::instance() return g_instance; } +void ModelManagerInterface::writeWarning(const QString &msg) +{ + if (ModelManagerInterface *i = instance()) + i->writeMessageInternal(msg); + else + qDebug() << msg; +} + +ModelManagerInterface::WorkingCopy ModelManagerInterface::workingCopy() +{ + if (ModelManagerInterface *i = instance()) + return i->workingCopyInternal(); + return WorkingCopy(); +} + QHash<QString, Language::Enum> ModelManagerInterface::languageForSuffix() const { return defaultLanguageMapping(); } +void ModelManagerInterface::writeMessageInternal(const QString &msg) const +{ + qDebug() << msg; +} + +ModelManagerInterface::WorkingCopy ModelManagerInterface::workingCopyInternal() const +{ + ModelManagerInterface::WorkingCopy res; + return res; +} + +void ModelManagerInterface::addTaskInternal(QFuture<void> result, const QString &msg, + const char *taskId) const +{ + Q_UNUSED(result); + qDebug() << "started " << taskId << " " << msg; +} + +void ModelManagerInterface::loadQmlTypeDescriptionsInternal(const QString &resourcePath) +{ + const QDir typeFileDir(resourcePath + QLatin1String("/qml-type-descriptions")); + const QStringList qmlTypesExtensions = QStringList() << QLatin1String("*.qmltypes"); + QFileInfoList qmlTypesFiles = typeFileDir.entryInfoList( + qmlTypesExtensions, + QDir::Files, + QDir::Name); + + QStringList errors; + QStringList warnings; + + // filter out the actual Qt builtins + for (int i = 0; i < qmlTypesFiles.size(); ++i) { + if (qmlTypesFiles.at(i).baseName() == QLatin1String("builtins")) { + QFileInfoList list; + list.append(qmlTypesFiles.at(i)); + CppQmlTypesLoader::defaultQtObjects = + CppQmlTypesLoader::loadQmlTypes(list, &errors, &warnings); + qmlTypesFiles.removeAt(i); + break; + } + } + + // load the fallbacks for libraries + CppQmlTypesLoader::defaultLibraryObjects.unite( + CppQmlTypesLoader::loadQmlTypes(qmlTypesFiles, &errors, &warnings)); + + foreach (const QString &error, errors) + writeMessageInternal(error); + foreach (const QString &warning, warnings) + writeMessageInternal(warning); +} + + + +Snapshot ModelManagerInterface::snapshot() const +{ + QMutexLocker locker(&m_mutex); + return _validSnapshot; +} + +Snapshot ModelManagerInterface::newestSnapshot() const +{ + QMutexLocker locker(&m_mutex); + return _newestSnapshot; +} + +void ModelManagerInterface::updateSourceFiles(const QStringList &files, + bool emitDocumentOnDiskChanged) +{ + refreshSourceFiles(files, emitDocumentOnDiskChanged); +} + +QFuture<void> ModelManagerInterface::refreshSourceFiles(const QStringList &sourceFiles, + bool emitDocumentOnDiskChanged) +{ + if (sourceFiles.isEmpty()) + return QFuture<void>(); + + QFuture<void> result = QtConcurrent::run(&ModelManagerInterface::parse, + workingCopyInternal(), sourceFiles, + this, Language::Qml, + emitDocumentOnDiskChanged); + + if (m_synchronizer.futures().size() > 10) { + QList<QFuture<void> > futures = m_synchronizer.futures(); + + m_synchronizer.clearFutures(); + + foreach (const QFuture<void> &future, futures) { + if (! (future.isFinished() || future.isCanceled())) + m_synchronizer.addFuture(future); + } + } + + m_synchronizer.addFuture(result); + + if (sourceFiles.count() > 1) + addTaskInternal(result, tr("Indexing"), Constants::TASK_INDEX); + + if (sourceFiles.count() > 1 && !m_shouldScanImports) { + bool scan = false; + { + QMutexLocker l(&m_mutex); + if (!m_shouldScanImports) { + m_shouldScanImports = true; + scan = true; + } + } + if (scan) + updateImportPaths(); + } + + return result; +} + + +void ModelManagerInterface::fileChangedOnDisk(const QString &path) +{ + QtConcurrent::run(&ModelManagerInterface::parse, + workingCopyInternal(), QStringList() << path, + this, Language::Unknown, true); +} + +void ModelManagerInterface::removeFiles(const QStringList &files) +{ + emit aboutToRemoveFiles(files); + + QMutexLocker locker(&m_mutex); + + foreach (const QString &file, files) { + _validSnapshot.remove(file); + _newestSnapshot.remove(file); + } +} + +namespace { +bool pInfoLessThanActive(const ModelManagerInterface::ProjectInfo &p1, const ModelManagerInterface::ProjectInfo &p2) +{ + QStringList s1 = p1.activeResourceFiles; + QStringList s2 = p2.activeResourceFiles; + if (s1.size() < s2.size()) + return true; + if (s1.size() > s2.size()) + return false; + for (int i = 0; i < s1.size(); ++i) { + if (s1.at(i) < s2.at(i)) + return true; + else if (s1.at(i) > s2.at(i)) + return false; + } + return false; +} + +bool pInfoLessThanAll(const ModelManagerInterface::ProjectInfo &p1, const ModelManagerInterface::ProjectInfo &p2) +{ + QStringList s1 = p1.allResourceFiles; + QStringList s2 = p2.allResourceFiles; + if (s1.size() < s2.size()) + return true; + if (s1.size() > s2.size()) + return false; + for (int i = 0; i < s1.size(); ++i) { + if (s1.at(i) < s2.at(i)) + return true; + else if (s1.at(i) > s2.at(i)) + return false; + } + return false; +} +} + +QStringList ModelManagerInterface::filesAtQrcPath(const QString &path, const QLocale *locale, + ProjectExplorer::Project *project, + QrcResourceSelector resources) +{ + QString normPath = QrcParser::normalizedQrcFilePath(path); + QList<ProjectInfo> pInfos; + if (project) + pInfos.append(projectInfo(project)); + else + pInfos = projectInfos(); + + QStringList res; + QSet<QString> pathsChecked; + foreach (const ModelManagerInterface::ProjectInfo &pInfo, pInfos) { + QStringList qrcFilePaths; + if (resources == ActiveQrcResources) + qrcFilePaths = pInfo.activeResourceFiles; + else + qrcFilePaths = pInfo.allResourceFiles; + foreach (const QString &qrcFilePath, qrcFilePaths) { + if (pathsChecked.contains(qrcFilePath)) + continue; + pathsChecked.insert(qrcFilePath); + QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath); + if (qrcFile.isNull()) + continue; + qrcFile->collectFilesAtPath(normPath, &res, locale); + } + } + res.sort(); // make the result predictable + return res; +} + +QMap<QString, QStringList> ModelManagerInterface::filesInQrcPath(const QString &path, + const QLocale *locale, + ProjectExplorer::Project *project, + bool addDirs, + QrcResourceSelector resources) +{ + QString normPath = QrcParser::normalizedQrcDirectoryPath(path); + QList<ProjectInfo> pInfos; + if (project) { + pInfos.append(projectInfo(project)); + } else { + pInfos = projectInfos(); + if (resources == ActiveQrcResources) // make the result predictable + qSort(pInfos.begin(), pInfos.end(), &pInfoLessThanActive); + else + qSort(pInfos.begin(), pInfos.end(), &pInfoLessThanAll); + } + QMap<QString, QStringList> res; + QSet<QString> pathsChecked; + foreach (const ModelManagerInterface::ProjectInfo &pInfo, pInfos) { + QStringList qrcFilePaths; + if (resources == ActiveQrcResources) + qrcFilePaths = pInfo.activeResourceFiles; + else + qrcFilePaths = pInfo.allResourceFiles; + foreach (const QString &qrcFilePath, qrcFilePaths) { + if (pathsChecked.contains(qrcFilePath)) + continue; + pathsChecked.insert(qrcFilePath); + QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath); + + if (qrcFile.isNull()) + continue; + qrcFile->collectFilesInPath(normPath, &res, addDirs, locale); + } + } + return res; +} + +QList<ModelManagerInterface::ProjectInfo> ModelManagerInterface::projectInfos() const +{ + QMutexLocker locker(&m_mutex); + + return m_projects.values(); +} + +ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfo(ProjectExplorer::Project *project) const +{ + QMutexLocker locker(&m_mutex); + + return m_projects.value(project, ProjectInfo()); +} + +void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p) +{ + if (! pinfo.isValid() || !p) + return; + + Snapshot snapshot; + ProjectInfo oldInfo; + { + QMutexLocker locker(&m_mutex); + oldInfo = m_projects.value(p); + m_projects.insert(p, pinfo); + snapshot = _validSnapshot; + } + + if (oldInfo.qmlDumpPath != pinfo.qmlDumpPath + || oldInfo.qmlDumpEnvironment != pinfo.qmlDumpEnvironment) { + m_pluginDumper->scheduleRedumpPlugins(); + m_pluginDumper->scheduleMaybeRedumpBuiltins(pinfo); + } + + + updateImportPaths(); + + // remove files that are no longer in the project and have been deleted + QStringList deletedFiles; + foreach (const QString &oldFile, oldInfo.sourceFiles) { + if (snapshot.document(oldFile) + && !pinfo.sourceFiles.contains(oldFile) + && !QFile::exists(oldFile)) { + deletedFiles += oldFile; + } + } + removeFiles(deletedFiles); + foreach (const QString &oldFile, deletedFiles) + m_fileToProject.remove(oldFile, p); + + // parse any files not yet in the snapshot + QStringList newFiles; + foreach (const QString &file, pinfo.sourceFiles) { + if (!snapshot.document(file)) + newFiles += file; + } + updateSourceFiles(newFiles, false); + foreach (const QString &newFile, deletedFiles) + m_fileToProject.insert(newFile, p); + + // update qrc cache + foreach (const QString &newQrc, pinfo.allResourceFiles) + m_qrcCache.addPath(newQrc); + foreach (const QString &oldQrc, oldInfo.allResourceFiles) + m_qrcCache.removePath(oldQrc); + + int majorVersion, minorVersion, patchVersion; + // dump builtin types if the shipped definitions are probably outdated and the + // Qt version ships qmlplugindump + if (::sscanf(pinfo.qtVersionString.toLatin1().constData(), "%d.%d.%d", + &majorVersion, &minorVersion, &patchVersion) != 3) + majorVersion = minorVersion = patchVersion = -1; + + if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (majorVersion == 8 + && patchVersion >= 5)))) { + m_pluginDumper->loadBuiltinTypes(pinfo); + } + + emit projectInfoUpdated(pinfo); +} + + +void ModelManagerInterface::removeProjectInfo(ProjectExplorer::Project *project) +{ + ProjectInfo info; + info.sourceFiles.clear(); + // update with an empty project info to clear data + updateProjectInfo(info, project); + + { + QMutexLocker locker(&m_mutex); + m_projects.remove(project); + } +} + +ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath(QString path) +{ + QMutexLocker locker(&m_mutex); + + foreach (const ProjectInfo &p, m_projects) + if (p.sourceFiles.contains(path)) + return p; + return ProjectInfo(); +} + +void ModelManagerInterface::emitDocumentChangedOnDisk(Document::Ptr doc) +{ emit documentChangedOnDisk(doc); } + +void ModelManagerInterface::updateQrcFile(const QString &path) +{ + m_qrcCache.updatePath(path); +} + +void ModelManagerInterface::updateDocument(Document::Ptr doc) +{ + { + QMutexLocker locker(&m_mutex); + _validSnapshot.insert(doc); + _newestSnapshot.insert(doc, true); + } + emit documentUpdated(doc); +} + +void ModelManagerInterface::updateLibraryInfo(const QString &path, const LibraryInfo &info) +{ + if (!info.pluginTypeInfoError().isEmpty()) + qDebug() << "Dumping errors for " << path << ":" << info.pluginTypeInfoError(); + + { + QMutexLocker locker(&m_mutex); + _validSnapshot.insertLibraryInfo(path, info); + _newestSnapshot.insertLibraryInfo(path, info); + } + // only emit if we got new useful information + if (info.isValid()) + emit libraryInfoUpdated(path, info); +} + +static QStringList filesInDirectoryForLanguages(const QString &path, QList<Language::Enum> languages) +{ + const QStringList pattern = ModelManagerInterface::globPatternsForLanguages(languages); + QStringList files; + + const QDir dir(path); + foreach (const QFileInfo &fi, dir.entryInfoList(pattern, QDir::Files)) + files += fi.absoluteFilePath(); + + return files; +} + +static void findNewImplicitImports(const Document::Ptr &doc, const Snapshot &snapshot, + QStringList *importedFiles, QSet<QString> *scannedPaths) +{ + // scan files that could be implicitly imported + // it's important we also do this for JS files, otherwise the isEmpty check will fail + if (snapshot.documentsInDirectory(doc->path()).isEmpty()) { + if (! scannedPaths->contains(doc->path())) { + *importedFiles += filesInDirectoryForLanguages(doc->path(), + Document::companionLanguages(doc->language())); + scannedPaths->insert(doc->path()); + } + } +} + +static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapshot, + QStringList *importedFiles, QSet<QString> *scannedPaths) +{ + // scan files and directories that are explicitly imported + foreach (const ImportInfo &import, doc->bind()->imports()) { + const QString &importName = import.path(); + if (import.type() == ImportType::File) { + if (! snapshot.document(importName)) + *importedFiles += importName; + } else if (import.type() == ImportType::Directory) { + if (snapshot.documentsInDirectory(importName).isEmpty()) { + if (! scannedPaths->contains(importName)) { + *importedFiles += filesInDirectoryForLanguages(importName, + Document::companionLanguages(doc->language())); + scannedPaths->insert(importName); + } + } + } else if (import.type() == ImportType::QrcFile) { + QStringList importPaths = ModelManagerInterface::instance()->filesAtQrcPath(importName); + foreach (const QString &importPath, importPaths) { + if (! snapshot.document(importPath)) + *importedFiles += importPath; + } + } else if (import.type() == ImportType::QrcDirectory) { + QMapIterator<QString,QStringList> dirContents(ModelManagerInterface::instance()->filesInQrcPath(importName)); + while (dirContents.hasNext()) { + dirContents.next(); + if (Document::isQmlLikeOrJsLanguage(ModelManagerInterface::guessLanguageOfFile(dirContents.key()))) { + foreach (const QString &filePath, dirContents.value()) { + if (! snapshot.document(filePath)) + *importedFiles += filePath; + } + } + } + } + } +} + +static bool findNewQmlLibraryInPath(const QString &path, + const Snapshot &snapshot, + ModelManagerInterface *modelManager, + QStringList *importedFiles, + QSet<QString> *scannedPaths, + QSet<QString> *newLibraries, + bool ignoreMissing) +{ + // if we know there is a library, done + 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 (!ignoreMissing) { + LibraryInfo libraryInfo(LibraryInfo::NotFound); + modelManager->updateLibraryInfo(path, libraryInfo); + } + return false; + } + + if (Utils::HostOsInfo::isWindowsHost()) { + // QTCREATORBUG-3402 - be case sensitive even here? + } + + // found a new library! + qmldirFile.open(QFile::ReadOnly); + QString qmldirData = QString::fromUtf8(qmldirFile.readAll()); + + QmlDirParser qmldirParser; + qmldirParser.parse(qmldirData); + + const QString libraryPath = QFileInfo(qmldirFile).absolutePath(); + newLibraries->insert(libraryPath); + modelManager->updateLibraryInfo(libraryPath, LibraryInfo(qmldirParser)); + + // scan the qml files in the library + foreach (const QmlDirParser::Component &component, qmldirParser.components()) { + if (! component.fileName.isEmpty()) { + const QFileInfo componentFileInfo(dir.filePath(component.fileName)); + const QString path = QDir::cleanPath(componentFileInfo.absolutePath()); + if (! scannedPaths->contains(path)) { + *importedFiles += filesInDirectoryForLanguages(path, + Document::companionLanguages(Language::Unknown)); + scannedPaths->insert(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) +{ + QString libraryPath = QString::fromLatin1("%1.%2.%3").arg( + path, + QString::number(version.majorVersion()), + QString::number(version.minorVersion())); + findNewQmlLibraryInPath( + libraryPath, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries, false); + + libraryPath = QString::fromLatin1("%1.%2").arg( + path, + QString::number(version.majorVersion())); + findNewQmlLibraryInPath( + libraryPath, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries, false); + + findNewQmlLibraryInPath( + path, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries, false); +} + +static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot, + ModelManagerInterface *modelManager, + QStringList *importedFiles, QSet<QString> *scannedPaths, QSet<QString> *newLibraries) +{ + // scan current dir + findNewQmlLibraryInPath(doc->path(), snapshot, modelManager, + importedFiles, scannedPaths, newLibraries, false); + + // scan dir and lib imports + const QStringList importPaths = modelManager->importPaths(); + foreach (const ImportInfo &import, doc->bind()->imports()) { + if (import.type() == ImportType::Directory) { + const QString targetPath = import.path(); + findNewQmlLibraryInPath(targetPath, snapshot, modelManager, + importedFiles, scannedPaths, newLibraries, false); + } + + if (import.type() == ImportType::Library) { + if (!import.version().isValid()) + continue; + foreach (const QString &importPath, importPaths) { + const QString targetPath = QDir(importPath).filePath(import.path()); + findNewQmlLibrary(targetPath, import.version(), snapshot, modelManager, + importedFiles, scannedPaths, newLibraries); + } + } + } +} + +void ModelManagerInterface::parseLoop(QSet<QString> &scannedPaths, + QSet<QString> &newLibraries, + WorkingCopy workingCopy, + QStringList files, + ModelManagerInterface *modelManager, + Language::Enum mainLanguage, + bool emitDocChangedOnDisk, + Utils::function<bool(qreal)> reportProgress) +{ + for (int i = 0; i < files.size(); ++i) { + if (!reportProgress(qreal(i) / files.size())) + return; + + const QString fileName = files.at(i); + + Language::Enum language = guessLanguageOfFile(fileName); + if (language == Language::Unknown) { + if (fileName.endsWith(QLatin1String(".qrc"))) + modelManager->updateQrcFile(fileName); + continue; + } + if (language == Language::Qml + && (mainLanguage == Language::QmlQtQuick1 || Language::QmlQtQuick2)) + language = mainLanguage; + QString contents; + int documentRevision = 0; + + if (workingCopy.contains(fileName)) { + QPair<QString, int> entry = workingCopy.get(fileName); + contents = entry.first; + documentRevision = entry.second; + } else { + QFile inFile(fileName); + + if (inFile.open(QIODevice::ReadOnly)) { + QTextStream ins(&inFile); + contents = ins.readAll(); + inFile.close(); + } + } + + Document::MutablePtr doc = Document::create(fileName, language); + doc->setEditorRevision(documentRevision); + 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); + findNewFileImports(doc, snapshot, &importedFiles, &scannedPaths); + findNewLibraryImports(doc, snapshot, modelManager, &importedFiles, &scannedPaths, &newLibraries); + + // add new files to parse list + foreach (const QString &file, importedFiles) { + if (! files.contains(file)) + files.append(file); + } + + modelManager->updateDocument(doc); + if (emitDocChangedOnDisk) + 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 ModelManagerInterface::parse(QFutureInterface<void> &future, + WorkingCopy workingCopy, + QStringList files, + ModelManagerInterface *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 ModelManagerInterface::importScan(QFutureInterface<void> &future, + ModelManagerInterface::WorkingCopy workingCopy, + QStringList paths, ModelManagerInterface *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()); + { + QMutexLocker l(&modelManager->m_mutex); + foreach (const QString &path, paths) { + QString cPath = QDir::cleanPath(path); + if (modelManager->m_scannedPaths.contains(cPath)) + continue; + pathsToScan.append(ScanItem(cPath)); + modelManager->m_scannedPaths.insert(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 + const Snapshot snapshot = modelManager->snapshot(); + while (!pathsToScan.isEmpty() && !future.isCanceled()) { + ScanItem toScan = pathsToScan.last(); + pathsToScan.pop_back(); + int pathBudget = (maxScanDepth + 2 - toScan.depth); + if (!scannedPaths.contains(toScan.path)) { + QStringList importedFiles; + if (!findNewQmlLibraryInPath(toScan.path, snapshot, modelManager, &importedFiles, + &scannedPaths, &newLibraries, true) + && !libOnly && snapshot.documentsInDirectory(toScan.path).isEmpty()) + importedFiles += filesInDirectoryForLanguages(toScan.path, + Document::companionLanguages(language)); + workDone += 1; + future.setProgressValue(progressRange * workDone / totalWork); + if (!importedFiles.isEmpty()) { + FutureReporter reporter(future, progressRange * pathBudget / (4 * totalWork), + progressRange * workDone / totalWork); + parseLoop(scannedPaths, newLibraries, workingCopy, importedFiles, modelManager, + language, emitDocChangedOnDisk, reporter); // run in parallel?? + importedFiles.clear(); + } + workDone += pathBudget / 4 - 1; + future.setProgressValue(progressRange * workDone / totalWork); + } else { + workDone += pathBudget / 4; + } + // always descend tree, as we might have just scanned with a smaller depth + if (toScan.depth < maxScanDepth) { + QDir dir(toScan.path); + QStringList subDirs(dir.entryList(QDir::Dirs)); + workDone += 1; + totalWork += pathBudget / 2 * subDirs.size() - pathBudget * 3 / 4 + 1; + foreach (const QString path, subDirs) + pathsToScan.append(ScanItem(dir.absoluteFilePath(path), toScan.depth + 1)); + } else { + workDone += pathBudget *3 / 4; + } + future.setProgressValue(progressRange * workDone / totalWork); + } + future.setProgressValue(progressRange); + if (future.isCanceled()) { + // assume no work has been done + QMutexLocker l(&modelManager->m_mutex); + foreach (const QString &path, paths) + modelManager->m_scannedPaths.remove(path); + } +} + +QStringList ModelManagerInterface::importPaths() const +{ + QMutexLocker l(&m_mutex); + return m_allImportPaths; +} + +QmlLanguageBundles ModelManagerInterface::activeBundles() const +{ + QMutexLocker l(&m_mutex); + return m_activeBundles; +} + +QmlLanguageBundles ModelManagerInterface::extendedBundles() const +{ + QMutexLocker l(&m_mutex); + return m_extendedBundles; +} + +void ModelManagerInterface::updateImportPaths() +{ + QStringList allImportPaths; + QmlLanguageBundles activeBundles; + QmlLanguageBundles extendedBundles; + QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); + while (it.hasNext()) { + it.next(); + foreach (const QString &path, it.value().importPaths) { + const QString canonicalPath = QFileInfo(path).canonicalFilePath(); + if (!canonicalPath.isEmpty()) + allImportPaths += canonicalPath; + } + } + it.toFront(); + while (it.hasNext()) { + it.next(); + activeBundles.mergeLanguageBundles(it.value().activeBundle); + foreach (Language::Enum l, it.value().activeBundle.languages()) { + foreach (const QString &path, it.value().activeBundle.bundleForLanguage(l) + .searchPaths().stringList()) { + const QString canonicalPath = QFileInfo(path).canonicalFilePath(); + if (!canonicalPath.isEmpty()) + allImportPaths += canonicalPath; + } + } + } + it.toFront(); + while (it.hasNext()) { + it.next(); + extendedBundles.mergeLanguageBundles(it.value().extendedBundle); + foreach (Language::Enum l, it.value().extendedBundle.languages()) { + foreach (const QString &path, it.value().extendedBundle.bundleForLanguage(l) + .searchPaths().stringList()) { + const QString canonicalPath = QFileInfo(path).canonicalFilePath(); + if (!canonicalPath.isEmpty()) + allImportPaths += canonicalPath; + } + } + } + allImportPaths += m_defaultImportPaths; + allImportPaths.removeDuplicates(); + + { + QMutexLocker l(&m_mutex); + m_allImportPaths = allImportPaths; + m_activeBundles = activeBundles; + m_extendedBundles = extendedBundles; + } + + + // check if any file in the snapshot imports something new in the new paths + Snapshot snapshot = _validSnapshot; + QStringList importedFiles; + QSet<QString> scannedPaths; + QSet<QString> newLibraries; + foreach (const Document::Ptr &doc, snapshot) + findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries); + + updateSourceFiles(importedFiles, true); + + if (!m_shouldScanImports) + return; + QStringList pathToScan; + { + QMutexLocker l(&m_mutex); + foreach (QString importPath, allImportPaths) + if (!m_scannedPaths.contains(importPath)) { + pathToScan.append(importPath); + } + } + + if (pathToScan.count() > 1) { + QFuture<void> result = QtConcurrent::run(&ModelManagerInterface::importScan, + workingCopyInternal(), pathToScan, + this, Language::Qml, + true); + + if (m_synchronizer.futures().size() > 10) { + QList<QFuture<void> > futures = m_synchronizer.futures(); + + m_synchronizer.clearFutures(); + + foreach (const QFuture<void> &future, futures) { + if (! (future.isFinished() || future.isCanceled())) + m_synchronizer.addFuture(future); + } + } + + m_synchronizer.addFuture(result); + + addTaskInternal(result, tr("Qml import scan"), Constants::TASK_IMPORT_SCAN); + } +} + +ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfo() const +{ + if (m_projects.isEmpty()) + return ProjectInfo(); + return m_projects.begin().value(); +} + +void ModelManagerInterface::loadPluginTypes(const QString &libraryPath, const QString &importPath, + const QString &importUri, const QString &importVersion) +{ + m_pluginDumper->loadPluginTypes(libraryPath, importPath, importUri, importVersion); +} + +// is called *inside a c++ parsing thread*, to allow hanging on to source and ast +void ModelManagerInterface::maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc) +{ + // avoid scanning documents without source code available + doc->keepSourceAndAST(); + if (doc->utf8Source().isEmpty()) { + doc->releaseSourceAndAST(); + return; + } + + // keep source and AST alive if we want to scan for register calls + const bool scan = FindExportedCppTypes::maybeExportsTypes(doc); + if (!scan) + doc->releaseSourceAndAST(); + + // delegate actual queuing to the gui thread + QMetaObject::invokeMethod(this, "queueCppQmlTypeUpdate", + Q_ARG(CPlusPlus::Document::Ptr, doc), Q_ARG(bool, scan)); +} + +void ModelManagerInterface::queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc, bool scan) +{ + QPair<CPlusPlus::Document::Ptr, bool> prev = m_queuedCppDocuments.value(doc->fileName()); + if (prev.first && prev.second) + prev.first->releaseSourceAndAST(); + m_queuedCppDocuments.insert(doc->fileName(), qMakePair(doc, scan)); + m_updateCppQmlTypesTimer->start(); +} + +void ModelManagerInterface::startCppQmlTypeUpdate() +{ + // if a future is still running, delay + if (m_cppQmlTypesUpdater.isRunning()) { + m_updateCppQmlTypesTimer->start(); + return; + } + + CPlusPlus::CppModelManagerBase *cppModelManager = + CPlusPlus::CppModelManagerBase::instance(); + if (!cppModelManager) + return; + + m_cppQmlTypesUpdater = QtConcurrent::run( + &ModelManagerInterface::updateCppQmlTypes, + this, cppModelManager->snapshot(), m_queuedCppDocuments); + m_queuedCppDocuments.clear(); +} + +void ModelManagerInterface::asyncReset() +{ + m_asyncResetTimer->start(); +} + +void ModelManagerInterface::updateCppQmlTypes(QFutureInterface<void> &interface, + ModelManagerInterface *qmlModelManager, + CPlusPlus::Snapshot snapshot, + QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents) +{ + CppDataHash newData = qmlModelManager->cppData(); + + FindExportedCppTypes finder(snapshot); + + bool hasNewInfo = false; + typedef QPair<CPlusPlus::Document::Ptr, bool> DocScanPair; + foreach (const DocScanPair &pair, documents) { + if (interface.isCanceled()) + return; + + CPlusPlus::Document::Ptr doc = pair.first; + const bool scan = pair.second; + const QString fileName = doc->fileName(); + if (!scan) { + hasNewInfo = hasNewInfo || newData.remove(fileName) > 0; + continue; + } + + finder(doc); + + QList<LanguageUtils::FakeMetaObject::ConstPtr> exported = finder.exportedTypes(); + QHash<QString, QString> contextProperties = finder.contextProperties(); + if (exported.isEmpty() && contextProperties.isEmpty()) { + hasNewInfo = hasNewInfo || newData.remove(fileName) > 0; + } else { + CppData &data = newData[fileName]; + // currently we have no simple way to compare, so we assume the worse + hasNewInfo = true; + data.exportedTypes = exported; + data.contextProperties = contextProperties; + } + + doc->releaseSourceAndAST(); + } + + QMutexLocker locker(&qmlModelManager->m_cppDataMutex); + qmlModelManager->m_cppDataHash = newData; + if (hasNewInfo) + // one could get away with re-linking the cpp types... + QMetaObject::invokeMethod(qmlModelManager, "asyncReset"); +} + +ModelManagerInterface::CppDataHash ModelManagerInterface::cppData() const +{ + QMutexLocker locker(&m_cppDataMutex); + return m_cppDataHash; +} + +LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const +{ + QList<ProjectExplorer::Project *> projects = m_fileToProject.values(doc->fileName()); + + ProjectExplorer::Project *project = 0; + foreach (ProjectExplorer::Project *p, projects) { + if (p) { + project = p; + break; + } + } + + if (!project) + return LibraryInfo(); + + QMutexLocker locker(&m_mutex); + ProjectInfo info = m_projects.value(project); + if (!info.isValid()) + return LibraryInfo(); + + return _validSnapshot.libraryInfo(info.qtImportsPath); +} + +ViewerContext ModelManagerInterface::completeVContext(const ViewerContext &vCtx, + const Document::Ptr &doc) const +{ + Q_UNUSED(doc); + ViewerContext res = vCtx; + switch (res.flags) { + case ViewerContext::Complete: + break; + case ViewerContext::AddQtPath: + case ViewerContext::AddAllPaths: + res.paths << importPaths(); + } + res.flags = ViewerContext::Complete; + return res; +} + +ViewerContext ModelManagerInterface::defaultVContext(bool autoComplete, const Document::Ptr &doc) const +{ + if (autoComplete) + return completeVContext(m_vContext, doc); + else + return m_vContext; +} + +void ModelManagerInterface::setDefaultVContext(const ViewerContext &vContext) +{ + m_vContext = vContext; +} + +void ModelManagerInterface::joinAllThreads() +{ + foreach (QFuture<void> future, m_synchronizer.futures()) + future.waitForFinished(); +} + +void ModelManagerInterface::resetCodeModel() +{ + QStringList documents; + + { + QMutexLocker locker(&m_mutex); + + // find all documents currently in the code model + foreach (Document::Ptr doc, _validSnapshot) + documents.append(doc->fileName()); + + // reset the snapshot + _validSnapshot = Snapshot(); + _newestSnapshot = Snapshot(); + } + + // start a reparse thread + updateSourceFiles(documents, false); +} + +} // namespace QmlJS diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index 7d225f33a6..88463d36ca 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -31,21 +31,31 @@ #define QMLJSMODELMANAGERINTERFACE_H #include "qmljs_global.h" -#include "qmljsdocument.h" #include "qmljsbundle.h" #include "qmljsconstants.h" +#include "qmljsdocument.h" +#include "qmljsqrcparser.h" #include "qmljsviewercontext.h" + +#include <cplusplus/CppDocument.h> #include <utils/environment.h> +#include <QFuture> +#include <QFutureSynchronizer> +#include <QHash> +#include <QMultiHash> #include <QObject> -#include <QStringList> #include <QPointer> +#include <QStringList> +#include <QStringList> +#include <QTimer> namespace ProjectExplorer { class Project; } namespace QmlJS { class Snapshot; +class PluginDumper; class QMLJS_EXPORT ModelManagerInterface: public QObject { @@ -140,61 +150,130 @@ public: static Language::Enum guessLanguageOfFile(const QString &fileName); static QStringList globPatternsForLanguages(const QList<Language::Enum> languages); static ModelManagerInterface *instance(); - - virtual WorkingCopy workingCopy() const = 0; - - virtual QmlJS::Snapshot snapshot() const = 0; - virtual QmlJS::Snapshot newestSnapshot() const = 0; - - virtual void updateSourceFiles(const QStringList &files, - bool emitDocumentOnDiskChanged) = 0; - virtual void fileChangedOnDisk(const QString &path) = 0; - virtual void removeFiles(const QStringList &files) = 0; - virtual QStringList filesAtQrcPath(const QString &path, const QLocale *locale = 0, - ProjectExplorer::Project *project = 0, - QrcResourceSelector resources = AllQrcResources) = 0; - virtual QMap<QString,QStringList> filesInQrcPath(const QString &path, - const QLocale *locale = 0, - ProjectExplorer::Project *project = 0, - bool addDirs = false, - QrcResourceSelector resources = AllQrcResources) = 0; - - virtual QList<ProjectInfo> projectInfos() const = 0; - virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0; - virtual void updateProjectInfo(const ProjectInfo &pinfo) = 0; - Q_SLOT virtual void removeProjectInfo(ProjectExplorer::Project *project) = 0; - virtual ProjectInfo projectInfoForPath(QString path) = 0; - - virtual QStringList importPaths() const = 0; - virtual QmlJS::QmlLanguageBundles activeBundles() const = 0; - virtual QmlJS::QmlLanguageBundles extendedBundles() const = 0; - - virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath, - const QString &importUri, const QString &importVersion) = 0; - - virtual CppDataHash cppData() const = 0; - - virtual LibraryInfo builtins(const Document::Ptr &doc) const = 0; - + static void writeWarning(const QString &msg); + static WorkingCopy workingCopy(); + + QmlJS::Snapshot snapshot() const; + QmlJS::Snapshot newestSnapshot() const; + + void updateSourceFiles(const QStringList &files, + bool emitDocumentOnDiskChanged); + void fileChangedOnDisk(const QString &path); + void removeFiles(const QStringList &files); + QStringList filesAtQrcPath(const QString &path, const QLocale *locale = 0, + ProjectExplorer::Project *project = 0, + QrcResourceSelector resources = AllQrcResources); + QMap<QString,QStringList> filesInQrcPath(const QString &path, + const QLocale *locale = 0, + ProjectExplorer::Project *project = 0, + bool addDirs = false, + QrcResourceSelector resources = AllQrcResources); + + QList<ProjectInfo> projectInfos() const; + ProjectInfo projectInfo(ProjectExplorer::Project *project) const; + void updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p); + + void updateDocument(QmlJS::Document::Ptr doc); + void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info); + void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc); + void updateQrcFile(const QString &path); + ProjectInfo projectInfoForPath(QString path); + + QStringList importPaths() const; + QmlJS::QmlLanguageBundles activeBundles() const; + QmlJS::QmlLanguageBundles extendedBundles() const; + + void loadPluginTypes(const QString &libraryPath, const QString &importPath, + const QString &importUri, const QString &importVersion); + + CppDataHash cppData() const; + LibraryInfo builtins(const Document::Ptr &doc) const; virtual ViewerContext completeVContext(const ViewerContext &vCtx, - const Document::Ptr &doc = Document::Ptr(0)) const = 0; + const Document::Ptr &doc = Document::Ptr(0)) const; virtual ViewerContext defaultVContext(bool autoComplete = true, - const Document::Ptr &doc = Document::Ptr(0)) const = 0; - virtual void setDefaultVContext(const ViewerContext &vContext) = 0; + const Document::Ptr &doc = Document::Ptr(0)) const; + virtual void setDefaultVContext(const ViewerContext &vContext); // Blocks until all parsing threads are done. Used for testing. - virtual void joinAllThreads() = 0; -public slots: - virtual void resetCodeModel() = 0; + void joinAllThreads(); + virtual ModelManagerInterface::ProjectInfo defaultProjectInfo() const; + +public slots: + virtual void resetCodeModel(); + void removeProjectInfo(ProjectExplorer::Project *project); signals: void documentUpdated(QmlJS::Document::Ptr doc); void documentChangedOnDisk(QmlJS::Document::Ptr doc); void aboutToRemoveFiles(const QStringList &files); void libraryInfoUpdated(const QString &path, const QmlJS::LibraryInfo &info); void projectInfoUpdated(const ProjectInfo &pinfo); + void projectPathChanged(const QString &projectPath); +protected slots: + void maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc); + void queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc, bool scan); + void asyncReset(); + virtual void startCppQmlTypeUpdate(); protected: virtual QHash<QString,Language::Enum> languageForSuffix() const; + virtual void writeMessageInternal(const QString &msg) const; + virtual WorkingCopy workingCopyInternal() const; + virtual void addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const; + + QFuture<void> refreshSourceFiles(const QStringList &sourceFiles, + bool emitDocumentOnDiskChanged); + + static void parseLoop(QSet<QString> &scannedPaths, QSet<QString> &newLibraries, + WorkingCopy workingCopyInternal, QStringList files, ModelManagerInterface *modelManager, + QmlJS::Language::Enum mainLanguage, bool emitDocChangedOnDisk, + Utils::function<bool (qreal)> reportProgress); + static void parse(QFutureInterface<void> &future, + WorkingCopy workingCopyInternal, + QStringList files, + ModelManagerInterface *modelManager, + QmlJS::Language::Enum mainLanguage, + bool emitDocChangedOnDisk); + static void importScan(QFutureInterface<void> &future, + WorkingCopy workingCopyInternal, + QStringList paths, + ModelManagerInterface *modelManager, + QmlJS::Language::Enum mainLanguage, + bool emitDocChangedOnDisk); + static void updateCppQmlTypes(QFutureInterface<void> &interface, + ModelManagerInterface *qmlModelManager, + CPlusPlus::Snapshot snapshot, + QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents); + + void updateImportPaths(); + void loadQmlTypeDescriptionsInternal(const QString &path); + + mutable QMutex m_mutex; + QmlJS::Snapshot _validSnapshot; + QmlJS::Snapshot _newestSnapshot; + QStringList m_allImportPaths; + QStringList m_defaultImportPaths; + QmlJS::QmlLanguageBundles m_activeBundles; + QmlJS::QmlLanguageBundles m_extendedBundles; + QmlJS::ViewerContext m_vContext; + bool m_shouldScanImports; + QSet<QString> m_scannedPaths; + + QTimer *m_updateCppQmlTypesTimer; + QTimer *m_asyncResetTimer; + QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > m_queuedCppDocuments; + QFuture<void> m_cppQmlTypesUpdater; + QrcCache m_qrcCache; + + CppDataHash m_cppDataHash; + mutable QMutex m_cppDataMutex; + + // project integration + QMap<ProjectExplorer::Project *, ProjectInfo> m_projects; + QMultiHash<QString, ProjectExplorer::Project *> m_fileToProject; + + PluginDumper *m_pluginDumper; + + QFutureSynchronizer<void> m_synchronizer; }; } // namespace QmlJS diff --git a/src/plugins/qmljstools/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index cf99d00637..12df8f5d00 100644 --- a/src/plugins/qmljstools/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -28,11 +28,11 @@ ****************************************************************************/ #include "qmljsplugindumper.h" -#include "qmljsmodelmanager.h" +#include "qmljsmodelmanagerinterface.h" #include <qmljs/qmljsinterpreter.h> -#include <projectexplorer/session.h> -#include <coreplugin/messagemanager.h> +//#include <projectexplorer/session.h> +//#include <coreplugin/messagemanager.h> #include <utils/filesystemwatcher.h> #include <utils/fileutils.h> @@ -40,10 +40,8 @@ using namespace LanguageUtils; using namespace QmlJS; -using namespace QmlJSTools; -using namespace QmlJSTools::Internal; -PluginDumper::PluginDumper(ModelManager *modelManager) +PluginDumper::PluginDumper(ModelManagerInterface *modelManager) : QObject(modelManager) , m_modelManager(modelManager) , m_pluginWatcher(0) @@ -256,10 +254,9 @@ static QString qmldumpFailedMessage(const QString &libraryPath, const QString &e static void printParseWarnings(const QString &libraryPath, const QString &warning) { - Core::MessageManager::write( + ModelManagerInterface::writeWarning( PluginDumper::tr("Warnings while parsing qmltypes information of %1:\n" - "%2").arg(libraryPath, warning), - Core::MessageManager::Flash); + "%2").arg(libraryPath, warning)); } static QString qmlPluginDumpErrorMessage(QProcess *process) @@ -317,8 +314,7 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode) if (exitCode != 0) { const QString errorMessages = qmlPluginDumpErrorMessage(process); - Core::MessageManager::write(qmldumpErrorMessage(libraryPath, errorMessages), - Core::MessageManager::Flash); + ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages)); } @@ -360,8 +356,7 @@ void PluginDumper::qmlPluginTypeDumpError(QProcess::ProcessError) return; const QString errorMessages = qmlPluginDumpErrorMessage(process); - Core::MessageManager::write(qmldumpErrorMessage(libraryPath, errorMessages), - Core::MessageManager::Flash); + ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); if (!libraryPath.isEmpty()) { const Snapshot snapshot = m_modelManager->snapshot(); LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); @@ -442,11 +437,7 @@ void PluginDumper::dump(const Plugin &plugin) return; } - ProjectExplorer::Project *activeProject = ProjectExplorer::SessionManager::startupProject(); - if (!activeProject) - return; - - ModelManagerInterface::ProjectInfo info = m_modelManager->projectInfo(activeProject); + ModelManagerInterface::ProjectInfo info = m_modelManager->defaultProjectInfo(); if (!info.tryQmlDump || info.qmlDumpPath.isEmpty()) { const Snapshot snapshot = m_modelManager->snapshot(); diff --git a/src/plugins/qmljstools/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index a1567b7ab3..8c4a95c42e 100644 --- a/src/plugins/qmljstools/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -42,16 +42,13 @@ QT_END_NAMESPACE namespace Utils { class FileSystemWatcher; } -namespace QmlJSTools { -namespace Internal { - -class ModelManager; +namespace QmlJS { class PluginDumper : public QObject { Q_OBJECT public: - explicit PluginDumper(ModelManager *modelManager); + explicit PluginDumper(ModelManagerInterface *modelManager); public: void loadBuiltinTypes(const QmlJS::ModelManagerInterface::ProjectInfo &info); @@ -94,7 +91,7 @@ private: private: Utils::FileSystemWatcher *pluginWatcher(); - ModelManager *m_modelManager; + ModelManagerInterface *m_modelManager; Utils::FileSystemWatcher *m_pluginWatcher; QHash<QProcess *, QString> m_runningQmldumps; QList<Plugin> m_plugins; @@ -102,7 +99,6 @@ private: QHash<QString, QmlJS::ModelManagerInterface::ProjectInfo> m_qtToInfo; }; -} // namespace Internal -} // namespace QmlJSTools +} // namespace QmlJS #endif // QMLJSPLUGINDUMPER_H diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index f4a5329b33..5a0e96a369 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -999,7 +999,7 @@ void CppModelManager::enableGarbageCollector(bool enable) m_enableGC = enable; } -void CppModelManager::setExtraDiagnostics(const QString &fileName, +bool CppModelManager::setExtraDiagnostics(const QString &fileName, const QString &kind, const QList<Document::DiagnosticMessage> &diagnostics) { @@ -1013,9 +1013,10 @@ void CppModelManager::setExtraDiagnostics(const QString &fileName, foreach (CppEditorSupport *editorSupport, cppEditorSupports) { if (editorSupport->fileName() == fileName) { editorSupport->setExtraDiagnostics(kind, diagnostics); - break; + return true; } } + return false; } void CppModelManager::setIfdefedOutBlocks(const QString &fileName, diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 96a5796a2d..b7b192c530 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -107,7 +107,7 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o); virtual void renameMacroUsages(const CPlusPlus::Macro ¯o, const QString &replacement); - virtual void setExtraDiagnostics(const QString &fileName, const QString &key, + virtual bool setExtraDiagnostics(const QString &fileName, const QString &key, const QList<Document::DiagnosticMessage> &diagnostics); virtual void setIfdefedOutBlocks(const QString &fileName, const QList<TextEditor::BlockRange> &ifdeffedOutBlocks); diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.cpp b/src/plugins/cpptools/cppmodelmanagerinterface.cpp index e755783bef..0f65f16225 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.cpp +++ b/src/plugins/cpptools/cppmodelmanagerinterface.cpp @@ -164,8 +164,6 @@ void ProjectPart::evaluateToolchain(const ToolChain *tc, toolchainDefines = tc->predefinedMacros(cxxflags); } -static CppModelManagerInterface *g_instance = 0; - const QString CppModelManagerInterface::configurationFileName() { return CPlusPlus::Preprocessor::configurationFileName; } @@ -175,21 +173,15 @@ const QString CppModelManagerInterface::editorConfigurationFileName() } CppModelManagerInterface::CppModelManagerInterface(QObject *parent) - : QObject(parent) -{ - Q_ASSERT(!g_instance); - g_instance = this; -} + : CPlusPlus::CppModelManagerBase(parent) +{ } CppModelManagerInterface::~CppModelManagerInterface() -{ - Q_ASSERT(g_instance == this); - g_instance = 0; -} +{ } CppModelManagerInterface *CppModelManagerInterface::instance() { - return g_instance; + return qobject_cast<CppModelManagerInterface *>(CPlusPlus::CppModelManagerBase::instance()); } void CppModelManagerInterface::ProjectInfo::clearProjectParts() diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index 84cca908b7..188367c68a 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -35,6 +35,7 @@ #include "cppprojectfile.h" #include <cplusplus/CppDocument.h> +#include <cplusplus/cppmodelmanagerbase.h> #include <projectexplorer/toolchain.h> #include <QFuture> @@ -118,7 +119,7 @@ public: ProjectExplorer::ToolChain::WarningFlags cxxWarningFlags; }; -class CPPTOOLS_EXPORT CppModelManagerInterface : public QObject +class CPPTOOLS_EXPORT CppModelManagerInterface : public CPlusPlus::CppModelManagerBase { Q_OBJECT @@ -228,7 +229,6 @@ public: virtual WorkingCopy workingCopy() const = 0; virtual QByteArray codeModelConfiguration() const = 0; - virtual CPlusPlus::Snapshot snapshot() const = 0; virtual QList<ProjectInfo> projectInfos() const = 0; virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0; @@ -255,8 +255,6 @@ public: virtual void renameMacroUsages(const CPlusPlus::Macro ¯o, const QString &replacement = QString()) = 0; virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0; - virtual void setExtraDiagnostics(const QString &fileName, const QString &kind, - const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics) = 0; virtual void setIfdefedOutBlocks(const QString &fileName, const QList<TextEditor::BlockRange> &ifdeffedOutBlocks) = 0; diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 87f5fa205d..8a4e111278 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -671,7 +671,7 @@ void QbsProject::updateQmlJsCodeModel(const qbs::ProjectData &prj) QmlJSTools::defaultProjectInfoForProject(this); setProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS, !projectInfo.sourceFiles.isEmpty()); - modelManager->updateProjectInfo(projectInfo); + modelManager->updateProjectInfo(projectInfo, this); } void QbsProject::updateApplicationTargets(const qbs::ProjectData &projectData) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 6358d335ba..ec55f9f7c4 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -634,7 +634,7 @@ void QmakeProject::updateQmlJSCodeModel() setProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS, !projectInfo.sourceFiles.isEmpty()); - modelManager->updateProjectInfo(projectInfo); + modelManager->updateProjectInfo(projectInfo, this); } ///*! diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index edc1e633a7..61a16bcc9a 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -29,28 +29,28 @@ #include "qmljsmodelmanager.h" #include "qmljstoolsconstants.h" -#include "qmljsplugindumper.h" -#include "qmljsfindexportedcpptypes.h" #include "qmljssemanticinfo.h" #include "qmljsbundleprovider.h" #include <coreplugin/icore.h> -#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/messagemanager.h> +#include <coreplugin/progressmanager/progressmanager.h> #include <cpptools/cppmodelmanagerinterface.h> -#include <qmljs/qmljsbind.h> -#include <texteditor/basetextdocument.h> +#include <extensionsystem/pluginmanager.h> #include <projectexplorer/buildconfiguration.h> #include <projectexplorer/project.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/session.h> #include <projectexplorer/target.h> -#include <qtsupport/qtkitinformation.h> +#include <qmljs/qmljsbind.h> +#include <qmljs/qmljsfindexportedcpptypes.h> +#include <qmljs/qmljsplugindumper.h> #include <qtsupport/qmldumptool.h> +#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtsupportconstants.h> -#include <utils/hostosinfo.h> +#include <texteditor/basetextdocument.h> #include <utils/function.h> -#include <extensionsystem/pluginmanager.h> +#include <utils/hostosinfo.h> #include <QDir> #include <QFile> @@ -170,8 +170,6 @@ void QmlJSTools::setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo & } } -static QStringList environmentImportPaths(); - QHash<QString,QmlJS::Language::Enum> ModelManager::languageForSuffix() const { QHash<QString,QmlJS::Language::Enum> res = ModelManagerInterface::languageForSuffix(); @@ -197,30 +195,10 @@ QHash<QString,QmlJS::Language::Enum> ModelManager::languageForSuffix() const } ModelManager::ModelManager(QObject *parent): - ModelManagerInterface(parent), - m_shouldScanImports(false), - m_pluginDumper(new PluginDumper(this)) + ModelManagerInterface(parent) { - m_synchronizer.setCancelOnWait(true); - - m_updateCppQmlTypesTimer = new QTimer(this); - m_updateCppQmlTypesTimer->setInterval(1000); - m_updateCppQmlTypesTimer->setSingleShot(true); - connect(m_updateCppQmlTypesTimer, SIGNAL(timeout()), SLOT(startCppQmlTypeUpdate())); - - m_asyncResetTimer = new QTimer(this); - m_asyncResetTimer->setInterval(15000); - m_asyncResetTimer->setSingleShot(true); - connect(m_asyncResetTimer, SIGNAL(timeout()), SLOT(resetCodeModel())); - - qRegisterMetaType<QmlJS::Document::Ptr>("QmlJS::Document::Ptr"); - qRegisterMetaType<QmlJS::LibraryInfo>("QmlJS::LibraryInfo"); qRegisterMetaType<QmlJSTools::SemanticInfo>("QmlJSTools::SemanticInfo"); - - loadQmlTypeDescriptions(); - - m_defaultImportPaths << environmentImportPaths(); - updateImportPaths(); + loadDefaultQmlTypeDescriptions(); } ModelManager::~ModelManager() @@ -244,49 +222,20 @@ void ModelManager::delayedInitialization() this, SLOT(removeProjectInfo(ProjectExplorer::Project*))); } -void ModelManager::loadQmlTypeDescriptions() +void ModelManager::loadDefaultQmlTypeDescriptions() { if (ICore::instance()) { - loadQmlTypeDescriptions(ICore::resourcePath()); - loadQmlTypeDescriptions(ICore::userResourcePath()); + loadQmlTypeDescriptionsInternal(ICore::resourcePath()); + loadQmlTypeDescriptionsInternal(ICore::userResourcePath()); } } -void ModelManager::loadQmlTypeDescriptions(const QString &resourcePath) +void ModelManager::writeMessageInternal(const QString &msg) const { - const QDir typeFileDir(resourcePath + QLatin1String("/qml-type-descriptions")); - const QStringList qmlTypesExtensions = QStringList() << QLatin1String("*.qmltypes"); - QFileInfoList qmlTypesFiles = typeFileDir.entryInfoList( - qmlTypesExtensions, - QDir::Files, - QDir::Name); - - QStringList errors; - QStringList warnings; - - // filter out the actual Qt builtins - for (int i = 0; i < qmlTypesFiles.size(); ++i) { - if (qmlTypesFiles.at(i).baseName() == QLatin1String("builtins")) { - QFileInfoList list; - list.append(qmlTypesFiles.at(i)); - CppQmlTypesLoader::defaultQtObjects = - CppQmlTypesLoader::loadQmlTypes(list, &errors, &warnings); - qmlTypesFiles.removeAt(i); - break; - } - } - - // load the fallbacks for libraries - CppQmlTypesLoader::defaultLibraryObjects.unite( - CppQmlTypesLoader::loadQmlTypes(qmlTypesFiles, &errors, &warnings)); - - foreach (const QString &error, errors) - MessageManager::write(error, MessageManager::Flash); - foreach (const QString &warning, warnings) - MessageManager::write(warning, MessageManager::Flash); + MessageManager::write(msg, MessageManager::Flash); } -ModelManagerInterface::WorkingCopy ModelManager::workingCopy() const +ModelManagerInterface::WorkingCopy ModelManager::workingCopyInternal() const { WorkingCopy workingCopy; DocumentModel *documentModel = EditorManager::documentModel(); @@ -302,691 +251,13 @@ ModelManagerInterface::WorkingCopy ModelManager::workingCopy() const return workingCopy; } -Snapshot ModelManager::snapshot() const -{ - QMutexLocker locker(&m_mutex); - return _validSnapshot; -} - -Snapshot ModelManager::newestSnapshot() const -{ - QMutexLocker locker(&m_mutex); - return _newestSnapshot; -} - -void ModelManager::updateSourceFiles(const QStringList &files, - bool emitDocumentOnDiskChanged) -{ - refreshSourceFiles(files, emitDocumentOnDiskChanged); -} - -QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles, - bool emitDocumentOnDiskChanged) -{ - if (sourceFiles.isEmpty()) - return QFuture<void>(); - - QFuture<void> result = QtConcurrent::run(&ModelManager::parse, - workingCopy(), sourceFiles, - this, Language::Qml, - emitDocumentOnDiskChanged); - - if (m_synchronizer.futures().size() > 10) { - QList<QFuture<void> > futures = m_synchronizer.futures(); - - m_synchronizer.clearFutures(); - - foreach (const QFuture<void> &future, futures) { - if (! (future.isFinished() || future.isCanceled())) - m_synchronizer.addFuture(future); - } - } - - m_synchronizer.addFuture(result); - - if (sourceFiles.count() > 1) - ProgressManager::addTask(result, tr("Indexing"), Constants::TASK_INDEX); - - if (sourceFiles.count() > 1 && !m_shouldScanImports) { - bool scan = false; - { - QMutexLocker l(&m_mutex); - if (!m_shouldScanImports) { - m_shouldScanImports = true; - scan = true; - } - } - if (scan) - updateImportPaths(); - } - - - return result; -} - -void ModelManager::fileChangedOnDisk(const QString &path) -{ - QtConcurrent::run(&ModelManager::parse, - workingCopy(), QStringList() << path, - this, Language::Unknown, true); -} - -void ModelManager::removeFiles(const QStringList &files) -{ - emit aboutToRemoveFiles(files); - - QMutexLocker locker(&m_mutex); - - foreach (const QString &file, files) { - _validSnapshot.remove(file); - _newestSnapshot.remove(file); - } -} - -namespace { -bool pInfoLessThanActive(const ModelManager::ProjectInfo &p1, const ModelManager::ProjectInfo &p2) -{ - QStringList s1 = p1.activeResourceFiles; - QStringList s2 = p2.activeResourceFiles; - if (s1.size() < s2.size()) - return true; - if (s1.size() > s2.size()) - return false; - for (int i = 0; i < s1.size(); ++i) { - if (s1.at(i) < s2.at(i)) - return true; - else if (s1.at(i) > s2.at(i)) - return false; - } - return false; -} - -bool pInfoLessThanAll(const ModelManager::ProjectInfo &p1, const ModelManager::ProjectInfo &p2) -{ - QStringList s1 = p1.allResourceFiles; - QStringList s2 = p2.allResourceFiles; - if (s1.size() < s2.size()) - return true; - if (s1.size() > s2.size()) - return false; - for (int i = 0; i < s1.size(); ++i) { - if (s1.at(i) < s2.at(i)) - return true; - else if (s1.at(i) > s2.at(i)) - return false; - } - return false; -} -} - -QStringList ModelManager::filesAtQrcPath(const QString &path, const QLocale *locale, - ProjectExplorer::Project *project, - QrcResourceSelector resources) -{ - QString normPath = QrcParser::normalizedQrcFilePath(path); - QList<ProjectInfo> pInfos; - if (project) - pInfos.append(projectInfo(project)); - else - pInfos = projectInfos(); - - QStringList res; - QSet<QString> pathsChecked; - foreach (const ModelManager::ProjectInfo &pInfo, pInfos) { - QStringList qrcFilePaths; - if (resources == ActiveQrcResources) - qrcFilePaths = pInfo.activeResourceFiles; - else - qrcFilePaths = pInfo.allResourceFiles; - foreach (const QString &qrcFilePath, qrcFilePaths) { - if (pathsChecked.contains(qrcFilePath)) - continue; - pathsChecked.insert(qrcFilePath); - QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath); - if (qrcFile.isNull()) - continue; - qrcFile->collectFilesAtPath(normPath, &res, locale); - } - } - res.sort(); // make the result predictable - return res; -} - -QMap<QString, QStringList> ModelManager::filesInQrcPath(const QString &path, - const QLocale *locale, - ProjectExplorer::Project *project, - bool addDirs, - QrcResourceSelector resources) +ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfo() const { - QString normPath = QrcParser::normalizedQrcDirectoryPath(path); - QList<ProjectInfo> pInfos; - if (project) { - pInfos.append(projectInfo(project)); - } else { - pInfos = projectInfos(); - if (resources == ActiveQrcResources) // make the result predictable - qSort(pInfos.begin(), pInfos.end(), &pInfoLessThanActive); - else - qSort(pInfos.begin(), pInfos.end(), &pInfoLessThanAll); - } - QMap<QString, QStringList> res; - QSet<QString> pathsChecked; - foreach (const ModelManager::ProjectInfo &pInfo, pInfos) { - QStringList qrcFilePaths; - if (resources == ActiveQrcResources) - qrcFilePaths = pInfo.activeResourceFiles; - else - qrcFilePaths = pInfo.allResourceFiles; - foreach (const QString &qrcFilePath, qrcFilePaths) { - if (pathsChecked.contains(qrcFilePath)) - continue; - pathsChecked.insert(qrcFilePath); - QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath); - - if (qrcFile.isNull()) - continue; - qrcFile->collectFilesInPath(normPath, &res, addDirs, locale); - } - } - return res; -} - -QList<ModelManager::ProjectInfo> ModelManager::projectInfos() const -{ - QMutexLocker locker(&m_mutex); - - return m_projects.values(); -} - -ModelManager::ProjectInfo ModelManager::projectInfo(ProjectExplorer::Project *project) const -{ - QMutexLocker locker(&m_mutex); - - return m_projects.value(project, ProjectInfo(project)); -} - -void ModelManager::updateProjectInfo(const ProjectInfo &pinfo) -{ - if (! pinfo.isValid()) - return; - - Snapshot snapshot; - ProjectInfo oldInfo; - { - QMutexLocker locker(&m_mutex); - oldInfo = m_projects.value(pinfo.project); - m_projects.insert(pinfo.project, pinfo); - snapshot = _validSnapshot; - } - - if (oldInfo.qmlDumpPath != pinfo.qmlDumpPath - || oldInfo.qmlDumpEnvironment != pinfo.qmlDumpEnvironment) { - m_pluginDumper->scheduleRedumpPlugins(); - m_pluginDumper->scheduleMaybeRedumpBuiltins(pinfo); - } - - - updateImportPaths(); - - // remove files that are no longer in the project and have been deleted - QStringList deletedFiles; - foreach (const QString &oldFile, oldInfo.sourceFiles) { - if (snapshot.document(oldFile) - && !pinfo.sourceFiles.contains(oldFile) - && !QFile::exists(oldFile)) { - deletedFiles += oldFile; - } - } - removeFiles(deletedFiles); - - // parse any files not yet in the snapshot - QStringList newFiles; - foreach (const QString &file, pinfo.sourceFiles) { - if (!snapshot.document(file)) - newFiles += file; - } - updateSourceFiles(newFiles, false); - - // update qrc cache - foreach (const QString &newQrc, pinfo.allResourceFiles) - m_qrcCache.addPath(newQrc); - foreach (const QString &oldQrc, oldInfo.allResourceFiles) - m_qrcCache.removePath(oldQrc); - - // dump builtin types if the shipped definitions are probably outdated and the - // Qt version ships qmlplugindump - if (QtSupport::QtVersionNumber(pinfo.qtVersionString) > QtSupport::QtVersionNumber(4, 8, 5)) - m_pluginDumper->loadBuiltinTypes(pinfo); - - emit projectInfoUpdated(pinfo); -} - - -void ModelManager::removeProjectInfo(ProjectExplorer::Project *project) -{ - ProjectInfo info(project); - info.sourceFiles.clear(); - // update with an empty project info to clear data - updateProjectInfo(info); - - { - QMutexLocker locker(&m_mutex); - m_projects.remove(project); - } -} + ProjectExplorer::Project *activeProject = ProjectExplorer::SessionManager::startupProject(); + if (!activeProject) + return ModelManagerInterface::ProjectInfo(); -ModelManagerInterface::ProjectInfo ModelManager::projectInfoForPath(QString path) -{ - QMutexLocker locker(&m_mutex); - - foreach (const ProjectInfo &p, m_projects) - if (p.sourceFiles.contains(path)) - return p; - return ProjectInfo(); -} - -void ModelManager::emitDocumentChangedOnDisk(Document::Ptr doc) -{ emit documentChangedOnDisk(doc); } - -void ModelManager::updateQrcFile(const QString &path) -{ - m_qrcCache.updatePath(path); -} - -void ModelManager::updateDocument(Document::Ptr doc) -{ - { - QMutexLocker locker(&m_mutex); - _validSnapshot.insert(doc); - _newestSnapshot.insert(doc, true); - } - emit documentUpdated(doc); -} - -void ModelManager::updateLibraryInfo(const QString &path, const LibraryInfo &info) -{ - if (!info.pluginTypeInfoError().isEmpty()) - qDebug() << "Dumping errors for " << path << ":" << info.pluginTypeInfoError(); - - { - QMutexLocker locker(&m_mutex); - _validSnapshot.insertLibraryInfo(path, info); - _newestSnapshot.insertLibraryInfo(path, info); - } - // only emit if we got new useful information - if (info.isValid()) - emit libraryInfoUpdated(path, info); -} - -static QStringList filesInDirectoryForLanguages(const QString &path, QList<Language::Enum> languages) -{ - const QStringList pattern = ModelManagerInterface::globPatternsForLanguages(languages); - QStringList files; - - const QDir dir(path); - foreach (const QFileInfo &fi, dir.entryInfoList(pattern, QDir::Files)) - files += fi.absoluteFilePath(); - - return files; -} - -static void findNewImplicitImports(const Document::Ptr &doc, const Snapshot &snapshot, - QStringList *importedFiles, QSet<QString> *scannedPaths) -{ - // scan files that could be implicitly imported - // it's important we also do this for JS files, otherwise the isEmpty check will fail - if (snapshot.documentsInDirectory(doc->path()).isEmpty()) { - if (! scannedPaths->contains(doc->path())) { - *importedFiles += filesInDirectoryForLanguages(doc->path(), - Document::companionLanguages(doc->language())); - scannedPaths->insert(doc->path()); - } - } -} - -static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapshot, - QStringList *importedFiles, QSet<QString> *scannedPaths) -{ - // scan files and directories that are explicitly imported - foreach (const ImportInfo &import, doc->bind()->imports()) { - const QString &importName = import.path(); - if (import.type() == ImportType::File) { - if (! snapshot.document(importName)) - *importedFiles += importName; - } else if (import.type() == ImportType::Directory) { - if (snapshot.documentsInDirectory(importName).isEmpty()) { - if (! scannedPaths->contains(importName)) { - *importedFiles += filesInDirectoryForLanguages(importName, - Document::companionLanguages(doc->language())); - scannedPaths->insert(importName); - } - } - } else if (import.type() == ImportType::QrcFile) { - QStringList importPaths = ModelManagerInterface::instance()->filesAtQrcPath(importName); - foreach (const QString &importPath, importPaths) { - if (! snapshot.document(importPath)) - *importedFiles += importPath; - } - } else if (import.type() == ImportType::QrcDirectory) { - QMapIterator<QString,QStringList> dirContents(ModelManagerInterface::instance()->filesInQrcPath(importName)); - while (dirContents.hasNext()) { - dirContents.next(); - if (Document::isQmlLikeOrJsLanguage(ModelManagerInterface::guessLanguageOfFile(dirContents.key()))) { - foreach (const QString &filePath, dirContents.value()) { - if (! snapshot.document(filePath)) - *importedFiles += filePath; - } - } - } - } - } -} - -static bool findNewQmlLibraryInPath(const QString &path, - const Snapshot &snapshot, - ModelManager *modelManager, - QStringList *importedFiles, - QSet<QString> *scannedPaths, - QSet<QString> *newLibraries, - bool ignoreMissing) -{ - // if we know there is a library, done - 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 (!ignoreMissing) { - LibraryInfo libraryInfo(LibraryInfo::NotFound); - modelManager->updateLibraryInfo(path, libraryInfo); - } - return false; - } - - if (Utils::HostOsInfo::isWindowsHost()) { - // QTCREATORBUG-3402 - be case sensitive even here? - } - - // found a new library! - qmldirFile.open(QFile::ReadOnly); - QString qmldirData = QString::fromUtf8(qmldirFile.readAll()); - - QmlDirParser qmldirParser; - qmldirParser.parse(qmldirData); - - const QString libraryPath = QFileInfo(qmldirFile).absolutePath(); - newLibraries->insert(libraryPath); - modelManager->updateLibraryInfo(libraryPath, LibraryInfo(qmldirParser)); - - // scan the qml files in the library - foreach (const QmlDirParser::Component &component, qmldirParser.components()) { - if (! component.fileName.isEmpty()) { - const QFileInfo componentFileInfo(dir.filePath(component.fileName)); - const QString path = QDir::cleanPath(componentFileInfo.absolutePath()); - if (! scannedPaths->contains(path)) { - *importedFiles += filesInDirectoryForLanguages(path, - Document::companionLanguages(Language::Unknown)); - scannedPaths->insert(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::fromLatin1("%1.%2.%3").arg( - path, - QString::number(version.majorVersion()), - QString::number(version.minorVersion())); - findNewQmlLibraryInPath( - libraryPath, snapshot, modelManager, - importedFiles, scannedPaths, newLibraries, false); - - libraryPath = QString::fromLatin1("%1.%2").arg( - path, - QString::number(version.majorVersion())); - findNewQmlLibraryInPath( - libraryPath, snapshot, modelManager, - importedFiles, scannedPaths, newLibraries, false); - - findNewQmlLibraryInPath( - path, snapshot, modelManager, - importedFiles, scannedPaths, newLibraries, false); -} - -static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot, - ModelManager *modelManager, - QStringList *importedFiles, QSet<QString> *scannedPaths, QSet<QString> *newLibraries) -{ - // scan current dir - findNewQmlLibraryInPath(doc->path(), snapshot, modelManager, - importedFiles, scannedPaths, newLibraries, false); - - // scan dir and lib imports - const QStringList importPaths = modelManager->importPaths(); - foreach (const ImportInfo &import, doc->bind()->imports()) { - if (import.type() == ImportType::Directory) { - const QString targetPath = import.path(); - findNewQmlLibraryInPath(targetPath, snapshot, modelManager, - importedFiles, scannedPaths, newLibraries, false); - } - - if (import.type() == ImportType::Library) { - if (!import.version().isValid()) - continue; - foreach (const QString &importPath, importPaths) { - const QString targetPath = QDir(importPath).filePath(import.path()); - findNewQmlLibrary(targetPath, import.version(), snapshot, modelManager, - importedFiles, scannedPaths, newLibraries); - } - } - } -} - -void ModelManager::parseLoop(QSet<QString> &scannedPaths, - QSet<QString> &newLibraries, - WorkingCopy workingCopy, - QStringList files, - ModelManager *modelManager, - Language::Enum mainLanguage, - bool emitDocChangedOnDisk, - Utils::function<bool(qreal)> reportProgress) -{ - for (int i = 0; i < files.size(); ++i) { - if (!reportProgress(qreal(i) / files.size())) - return; - - const QString fileName = files.at(i); - - Language::Enum language = guessLanguageOfFile(fileName); - if (language == Language::Unknown) { - if (fileName.endsWith(QLatin1String(".qrc"))) - modelManager->updateQrcFile(fileName); - continue; - } - if (language == Language::Qml - && (mainLanguage == Language::QmlQtQuick1 || Language::QmlQtQuick2)) - language = mainLanguage; - QString contents; - int documentRevision = 0; - - if (workingCopy.contains(fileName)) { - QPair<QString, int> entry = workingCopy.get(fileName); - contents = entry.first; - documentRevision = entry.second; - } else { - QFile inFile(fileName); - - if (inFile.open(QIODevice::ReadOnly)) { - QTextStream ins(&inFile); - contents = ins.readAll(); - inFile.close(); - } - } - - Document::MutablePtr doc = Document::create(fileName, language); - doc->setEditorRevision(documentRevision); - 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); - findNewFileImports(doc, snapshot, &importedFiles, &scannedPaths); - findNewLibraryImports(doc, snapshot, modelManager, &importedFiles, &scannedPaths, &newLibraries); - - // add new files to parse list - foreach (const QString &file, importedFiles) { - if (! files.contains(file)) - files.append(file); - } - - modelManager->updateDocument(doc); - if (emitDocChangedOnDisk) - 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()); - { - QMutexLocker l(&modelManager->m_mutex); - foreach (const QString &path, paths) { - QString cPath = QDir::cleanPath(path); - if (modelManager->m_scannedPaths.contains(cPath)) - continue; - pathsToScan.append(ScanItem(cPath)); - modelManager->m_scannedPaths.insert(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 - const Snapshot snapshot = modelManager->snapshot(); - while (!pathsToScan.isEmpty() && !future.isCanceled()) { - ScanItem toScan = pathsToScan.last(); - pathsToScan.pop_back(); - int pathBudget = (maxScanDepth + 2 - toScan.depth); - if (!scannedPaths.contains(toScan.path)) { - QStringList importedFiles; - if (!findNewQmlLibraryInPath(toScan.path, snapshot, modelManager, &importedFiles, - &scannedPaths, &newLibraries, true) - && !libOnly && snapshot.documentsInDirectory(toScan.path).isEmpty()) - importedFiles += filesInDirectoryForLanguages(toScan.path, - Document::companionLanguages(language)); - workDone += 1; - future.setProgressValue(progressRange * workDone / totalWork); - if (!importedFiles.isEmpty()) { - FutureReporter reporter(future, progressRange * pathBudget / (4 * totalWork), - progressRange * workDone / totalWork); - parseLoop(scannedPaths, newLibraries, workingCopy, importedFiles, modelManager, - language, emitDocChangedOnDisk, reporter); // run in parallel?? - importedFiles.clear(); - } - workDone += pathBudget / 4 - 1; - future.setProgressValue(progressRange * workDone / totalWork); - } else { - workDone += pathBudget / 4; - } - // always descend tree, as we might have just scanned with a smaller depth - if (toScan.depth < maxScanDepth) { - QDir dir(toScan.path); - QStringList subDirs(dir.entryList(QDir::Dirs)); - workDone += 1; - totalWork += pathBudget / 2 * subDirs.size() - pathBudget * 3 / 4 + 1; - foreach (const QString path, subDirs) - pathsToScan.append(ScanItem(dir.absoluteFilePath(path), toScan.depth + 1)); - } else { - workDone += pathBudget *3 / 4; - } - future.setProgressValue(progressRange * workDone / totalWork); - } - future.setProgressValue(progressRange); - if (future.isCanceled()) { - // assume no work has been done - QMutexLocker l(&modelManager->m_mutex); - foreach (const QString &path, paths) - modelManager->m_scannedPaths.remove(path); - } + return projectInfo(activeProject); } // Check whether fileMimeType is the same or extends knownMimeType @@ -1006,312 +277,8 @@ bool ModelManager::matchesMimeType(const MimeType &fileMimeType, const MimeType return false; } -QStringList ModelManager::importPaths() const -{ - QMutexLocker l(&m_mutex); - return m_allImportPaths; -} - -QmlLanguageBundles ModelManager::activeBundles() const -{ - QMutexLocker l(&m_mutex); - return m_activeBundles; -} - -QmlLanguageBundles ModelManager::extendedBundles() const +void ModelManager::addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const { - QMutexLocker l(&m_mutex); - return m_extendedBundles; + ProgressManager::addTask(result, msg, taskId); } -static QStringList environmentImportPaths() -{ - QStringList paths; - - QByteArray envImportPath = qgetenv("QML_IMPORT_PATH"); - - foreach (const QString &path, QString::fromLatin1(envImportPath) - .split(Utils::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts)) { - QString canonicalPath = QDir(path).canonicalPath(); - if (!canonicalPath.isEmpty() && !paths.contains(canonicalPath)) - paths.append(canonicalPath); - } - - return paths; -} - -void ModelManager::updateImportPaths() -{ - QStringList allImportPaths; - QmlLanguageBundles activeBundles; - QmlLanguageBundles extendedBundles; - QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); - while (it.hasNext()) { - it.next(); - foreach (const QString &path, it.value().importPaths) { - const QString canonicalPath = QFileInfo(path).canonicalFilePath(); - if (!canonicalPath.isEmpty()) - allImportPaths += canonicalPath; - } - } - it.toFront(); - while (it.hasNext()) { - it.next(); - activeBundles.mergeLanguageBundles(it.value().activeBundle); - foreach (Language::Enum l, it.value().activeBundle.languages()) { - foreach (const QString &path, it.value().activeBundle.bundleForLanguage(l) - .searchPaths().stringList()) { - const QString canonicalPath = QFileInfo(path).canonicalFilePath(); - if (!canonicalPath.isEmpty()) - allImportPaths += canonicalPath; - } - } - } - it.toFront(); - while (it.hasNext()) { - it.next(); - extendedBundles.mergeLanguageBundles(it.value().extendedBundle); - foreach (Language::Enum l, it.value().extendedBundle.languages()) { - foreach (const QString &path, it.value().extendedBundle.bundleForLanguage(l) - .searchPaths().stringList()) { - const QString canonicalPath = QFileInfo(path).canonicalFilePath(); - if (!canonicalPath.isEmpty()) - allImportPaths += canonicalPath; - } - } - } - allImportPaths += m_defaultImportPaths; - allImportPaths.removeDuplicates(); - - { - QMutexLocker l(&m_mutex); - m_allImportPaths = allImportPaths; - m_activeBundles = activeBundles; - m_extendedBundles = extendedBundles; - } - - - // check if any file in the snapshot imports something new in the new paths - Snapshot snapshot = _validSnapshot; - QStringList importedFiles; - QSet<QString> scannedPaths; - QSet<QString> newLibraries; - foreach (const Document::Ptr &doc, snapshot) - findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries); - - updateSourceFiles(importedFiles, true); - - if (!m_shouldScanImports) - return; - QStringList pathToScan; - { - QMutexLocker l(&m_mutex); - foreach (QString importPath, allImportPaths) - if (!m_scannedPaths.contains(importPath)) { - pathToScan.append(importPath); - } - } - - if (pathToScan.count() > 1) { - QFuture<void> result = QtConcurrent::run(&ModelManager::importScan, - workingCopy(), pathToScan, - this, Language::Qml, - true); - - if (m_synchronizer.futures().size() > 10) { - QList<QFuture<void> > futures = m_synchronizer.futures(); - - m_synchronizer.clearFutures(); - - foreach (const QFuture<void> &future, futures) { - if (! (future.isFinished() || future.isCanceled())) - m_synchronizer.addFuture(future); - } - } - - m_synchronizer.addFuture(result); - - ProgressManager::addTask(result, tr("Qml import scan"), Constants::TASK_IMPORT_SCAN); - } -} - -void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &importPath, - const QString &importUri, const QString &importVersion) -{ - m_pluginDumper->loadPluginTypes(libraryPath, importPath, importUri, importVersion); -} - -// is called *inside a c++ parsing thread*, to allow hanging on to source and ast -void ModelManager::maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc) -{ - // avoid scanning documents without source code available - doc->keepSourceAndAST(); - if (doc->utf8Source().isEmpty()) { - doc->releaseSourceAndAST(); - return; - } - - // keep source and AST alive if we want to scan for register calls - const bool scan = FindExportedCppTypes::maybeExportsTypes(doc); - if (!scan) - doc->releaseSourceAndAST(); - - // delegate actual queuing to the gui thread - QMetaObject::invokeMethod(this, "queueCppQmlTypeUpdate", - Q_ARG(CPlusPlus::Document::Ptr, doc), Q_ARG(bool, scan)); -} - -void ModelManager::queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc, bool scan) -{ - QPair<CPlusPlus::Document::Ptr, bool> prev = m_queuedCppDocuments.value(doc->fileName()); - if (prev.first && prev.second) - prev.first->releaseSourceAndAST(); - m_queuedCppDocuments.insert(doc->fileName(), qMakePair(doc, scan)); - m_updateCppQmlTypesTimer->start(); -} - -void ModelManager::startCppQmlTypeUpdate() -{ - // if a future is still running, delay - if (m_cppQmlTypesUpdater.isRunning()) { - m_updateCppQmlTypesTimer->start(); - return; - } - - CppTools::CppModelManagerInterface *cppModelManager = - CppTools::CppModelManagerInterface::instance(); - if (!cppModelManager) - return; - - m_cppQmlTypesUpdater = QtConcurrent::run( - &ModelManager::updateCppQmlTypes, - this, cppModelManager->snapshot(), m_queuedCppDocuments); - m_queuedCppDocuments.clear(); -} - -void ModelManager::asyncReset() -{ - m_asyncResetTimer->start(); -} - -void ModelManager::updateCppQmlTypes(QFutureInterface<void> &interface, - ModelManager *qmlModelManager, - CPlusPlus::Snapshot snapshot, - QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents) -{ - CppDataHash newData = qmlModelManager->cppData(); - - FindExportedCppTypes finder(snapshot); - - bool hasNewInfo = false; - typedef QPair<CPlusPlus::Document::Ptr, bool> DocScanPair; - foreach (const DocScanPair &pair, documents) { - if (interface.isCanceled()) - return; - - CPlusPlus::Document::Ptr doc = pair.first; - const bool scan = pair.second; - const QString fileName = doc->fileName(); - if (!scan) { - hasNewInfo = hasNewInfo || newData.remove(fileName) > 0; - continue; - } - - finder(doc); - - QList<LanguageUtils::FakeMetaObject::ConstPtr> exported = finder.exportedTypes(); - QHash<QString, QString> contextProperties = finder.contextProperties(); - if (exported.isEmpty() && contextProperties.isEmpty()) { - hasNewInfo = hasNewInfo || newData.remove(fileName) > 0; - } else { - CppData &data = newData[fileName]; - // currently we have no simple way to compare, so we assume the worse - hasNewInfo = true; - data.exportedTypes = exported; - data.contextProperties = contextProperties; - } - - doc->releaseSourceAndAST(); - } - - QMutexLocker locker(&qmlModelManager->m_cppDataMutex); - qmlModelManager->m_cppDataHash = newData; - if (hasNewInfo) - // one could get away with re-linking the cpp types... - QMetaObject::invokeMethod(qmlModelManager, "asyncReset"); -} - -ModelManager::CppDataHash ModelManager::cppData() const -{ - QMutexLocker locker(&m_cppDataMutex); - return m_cppDataHash; -} - -LibraryInfo ModelManager::builtins(const Document::Ptr &doc) const -{ - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(doc->fileName()); - if (!project) - return LibraryInfo(); - - QMutexLocker locker(&m_mutex); - ProjectInfo info = m_projects.value(project); - if (!info.isValid()) - return LibraryInfo(); - - return _validSnapshot.libraryInfo(info.qtImportsPath); -} - -ViewerContext ModelManager::completeVContext(const ViewerContext &vCtx, - const Document::Ptr &doc) const -{ - Q_UNUSED(doc); - ViewerContext res = vCtx; - switch (res.flags) { - case ViewerContext::Complete: - break; - case ViewerContext::AddQtPath: - case ViewerContext::AddAllPaths: - res.paths << importPaths(); - } - res.flags = ViewerContext::Complete; - return res; -} - -ViewerContext ModelManager::defaultVContext(bool autoComplete, const Document::Ptr &doc) const -{ - if (autoComplete) - return completeVContext(m_vContext, doc); - else - return m_vContext; -} - -void ModelManager::setDefaultVContext(const ViewerContext &vContext) -{ - m_vContext = vContext; -} - -void ModelManager::joinAllThreads() -{ - foreach (QFuture<void> future, m_synchronizer.futures()) - future.waitForFinished(); -} - -void ModelManager::resetCodeModel() -{ - QStringList documents; - - { - QMutexLocker locker(&m_mutex); - - // find all documents currently in the code model - foreach (Document::Ptr doc, _validSnapshot) - documents.append(doc->fileName()); - - // reset the snapshot - _validSnapshot = Snapshot(); - _newestSnapshot = Snapshot(); - } - - // start a reparse thread - updateSourceFiles(documents, false); -} diff --git a/src/plugins/qmljstools/qmljsmodelmanager.h b/src/plugins/qmljstools/qmljsmodelmanager.h index ac60ea106c..2b8233a66f 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.h +++ b/src/plugins/qmljstools/qmljsmodelmanager.h @@ -67,129 +67,15 @@ public: ~ModelManager(); void delayedInitialization(); - - WorkingCopy workingCopy() const QTC_OVERRIDE; - QmlJS::Snapshot snapshot() const QTC_OVERRIDE; - QmlJS::Snapshot newestSnapshot() const QTC_OVERRIDE; - - void updateSourceFiles(const QStringList &files, - bool emitDocumentOnDiskChanged) QTC_OVERRIDE; - void fileChangedOnDisk(const QString &path) QTC_OVERRIDE; - void removeFiles(const QStringList &files) QTC_OVERRIDE; - QStringList filesAtQrcPath(const QString &path, const QLocale *locale = 0, - ProjectExplorer::Project *project = 0, - QrcResourceSelector resources = AllQrcResources) QTC_OVERRIDE; - QMap<QString,QStringList> filesInQrcPath(const QString &path, - const QLocale *locale = 0, - ProjectExplorer::Project *project = 0, - bool addDirs = false, - QrcResourceSelector resources = AllQrcResources) QTC_OVERRIDE; - - QList<ProjectInfo> projectInfos() const QTC_OVERRIDE; - ProjectInfo projectInfo(ProjectExplorer::Project *project) const QTC_OVERRIDE; - void updateProjectInfo(const ProjectInfo &pinfo) QTC_OVERRIDE; - Q_SLOT virtual void removeProjectInfo(ProjectExplorer::Project *project); - virtual ProjectInfo projectInfoForPath(QString path); - - void updateDocument(QmlJS::Document::Ptr doc); - void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info); - void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc); - void updateQrcFile(const QString &path); - - QStringList importPaths() const QTC_OVERRIDE; - QmlJS::QmlLanguageBundles activeBundles() const QTC_OVERRIDE; - QmlJS::QmlLanguageBundles extendedBundles() const QTC_OVERRIDE; - - void loadPluginTypes(const QString &libraryPath, const QString &importPath, - const QString &importUri, const QString &importVersion) QTC_OVERRIDE; - - CppDataHash cppData() const QTC_OVERRIDE; - - QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &doc) const QTC_OVERRIDE; - - QmlJS::ViewerContext completeVContext( - const QmlJS::ViewerContext &vCtx, - const QmlJS::Document::Ptr &doc = QmlJS::Document::Ptr(0)) const QTC_OVERRIDE; - QmlJS::ViewerContext defaultVContext( - bool autoComplete = true, - const QmlJS::Document::Ptr &doc = QmlJS::Document::Ptr(0)) const QTC_OVERRIDE; - void setDefaultVContext(const QmlJS::ViewerContext &vContext) QTC_OVERRIDE; - - void joinAllThreads() QTC_OVERRIDE; - -public slots: - void resetCodeModel() QTC_OVERRIDE; - -Q_SIGNALS: - void projectPathChanged(const QString &projectPath); - protected: - QFuture<void> refreshSourceFiles(const QStringList &sourceFiles, - bool emitDocumentOnDiskChanged); - - static void parseLoop(QSet<QString> &scannedPaths, QSet<QString> &newLibraries, - WorkingCopy workingCopy, QStringList files, ModelManager *modelManager, - QmlJS::Language::Enum mainLanguage, bool emitDocChangedOnDisk, - Utils::function<bool (qreal)> reportProgress); - static void parse(QFutureInterface<void> &future, - WorkingCopy workingCopy, - QStringList files, - ModelManager *modelManager, - QmlJS::Language::Enum mainLanguage, - bool emitDocChangedOnDisk); - static void importScan(QFutureInterface<void> &future, - WorkingCopy workingCopy, - QStringList paths, - ModelManager *modelManager, - QmlJS::Language::Enum mainLanguage, - bool emitDocChangedOnDisk); - - void loadQmlTypeDescriptions(); - void loadQmlTypeDescriptions(const QString &path); - - void updateImportPaths(); - -private slots: - void maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc); - void queueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc, bool scan); - void startCppQmlTypeUpdate(); - void asyncReset(); - + QHash<QString, QmlJS::Language::Enum> languageForSuffix() const QTC_OVERRIDE; + void writeMessageInternal(const QString &msg) const QTC_OVERRIDE; + ModelManagerInterface::ProjectInfo defaultProjectInfo() const QTC_OVERRIDE; + WorkingCopy workingCopyInternal() const QTC_OVERRIDE; + void addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const QTC_OVERRIDE; private: + void loadDefaultQmlTypeDescriptions(); static bool matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType); - static void updateCppQmlTypes(QFutureInterface<void> &interface, - ModelManager *qmlModelManager, - CPlusPlus::Snapshot snapshot, - QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents); - - mutable QMutex m_mutex; - QmlJS::Snapshot _validSnapshot; - QmlJS::Snapshot _newestSnapshot; - QStringList m_allImportPaths; - QStringList m_defaultImportPaths; - QmlJS::QmlLanguageBundles m_activeBundles; - QmlJS::QmlLanguageBundles m_extendedBundles; - QmlJS::ViewerContext m_vContext; - bool m_shouldScanImports; - QSet<QString> m_scannedPaths; - - QTimer *m_updateCppQmlTypesTimer; - QTimer *m_asyncResetTimer; - QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > m_queuedCppDocuments; - QFuture<void> m_cppQmlTypesUpdater; - QmlJS::QrcCache m_qrcCache; - - CppDataHash m_cppDataHash; - mutable QMutex m_cppDataMutex; - - // project integration - QMap<ProjectExplorer::Project *, ProjectInfo> m_projects; - - PluginDumper *m_pluginDumper; - - QFutureSynchronizer<void> m_synchronizer; - - QHash<QString, QmlJS::Language::Enum> languageForSuffix() const QTC_OVERRIDE; }; } // namespace Internal diff --git a/src/plugins/qmljstools/qmljstools.pro b/src/plugins/qmljstools/qmljstools.pro index c3fdd89e7d..d0a6409055 100644 --- a/src/plugins/qmljstools/qmljstools.pro +++ b/src/plugins/qmljstools/qmljstools.pro @@ -15,12 +15,10 @@ HEADERS += \ $$PWD/qmljsmodelmanager.h \ $$PWD/qmljsqtstylecodeformatter.h \ $$PWD/qmljsrefactoringchanges.h \ - $$PWD/qmljsplugindumper.h \ $$PWD/qmljsfunctionfilter.h \ $$PWD/qmljslocatordata.h \ $$PWD/qmljsindenter.h \ $$PWD/qmljscodestylesettingspage.h \ - $$PWD/qmljsfindexportedcpptypes.h \ $$PWD/qmljssemanticinfo.h \ $$PWD/qmljstools_global.h \ $$PWD/qmlconsolemanager.h \ @@ -41,12 +39,10 @@ SOURCES += \ $$PWD/qmljsmodelmanager.cpp \ $$PWD/qmljsqtstylecodeformatter.cpp \ $$PWD/qmljsrefactoringchanges.cpp \ - $$PWD/qmljsplugindumper.cpp \ $$PWD/qmljsfunctionfilter.cpp \ $$PWD/qmljslocatordata.cpp \ $$PWD/qmljsindenter.cpp \ $$PWD/qmljscodestylesettingspage.cpp \ - $$PWD/qmljsfindexportedcpptypes.cpp \ $$PWD/qmljssemanticinfo.cpp \ $$PWD/qmlconsolemanager.cpp \ $$PWD/qmlconsoleitemmodel.cpp \ diff --git a/src/plugins/qmljstools/qmljstools.qbs b/src/plugins/qmljstools/qmljstools.qbs index 714528ac3d..6fab90b4af 100644 --- a/src/plugins/qmljstools/qmljstools.qbs +++ b/src/plugins/qmljstools/qmljstools.qbs @@ -27,8 +27,6 @@ QtcPlugin { "qmljscodestylesettingspage.cpp", "qmljscodestylesettingspage.h", "qmljscodestylesettingspage.ui", - "qmljsfindexportedcpptypes.cpp", - "qmljsfindexportedcpptypes.h", "qmljsfunctionfilter.cpp", "qmljsfunctionfilter.h", "qmljsindenter.cpp", @@ -39,8 +37,6 @@ QtcPlugin { "qmljsmodelmanager.cpp", "qmljsmodelmanager.h", "qmljsmodelmanager.h", - "qmljsplugindumper.cpp", - "qmljsplugindumper.h", "qmljsqtstylecodeformatter.cpp", "qmljsqtstylecodeformatter.h", "qmljsrefactoringchanges.cpp", diff --git a/src/plugins/qmljstools/qmljstoolsconstants.h b/src/plugins/qmljstools/qmljstoolsconstants.h index 0803cf4988..b68acf1d63 100644 --- a/src/plugins/qmljstools/qmljstoolsconstants.h +++ b/src/plugins/qmljstools/qmljstoolsconstants.h @@ -42,9 +42,6 @@ const char QMLTYPES_MIMETYPE[] = "application/x-qt.meta-info+qml"; const char JS_MIMETYPE[] = "application/javascript"; const char JSON_MIMETYPE[] = "application/json"; -const char TASK_INDEX[] = "QmlJSEditor.TaskIndex"; -const char TASK_IMPORT_SCAN[] = "QmlJSEditor.TaskImportScan"; - const char QML_JS_CODE_STYLE_SETTINGS_ID[] = "A.Code Style"; const char QML_JS_CODE_STYLE_SETTINGS_NAME[] = QT_TRANSLATE_NOOP("QmlJSTools", "Code Style"); diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp index 4e02e5b36c..199cacd334 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.cpp +++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp @@ -132,13 +132,13 @@ ExtensionSystem::IPlugin::ShutdownFlag QmlJSToolsPlugin::aboutToShutdown() void QmlJSToolsPlugin::onTaskStarted(Core::Id type) { - if (type == QmlJSTools::Constants::TASK_INDEX) + if (type == QmlJS::Constants::TASK_INDEX) m_resetCodeModelAction->setEnabled(false); } void QmlJSToolsPlugin::onAllTasksFinished(Core::Id type) { - if (type == QmlJSTools::Constants::TASK_INDEX) + if (type == QmlJS::Constants::TASK_INDEX) m_resetCodeModelAction->setEnabled(true); } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 76a07ce9de..03e732513a 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -247,7 +247,7 @@ void QmlProject::refresh(RefreshOptions options) QmlJSTools::defaultProjectInfoForProject(this); projectInfo.importPaths = customImportPaths(); - m_modelManager->updateProjectInfo(projectInfo); + m_modelManager->updateProjectInfo(projectInfo, this); } QStringList QmlProject::convertToAbsoluteFiles(const QStringList &paths) const diff --git a/src/plugins/qtsupport/qmldumptool.cpp b/src/plugins/qtsupport/qmldumptool.cpp index af5d9c2759..c2a3e318f9 100644 --- a/src/plugins/qtsupport/qmldumptool.cpp +++ b/src/plugins/qtsupport/qmldumptool.cpp @@ -134,7 +134,7 @@ private slots: projectInfo.qmlDumpPath = version->qmlDumpTool(!update.preferDebug); projectInfo.qmlDumpEnvironment = version->qmlToolsEnvironment(); projectInfo.qmlDumpHasRelocatableFlag = version->hasQmlDumpWithRelocatableFlag(); - modelManager->updateProjectInfo(projectInfo); + modelManager->updateProjectInfo(projectInfo, update.project); } // clean up |