From f725c24c561ea6d149736620af190cc10eea95e8 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Tue, 16 Aug 2011 14:11:30 +0200
Subject: [PATCH] QmlJS: Fix semantic and non-semantic QML error reporting.

The QML snapshot only ever contains valid Documents; to compile a list
of parser problems we need to get at the invalid documents.

To do that, the model manager now provides a Snapshot with up to date,
but potentially invalid documents. That should also be useful for other
things.

Change-Id: I67892f63771c221bf2fe2c2bf0240a0f4e523227
Reviewed-on: http://codereview.qt.nokia.com/3012
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
---
 src/libs/qmljs/qmljsdocument.cpp             |  4 +--
 src/libs/qmljs/qmljsdocument.h               |  2 +-
 src/libs/qmljs/qmljsmodelmanagerinterface.h  |  2 +-
 src/plugins/qmljseditor/qmltaskmanager.cpp   | 21 ++++++--------
 src/plugins/qmljseditor/qmltaskmanager.h     |  2 +-
 src/plugins/qmljstools/qmljsmodelmanager.cpp | 30 +++++++++++++-------
 src/plugins/qmljstools/qmljsmodelmanager.h   |  5 ++--
 7 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp
index 0eceac0ca94..897c56a8913 100644
--- a/src/libs/qmljs/qmljsdocument.cpp
+++ b/src/libs/qmljs/qmljsdocument.cpp
@@ -389,9 +389,9 @@ Snapshot::~Snapshot()
 {
 }
 
-void Snapshot::insert(const Document::Ptr &document)
+void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
 {
-    if (document && (document->qmlProgram() || document->jsProgram())) {
+    if (document && (allowInvalid || document->qmlProgram() || document->jsProgram())) {
         const QString fileName = document->fileName();
         const QString path = document->path();
 
diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h
index 0999712faaf..9b6191d8fa1 100644
--- a/src/libs/qmljs/qmljsdocument.h
+++ b/src/libs/qmljs/qmljsdocument.h
@@ -198,7 +198,7 @@ public:
     const_iterator begin() const { return _documents.begin(); }
     const_iterator end() const { return _documents.end(); }
 
-    void insert(const Document::Ptr &document);
+    void insert(const Document::Ptr &document, bool allowInvalid = false);
     void insertLibraryInfo(const QString &path, const LibraryInfo &info);
     void remove(const QString &fileName);
 
diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h
index 731b9c6ade7..17530e43593 100644
--- a/src/libs/qmljs/qmljsmodelmanagerinterface.h
+++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h
@@ -119,7 +119,7 @@ public:
     static ModelManagerInterface *instance();
 
     virtual WorkingCopy workingCopy() const = 0;
-    virtual QmlJS::Snapshot snapshot() const = 0;
+    virtual QmlJS::Snapshot snapshot(bool preferValid = true) const = 0;
 
     virtual void updateSourceFiles(const QStringList &files,
                                    bool emitDocumentOnDiskChanged) = 0;
diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp
index f87ae0ae60a..93e17201cfd 100644
--- a/src/plugins/qmljseditor/qmltaskmanager.cpp
+++ b/src/plugins/qmljseditor/qmltaskmanager.cpp
@@ -119,7 +119,8 @@ void QmlTaskManager::collectMessages(
                                                fileName, Constants::TASK_CATEGORY_QML_ANALYSIS);
             }
 
-            future.reportResult(result);
+            if (!result.tasks.isEmpty())
+                future.reportResult(result);
             if (future.isCanceled())
                 break;
         }
@@ -145,16 +146,15 @@ void QmlTaskManager::updateMessagesNow(bool updateSemantic)
 
     // abort any update that's going on already
     m_messageCollector.cancel();
-    removeAllTasks();
+    removeAllTasks(updateSemantic);
 
-    // collect all the source files in open projects
     ModelManagerInterface *modelManager = ModelManagerInterface::instance();
 
     // process them
     QFuture<FileErrorMessages> future =
             QtConcurrent::run<FileErrorMessages>(
-                &collectMessages, modelManager->snapshot(), modelManager->projectInfos(),
-                modelManager->importPaths(), !updateSemantic);
+                &collectMessages, modelManager->snapshot(false), modelManager->projectInfos(),
+                modelManager->importPaths(), updateSemantic);
     m_messageCollector.setFuture(future);
 }
 
@@ -198,14 +198,11 @@ void QmlTaskManager::removeTasksForFile(const QString &fileName)
     }
 }
 
-void QmlTaskManager::removeAllTasks()
+void QmlTaskManager::removeAllTasks(bool clearSemantic)
 {
-    QMapIterator<QString, QList<ProjectExplorer::Task> > it(m_docsWithTasks);
-    while (it.hasNext()) {
-        it.next();
-        foreach (const ProjectExplorer::Task &task, it.value())
-            m_taskHub->removeTask(task);
-    }
+    m_taskHub->clearTasks(Constants::TASK_CATEGORY_QML);
+    if (clearSemantic)
+        m_taskHub->clearTasks(Constants::TASK_CATEGORY_QML_ANALYSIS);
     m_docsWithTasks.clear();
 }
 
