From 942326ae9bf96fc71264e2b31b106fa8622b831a Mon Sep 17 00:00:00 2001
From: Fawzi Mohamed <fawzi.mohamed@digia.com>
Date: Thu, 6 Dec 2012 17:20:58 +0100
Subject: qmljs: add infrastructure handling qml dialects better

QmlBundles enables us to treat the different qml
dialects differently.

Add imports completion.

Change-log: [Qml/JS Support] Corrected handling of QtQuick2 only features.
Change-log: [Qml/JS Support] Added import completion in editor.
Task-number: QTCREATORBUG-8750
Task-number: QTCREATORBUG-8624
Task-number: QTCREATORBUG-8584
Task-number: QTCREATORBUG-8583
Task-number: QTCREATORBUG-8429

Change-Id: I1384b1b23136a85b4d077895ea86f92960da9e71
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
---
 src/plugins/qmljstools/qmljsbundleprovider.cpp | 201 +++++++++++++++++++++++++
 src/plugins/qmljstools/qmljsbundleprovider.h   |  80 ++++++++++
 src/plugins/qmljstools/qmljsmodelmanager.cpp   | 163 ++++++++++++++++++++
 src/plugins/qmljstools/qmljsmodelmanager.h     |  10 ++
 src/plugins/qmljstools/qmljstools.pro          |   2 +
 src/plugins/qmljstools/qmljstools.qbs          |   2 +
 src/plugins/qmljstools/qmljstoolsplugin.cpp    |   2 +
 7 files changed, 460 insertions(+)
 create mode 100644 src/plugins/qmljstools/qmljsbundleprovider.cpp
 create mode 100644 src/plugins/qmljstools/qmljsbundleprovider.h

(limited to 'src/plugins/qmljstools')

