aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@digia.com>2014-01-23 14:28:31 +0100
committerFawzi Mohamed <fawzi.mohamed@digia.com>2014-02-19 21:18:58 +0100
commitd24cb60d487e2241c8364b83658f31178305176a (patch)
tree2702c6f07ecca6a11c194b5352ab622dd55dc783 /src
parentbf989b75a212b6a39f5a910ca78ad84f50e71f00 (diff)
qml: moving most of ModelManager logic to ModelManageInterface
Currently ModelManager contains lot logic, but as it sits in QmlJSTools it is not possible to use it in standalone tests. Moving most of the logic to ModelManagerInterface (and cleanup) to allow better testing, and refactoring. This introduces a dependency of the qmljs lib on the cplusplus lib Also a (small) part of the CppTool::ModelManagerInterface has been moved to CPlusPlus::CppModelManagerBase to remove the dependency on CppTools to gather the Qml types exposed from C++. Change-Id: Icad7fe96dfd0f1a2b1058d82bd98c77c40aa5e9d Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/libs/cplusplus/cplusplus-lib.pri6
-rw-r--r--src/libs/cplusplus/cplusplus.qbs1
-rw-r--r--src/libs/cplusplus/cppmodelmanagerbase.cpp76
-rw-r--r--src/libs/cplusplus/cppmodelmanagerbase.h62
-rw-r--r--src/libs/qmljs/qmljs-lib.pri4
-rw-r--r--src/libs/qmljs/qmljs.qbs3
-rw-r--r--src/libs/qmljs/qmljs_dependencies.pri3
-rw-r--r--src/libs/qmljs/qmljsconstants.h6
-rw-r--r--src/libs/qmljs/qmljsfindexportedcpptypes.cpp (renamed from src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp)37
-rw-r--r--src/libs/qmljs/qmljsfindexportedcpptypes.h (renamed from src/plugins/qmljstools/qmljsfindexportedcpptypes.h)13
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.cpp1140
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.h167
-rw-r--r--src/libs/qmljs/qmljsplugindumper.cpp (renamed from src/plugins/qmljstools/qmljsplugindumper.cpp)27
-rw-r--r--src/libs/qmljs/qmljsplugindumper.h (renamed from src/plugins/qmljstools/qmljsplugindumper.h)12
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp5
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h2
-rw-r--r--src/plugins/cpptools/cppmodelmanagerinterface.cpp16
-rw-r--r--src/plugins/cpptools/cppmodelmanagerinterface.h6
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.cpp2
-rw-r--r--src/plugins/qmljstools/qmljsmodelmanager.cpp1079
-rw-r--r--src/plugins/qmljstools/qmljsmodelmanager.h126
-rw-r--r--src/plugins/qmljstools/qmljstools.pro4
-rw-r--r--src/plugins/qmljstools/qmljstools.qbs4
-rw-r--r--src/plugins/qmljstools/qmljstoolsconstants.h3
-rw-r--r--src/plugins/qmljstools/qmljstoolsplugin.cpp4
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp2
-rw-r--r--src/plugins/qtsupport/qmldumptool.cpp2
28 files changed, 1505 insertions, 1309 deletions
diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri
index bd77b940bfb..7d2a3c9acaf 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 2331804a55f..09dfe63cec5 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 00000000000..6ad44b5bc4a
--- /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 00000000000..f76c80a3ed2
--- /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 6324d83e321..47c4a9ecf6b 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 94968cf313b..00161285458 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 e1d1204148c..3686f2e6287 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 3ddb014754f..377f282ea4b 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 4b9f819fd70..7034ea64b92 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 90884d66d25..ca6508c39ad 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 ec70d6bf650..d9aa6aa1180 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 7d225f33a65..88463d36cac 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 cf99d00637a..12df8f5d008 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 a1567b7ab3e..8c4a95c42e9 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 f4a5329b33b..5a0e96a3696 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 96a5796a2db..b7b192c5304 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -107,7 +107,7 @@ public:
virtual void findMacroUsages(const CPlusPlus::Macro &macro);
virtual void renameMacroUsages(const CPlusPlus::Macro &macro, 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 e755783bef5..0f65f162255 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 84cca908b71..188367c68ad 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 &macro, const QString &replacement = QString()) = 0;
virtual void findMacroUsages(const CPlusPlus::Macro &macro) = 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 87f5fa205d4..8a4e1112787 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 6358d335ba7..ec55f9f7c42 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 edc1e633a70..61a16bcc9a2 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 ac60ea106ca..2b8233a66f4 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 c3fdd89e7d7..d0a64090555 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 714528ac3d6..6fab90b4af3 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 0803cf49883..b68acf1d634 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 4e02e5b36cb..199cacd3344 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 76a07ce9deb..03e732513ae 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 af5d9c27592..c2a3e318f9f 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