diff --git a/src/plugins/qmljseditor/qmltaskmanager.h b/src/plugins/qmljseditor/qmltaskmanager.h
index 354ca14c722..8657228d085 100644
--- a/src/plugins/qmljseditor/qmltaskmanager.h
+++ b/src/plugins/qmljseditor/qmltaskmanager.h
@@ -76,7 +76,7 @@ private slots:
 private:
     void insertTask(const ProjectExplorer::Task &task);
     void removeTasksForFile(const QString &fileName);
-    void removeAllTasks();
+    void removeAllTasks(bool clearSemantic);
 
 private:
     class FileErrorMessages
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp
index 6ec07db623f..6ff2c895504 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp
@@ -169,11 +169,14 @@ ModelManagerInterface::WorkingCopy ModelManager::workingCopy() const
     return workingCopy;
 }
 
-Snapshot ModelManager::snapshot() const
+Snapshot ModelManager::snapshot(bool preferValid) const
 {
     QMutexLocker locker(&m_mutex);
 
-    return _snapshot;
+    if (preferValid)
+        return _validSnapshot;
+    else
+        return _newestSnapshot;
 }
 
 void ModelManager::updateSourceFiles(const QStringList &files,
@@ -228,8 +231,10 @@ void ModelManager::removeFiles(const QStringList &files)
 
     QMutexLocker locker(&m_mutex);
 
-    foreach (const QString &file, files)
-        _snapshot.remove(file);
+    foreach (const QString &file, files) {
+        _validSnapshot.remove(file);
+        _newestSnapshot.remove(file);
+    }
 }
 
 QList<ModelManager::ProjectInfo> ModelManager::projectInfos() const
@@ -257,7 +262,7 @@ void ModelManager::updateProjectInfo(const ProjectInfo &pinfo)
         QMutexLocker locker(&m_mutex);
         oldInfo = m_projects.value(pinfo.project);
         m_projects.insert(pinfo.project, pinfo);
-        snapshot = _snapshot;
+        snapshot = _validSnapshot;
     }
 
     if (oldInfo.qmlDumpPath != pinfo.qmlDumpPath
@@ -302,7 +307,8 @@ void ModelManager::updateDocument(Document::Ptr doc)
 {
     {
         QMutexLocker locker(&m_mutex);
-        _snapshot.insert(doc);
+        _validSnapshot.insert(doc);
+        _newestSnapshot.insert(doc, true);
     }
     emit documentUpdated(doc);
 }
@@ -311,7 +317,8 @@ void ModelManager::updateLibraryInfo(const QString &path, const LibraryInfo &inf
 {
     {
         QMutexLocker locker(&m_mutex);
-        _snapshot.insertLibraryInfo(path, info);
+        _validSnapshot.insertLibraryInfo(path, info);
+        _newestSnapshot.insertLibraryInfo(path, info);
     }
     // only emit if we got new useful information
     if (info.isValid())
@@ -650,7 +657,7 @@ void ModelManager::updateImportPaths()
     m_allImportPaths.removeDuplicates();
 
     // check if any file in the snapshot imports something new in the new paths
-    Snapshot snapshot = _snapshot;
+    Snapshot snapshot = _validSnapshot;
     QStringList importedFiles;
     QSet<QString> scannedPaths;
     QSet<QString> newLibraries;
@@ -724,7 +731,7 @@ LibraryInfo ModelManager::builtins(const Document::Ptr &doc) const
     if (!info.isValid())
         return LibraryInfo();
 
-    return _snapshot.libraryInfo(info.qtImportsPath);
+    return _validSnapshot.libraryInfo(info.qtImportsPath);
 }
 
 void ModelManager::joinAllThreads()
@@ -741,11 +748,12 @@ void ModelManager::resetCodeModel()
         QMutexLocker locker(&m_mutex);
 
         // find all documents currently in the code model
-        foreach (Document::Ptr doc, _snapshot)
+        foreach (Document::Ptr doc, _validSnapshot)
             documents.append(doc->fileName());
 
         // reset the snapshot
-        _snapshot = Snapshot();
+        _validSnapshot = Snapshot();
+        _newestSnapshot = Snapshot();
     }
 
     // start a reparse thread
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.h b/src/plugins/qmljstools/qmljsmodelmanager.h
index 14e51b95d01..7fe82145b38 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.h
+++ b/src/plugins/qmljstools/qmljsmodelmanager.h
@@ -69,7 +69,7 @@ public:
     void delayedInitialization();
 
     virtual WorkingCopy workingCopy() const;
-    virtual QmlJS::Snapshot snapshot() const;
+    virtual QmlJS::Snapshot snapshot(bool preferValid = true) const;
 
     virtual void updateSourceFiles(const QStringList &files,
                                    bool emitDocumentOnDiskChanged);
@@ -126,7 +126,8 @@ private:
 
     mutable QMutex m_mutex;
     Core::ICore *m_core;
-    QmlJS::Snapshot _snapshot;
+    QmlJS::Snapshot _validSnapshot;
+    QmlJS::Snapshot _newestSnapshot;
     QStringList m_allImportPaths;
     QStringList m_defaultImportPaths;
 
-- 
GitLab