diff --git a/src/plugins/qmljstools/qmljsbundleprovider.cpp b/src/plugins/qmljstools/qmljsbundleprovider.cpp
new file mode 100644
index 0000000000..fa3933a0c4
--- /dev/null
+++ b/src/plugins/qmljstools/qmljsbundleprovider.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qmljsbundleprovider.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/target.h>
+#include <qmljs/qmljsbundle.h>
+#include <qmljs/qmljsdocument.h>
+#include <qtsupport/qtkitinformation.h>
+#include <qtsupport/qtsupportconstants.h>
+
+#include <QDir>
+#include <QFile>
+#include <QHash>
+#include <QHashIterator>
+#include <QList>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QtAlgorithms>
+
+namespace QmlJSTools {
+
+namespace {
+typedef QmlJS::Document::Language Language;
+typedef QmlJS::QmlBundle QmlBundle;
+typedef QmlJS::QmlLanguageBundles QmlLanguageBundles;
+}
+
+/*!
+  \class QmlJSEditor::BasicBundleProvider
+
+  \brief a class that sets up the default bundles for qt and various qml states.
+  */
+BasicBundleProvider::BasicBundleProvider(QObject *parent) :
+    IBundleProvider(parent)
+{ }
+
+QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName)
+{
+    static bool wroteErrors = false;
+    QmlBundle res;
+    QString defaultBundlePath = Core::ICore::resourcePath()
+            + QLatin1String("/qml-type-descriptions/")
+            + bundleInfoName;
+    if (!QFileInfo(defaultBundlePath).exists()) {
+        qWarning() << "BasicBundleProvider: ERROR " << defaultBundlePath
+                   << " not found";
+        return res;
+    }
+    QStringList errors;
+    if (!res.readFrom(defaultBundlePath, &errors) && ! wroteErrors) {
+        qWarning() << "BasicBundleProvider: ERROR reading " << defaultBundlePath
+                   << " : " << errors;
+        wroteErrors = true;
+    }
+    return res;
+}
+
+QmlBundle BasicBundleProvider::defaultQt4QtQuick1Bundle()
+{
+    return defaultBundle(QLatin1String("qt4QtQuick1-bundle.json"));
+}
+
+QmlBundle BasicBundleProvider::defaultQt5QtQuick1Bundle()
+{
+    return defaultBundle(QLatin1String("qt5QtQuick1-bundle.json"));
+}
+
+QmlBundle BasicBundleProvider::defaultQt5QtQuick2Bundle()
+{
+    return defaultBundle(QLatin1String("qt5QtQuick2-bundle.json"));
+}
+
+QmlBundle BasicBundleProvider::defaultQbsBundle()
+{
+    return defaultBundle(QLatin1String("qbs-bundle.json"));
+}
+
+QmlBundle BasicBundleProvider::defaultQmltypesBundle()
+{
+    return defaultBundle(QLatin1String("qmltypes-bundle.json"));
+}
+
+QmlBundle BasicBundleProvider::defaultQmlprojectBundle()
+{
+    return defaultBundle(QLatin1String("qmlproject-bundle.json"));
+}
+
+void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit
+                                             , QmlJS::QmlLanguageBundles &bundles
+                                             , const QHash<QString,QString> &replacements)
+{
+    typedef QmlJS::Document Doc;
+    QHash<QString,QString> myReplacements = replacements;
+
+    bundles.mergeBundleForLanguage(Doc::QmlQbsLanguage, defaultQbsBundle());
+    bundles.mergeBundleForLanguage(Doc::QmlTypeInfoLanguage, defaultQmltypesBundle());
+    bundles.mergeBundleForLanguage(Doc::QmlProjectLanguage, defaultQmlprojectBundle());
+
+    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(kit);
+    if (!qtVersion) {
+        QmlBundle b1(defaultQt4QtQuick1Bundle());
+        bundles.mergeBundleForLanguage(Doc::QmlLanguage, b1);
+        bundles.mergeBundleForLanguage(Doc::QmlQtQuick1Language, b1);
+        QmlBundle b11(defaultQt5QtQuick1Bundle());
+        bundles.mergeBundleForLanguage(Doc::QmlLanguage, b11);
+        bundles.mergeBundleForLanguage(Doc::QmlQtQuick1Language, b11);
+        QmlBundle b2(defaultQt5QtQuick2Bundle());
+        bundles.mergeBundleForLanguage(Doc::QmlLanguage, b2);
+        bundles.mergeBundleForLanguage(Doc::QmlQtQuick2Language, b2);
+        return;
+    }
+    QString qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
+    QString qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
+
+    Core::FeatureSet features = qtVersion->availableFeatures();
+    if (features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK))
+            || features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK_1))
+            || features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK_1_1))) {
+        myReplacements.insert(QLatin1String("$(CURRENT_DIRECTORY)"), qtImportsPath);
+        QDir qtQuick1Bundles(qtImportsPath);
+        qtQuick1Bundles.setNameFilters(QStringList(QLatin1String("*-bundle.json")));
+        QmlBundle qtQuick1Bundle;
+        QFileInfoList list = qtQuick1Bundles.entryInfoList();
+        for (int i = 0; i < list.size(); ++i) {
+            QmlBundle bAtt;
+            QStringList errors;
+            if (!bAtt.readFrom(list.value(i).filePath(), &errors))
+                qWarning() << "BasicBundleProvider: ERROR reading " << list[i].filePath() << " : "
+                           << errors;
+            qtQuick1Bundle.merge(bAtt);
+        }
+        if (!qtQuick1Bundle.supportedImports().contains(QLatin1String("QtQuick 1."),
+                                                        QmlJS::PersistentTrie::Partial)) {
+            if (qtVersion->qtVersion().majorVersion == 4)
+                qtQuick1Bundle.merge(defaultQt4QtQuick1Bundle());
+            else if (qtVersion->qtVersion().majorVersion > 4)
+                qtQuick1Bundle.merge(defaultQt5QtQuick1Bundle());
+        }
+        qtQuick1Bundle.replaceVars(myReplacements);
+        bundles.mergeBundleForLanguage(Doc::QmlLanguage, qtQuick1Bundle);
+        bundles.mergeBundleForLanguage(Doc::QmlQtQuick1Language, qtQuick1Bundle);
+    }
+    if (features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK_2))) {
+        myReplacements.insert(QLatin1String("$(CURRENT_DIRECTORY)"), qtQmlPath);
+        QDir qtQuick2Bundles(qtQmlPath);
+        qtQuick2Bundles.setNameFilters(QStringList(QLatin1String("*-bundle.json")));
+        QmlBundle qtQuick2Bundle;
+        QFileInfoList list = qtQuick2Bundles.entryInfoList();
+        for (int i = 0; i < list.size(); ++i) {
+            QmlBundle bAtt;
+            QStringList errors;
+            if (!bAtt.readFrom(list.value(i).filePath(), &errors))
+                qWarning() << "BasicBundleProvider: ERROR reading " << list[i].filePath() << " : "
+                           << errors;
+            qtQuick2Bundle.merge(bAtt);
+        }
+        if (!qtQuick2Bundle.supportedImports().contains(QLatin1String("QtQuick 2."),
+                                                        QmlJS::PersistentTrie::Partial)) {
+            qtQuick2Bundle.merge(defaultQt5QtQuick2Bundle());
+        }
+        qtQuick2Bundle.replaceVars(myReplacements);
+        bundles.mergeBundleForLanguage(Doc::QmlLanguage, qtQuick2Bundle);
+        bundles.mergeBundleForLanguage(Doc::QmlQtQuick2Language, qtQuick2Bundle);
+    }
+}
+
+} // end namespace QmlJSTools
diff --git a/src/plugins/qmljstools/qmljsbundleprovider.h b/src/plugins/qmljstools/qmljsbundleprovider.h
new file mode 100644
index 0000000000..f02a6e3fe7
--- /dev/null
+++ b/src/plugins/qmljstools/qmljsbundleprovider.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QMLJSBUNDLEPROVIDER_H
+#define QMLJSBUNDLEPROVIDER_H
+
+#include <QObject>
+
+#include <qmljs/qmljsbundle.h>
+#include <qmljs/qmljsdocument.h>
+
+#include "qmljstools_global.h"
+
+namespace ProjectExplorer {
+class Kit;
+class Project;
+class Target;
+}
+
+namespace QmlJSTools {
+
+class QMLJSTOOLS_EXPORT IBundleProvider : public QObject
+{
+    Q_OBJECT
+public:
+    explicit IBundleProvider(QObject *parent = 0)
+        : QObject(parent)
+    { }
+
+    virtual void mergeBundlesForKit(ProjectExplorer::Kit *kit, QmlJS::QmlLanguageBundles &bundles
+                                    , const QHash<QString,QString> &replacements) = 0;
+};
+
+class QMLJSTOOLS_EXPORT BasicBundleProvider : public IBundleProvider
+{
+    Q_OBJECT
+public:
+    explicit BasicBundleProvider(QObject *parent = 0);
+
+    virtual void mergeBundlesForKit(ProjectExplorer::Kit *kit, QmlJS::QmlLanguageBundles &bundles
+                                    , const QHash<QString,QString> &replacements);
+
+    static QmlJS::QmlBundle defaultBundle(const QString &bundleInfoName);
+    static QmlJS::QmlBundle defaultQt4QtQuick1Bundle();
+    static QmlJS::QmlBundle defaultQt5QtQuick1Bundle();
+    static QmlJS::QmlBundle defaultQt5QtQuick2Bundle();
+    static QmlJS::QmlBundle defaultQbsBundle();
+    static QmlJS::QmlBundle defaultQmltypesBundle();
+    static QmlJS::QmlBundle defaultQmlprojectBundle();
+};
+
+} // end QmlJSTools namespace
+
+#endif // QMLJSBUNDLEPROVIDER_H
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp
index 6020dd9e55..36cac68fda 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp
@@ -32,6 +32,7 @@
 #include "qmljsplugindumper.h"
 #include "qmljsfindexportedcpptypes.h"
 #include "qmljssemanticinfo.h"
+#include "qmljsbundleprovider.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/editormanager/editormanager.h>
@@ -42,15 +43,25 @@
 #include <cplusplus/CppDocument.h>
 #include <qmljs/qmljscontext.h>
 #include <qmljs/qmljsbind.h>
+#include <qmljs/qmljsbundle.h>
 #include <qmljs/parser/qmldirparser_p.h>
 #include <texteditor/itexteditor.h>
 #include <texteditor/basetexteditor.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitinformation.h>
 #include <projectexplorer/project.h>
 #include <projectexplorer/projectexplorer.h>
 #include <projectexplorer/projectexplorerconstants.h>
 #include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/toolchain.h>
 #include <qtsupport/baseqtversion.h>
+#include <qtsupport/qtkitinformation.h>
+#include <qtsupport/qmldumptool.h>
+#include <qtsupport/qtsupportconstants.h>
 #include <utils/hostosinfo.h>
+#include <extensionsystem/pluginmanager.h>
 
 #include <QDir>
 #include <QFile>
@@ -61,6 +72,7 @@
 #include <QTextStream>
 #include <QCoreApplication>
 #include <QTimer>
+#include <QRegExp>
 
 #include <QDebug>
 
@@ -68,6 +80,104 @@ using namespace QmlJS;
 using namespace QmlJSTools;
 using namespace QmlJSTools::Internal;
 
+
+ModelManagerInterface::ProjectInfo QmlJSTools::defaultProjectInfoForProject(
+        ProjectExplorer::Project *project)
+{
+    ModelManagerInterface::ProjectInfo projectInfo(project);
+    ProjectExplorer::Target *activeTarget = 0;
+    if (project) {
+        Core::MimeDatabase *db = Core::ICore::mimeDatabase();
+        QList<Core::MimeGlobPattern> globs;
+        QList<Core::MimeType> mimeTypes = db->mimeTypes();
+        foreach (const Core::MimeType &mimeType, mimeTypes)
+            if (mimeType.type() == QLatin1String(Constants::QML_MIMETYPE)
+                    || mimeType.subClassesOf().contains(QLatin1String(Constants::QML_MIMETYPE)))
+                globs << mimeType.globPatterns();
+        if (globs.isEmpty())
+            globs << Core::MimeGlobPattern(QRegExp(QLatin1String(".*\\.(?:qbs|qml|qmltypes|qmlproject)$")));
+        foreach (const QString &filePath
+                 , project->files(ProjectExplorer::Project::ExcludeGeneratedFiles))
+            foreach (const Core::MimeGlobPattern &glob, globs)
+                if (glob.regExp().exactMatch(filePath))
+                    projectInfo.sourceFiles << filePath;
+        activeTarget = project->activeTarget();
+    }
+    ProjectExplorer::Kit *activeKit = activeTarget ? activeTarget->kit() :
+                                           ProjectExplorer::KitManager::instance()->defaultKit();
+    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(activeKit);
+
+    bool preferDebugDump = false;
+    bool setPreferDump = false;
+    projectInfo.tryQmlDump = false;
+
+    if (activeTarget) {
+        if (ProjectExplorer::BuildConfiguration *bc = activeTarget->activeBuildConfiguration()) {
+            preferDebugDump = bc->buildType() == ProjectExplorer::BuildConfiguration::Debug;
+            setPreferDump = true;
+        }
+    }
+    if (!setPreferDump && qtVersion)
+        preferDebugDump = (qtVersion->defaultBuildConfig() & QtSupport::BaseQtVersion::DebugBuild);
+    if (qtVersion && qtVersion->isValid()) {
+        projectInfo.tryQmlDump = project && (
+                    qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
+                    || qtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT));
+        projectInfo.qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
+        projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
+        projectInfo.qtVersionString = qtVersion->qtVersionString();
+    }
+
+    if (projectInfo.tryQmlDump) {
+        ProjectExplorer::ToolChain *toolChain =
+                ProjectExplorer::ToolChainKitInformation::toolChain(activeKit);
+        QtSupport::QmlDumpTool::pathAndEnvironment(project, qtVersion,
+                                                   toolChain,
+                                                   preferDebugDump, &projectInfo.qmlDumpPath,
+                                                   &projectInfo.qmlDumpEnvironment);
+    } else {
+        projectInfo.qmlDumpPath.clear();
+        projectInfo.qmlDumpEnvironment.clear();
+    }
+    setupProjectInfoQmlBundles(projectInfo);
+    return projectInfo;
+}
+
+void QmlJSTools::setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &projectInfo)
+{
+    ProjectExplorer::Target *activeTarget = 0;
+    if (projectInfo.project) {
+        activeTarget = projectInfo.project->activeTarget();
+    }
+    ProjectExplorer::Kit *activeKit = activeTarget
+            ? activeTarget->kit() : ProjectExplorer::KitManager::instance()->defaultKit();
+    QHash<QString, QString> replacements;
+    replacements.insert(QLatin1String("$(QT_INSTALL_IMPORTS)"), projectInfo.qtImportsPath);
+    replacements.insert(QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath);
+
+    QList<IBundleProvider *> bundleProviders =
+            ExtensionSystem::PluginManager::getObjects<IBundleProvider>();
+
+    foreach (IBundleProvider *bp, bundleProviders) {
+        if (bp)
+            bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements);
+    }
+    projectInfo.extendedBundle = projectInfo.activeBundle;
+
+    if (projectInfo.project) {
+        QSet<ProjectExplorer::Kit *> currentKits;
+        foreach (const ProjectExplorer::Target *t, projectInfo.project->targets())
+            if (t->kit())
+                currentKits.insert(t->kit());
+        currentKits.remove(activeKit);
+        foreach (ProjectExplorer::Kit *kit, currentKits) {
+            foreach (IBundleProvider *bp, bundleProviders)
+                if (bp)
+                    bp->mergeBundlesForKit(kit, projectInfo.extendedBundle, replacements);
+        }
+    }
+}
+
 static QStringList environmentImportPaths();
 
 static void mergeSuffixes(QStringList &l1, const QStringList &l2)
@@ -373,6 +483,7 @@ void ModelManager::updateProjectInfo(const ProjectInfo &pinfo)
 void ModelManager::removeProjectInfo(ProjectExplorer::Project *project)
 {
     ProjectInfo info(project);
+    info.sourceFiles.clear();
     // update with an empty project info to clear data
     updateProjectInfo(info);
 
@@ -382,6 +493,16 @@ void ModelManager::removeProjectInfo(ProjectExplorer::Project *project)
     }
 }
 
+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); }
 
@@ -660,6 +781,18 @@ QStringList ModelManager::importPaths() const
     return m_allImportPaths;
 }
 
+QmlLanguageBundles ModelManager::activeBundles() const
+{
+    QMutexLocker l(&m_mutex);
+    return m_activeBundles;
+}
+
+QmlLanguageBundles ModelManager::extendedBundles() const
+{
+    QMutexLocker l(&m_mutex);
+    return m_extendedBundles;
+}
+
 static QStringList environmentImportPaths()
 {
     QStringList paths;
@@ -679,6 +812,8 @@ static QStringList environmentImportPaths()
 void ModelManager::updateImportPaths()
 {
     QStringList allImportPaths;
+    QmlLanguageBundles activeBundles;
+    QmlLanguageBundles extendedBundles;
     QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
     while (it.hasNext()) {
         it.next();
@@ -688,12 +823,40 @@ void ModelManager::updateImportPaths()
                 allImportPaths += canonicalPath;
         }
     }
+    it.toFront();
+    while (it.hasNext()) {
+        it.next();
+        activeBundles.mergeLanguageBundles(it.value().activeBundle);
+        foreach (Document::Language 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 (Document::Language 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;
     }
 
 
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.h b/src/plugins/qmljstools/qmljsmodelmanager.h
index 571ea8b055..3b0763f904 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.h
+++ b/src/plugins/qmljstools/qmljsmodelmanager.h
@@ -82,12 +82,15 @@ public:
     virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
     virtual void updateProjectInfo(const ProjectInfo &pinfo);
     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);
 
     virtual QStringList importPaths() const;
+    virtual QmlJS::QmlLanguageBundles activeBundles() const;
+    virtual QmlJS::QmlLanguageBundles extendedBundles() const;
 
     virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath,
                                  const QString &importUri, const QString &importVersion);
@@ -136,6 +139,8 @@ private:
     QmlJS::Snapshot _newestSnapshot;
     QStringList m_allImportPaths;
     QStringList m_defaultImportPaths;
+    QmlJS::QmlLanguageBundles m_activeBundles;
+    QmlJS::QmlLanguageBundles m_extendedBundles;
 
     QFutureSynchronizer<void> m_synchronizer;
 
@@ -153,6 +158,11 @@ private:
 };
 
 } // namespace Internal
+
+QMLJSTOOLS_EXPORT QmlJS::ModelManagerInterface::ProjectInfo defaultProjectInfoForProject(
+        ProjectExplorer::Project *project);
+QMLJSTOOLS_EXPORT void setupProjectInfoQmlBundles(QmlJS::ModelManagerInterface::ProjectInfo &projectInfo);
+
 } // namespace QmlJSTools
 
 #endif // QMLJSMODELMANAGER_H
diff --git a/src/plugins/qmljstools/qmljstools.pro b/src/plugins/qmljstools/qmljstools.pro
index b653f9b084..575d486be1 100644
--- a/src/plugins/qmljstools/qmljstools.pro
+++ b/src/plugins/qmljstools/qmljstools.pro
@@ -10,6 +10,7 @@ DEFINES += QMLJSTOOLS_LIBRARY
 }
 
 HEADERS += \
+    $$PWD/qmljsbundleprovider.h \
     $$PWD/qmljstoolsplugin.h \
     $$PWD/qmljstoolsconstants.h \
     $$PWD/qmljstoolssettings.h \
@@ -36,6 +37,7 @@ HEADERS += \
     $$PWD/qmlconsoleproxymodel.h
 
 SOURCES += \
+    $$PWD/qmljsbundleprovider.cpp \
     $$PWD/qmljstoolsplugin.cpp \
     $$PWD/qmljstoolssettings.cpp \
     $$PWD/qmljscodestylepreferencesfactory.cpp \
diff --git a/src/plugins/qmljstools/qmljstools.qbs b/src/plugins/qmljstools/qmljstools.qbs
index 9f62253750..d787c842b1 100644
--- a/src/plugins/qmljstools/qmljstools.qbs
+++ b/src/plugins/qmljstools/qmljstools.qbs
@@ -21,6 +21,8 @@ QtcPlugin {
     cpp.includePaths: base.concat("../../libs/3rdparty")
 
     files: [
+        "qmljsbundleprovider.cpp",
+        "qmljsbundleprovider.h",
         "qmljscodestylepreferencesfactory.cpp",
         "qmljscodestylepreferencesfactory.h",
         "qmljscodestylesettingspage.cpp",
diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp
index 22d6717294..dc9ba4ec1b 100644
--- a/src/plugins/qmljstools/qmljstoolsplugin.cpp
+++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp
@@ -35,6 +35,7 @@
 #include "qmljstoolsconstants.h"
 #include "qmljstoolssettings.h"
 #include "qmlconsolemanager.h"
+#include "qmljsbundleprovider.h"
 
 #include <extensionsystem/pluginmanager.h>
 
@@ -94,6 +95,7 @@ bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error)
     addAutoReleasedObject(locatorData);
     addAutoReleasedObject(new FunctionFilter(locatorData));
     addAutoReleasedObject(new QmlJSCodeStyleSettingsPage);
+    addAutoReleasedObject(new BasicBundleProvider);
 
     // Menus
     Core::ActionContainer *mtools = Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
-- 
cgit v1.2.1