/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** 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 The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qmltaskmanager.h" #include "qmljseditor.h" #include "qmljseditorconstants.h" #include #include #include #include #include #include #include #include #include #include #include using namespace ProjectExplorer; using namespace QmlJS; using namespace Utils; namespace QmlJSEditor { namespace Internal { QmlTaskManager::QmlTaskManager() { // displaying results incrementally leads to flickering // connect(&m_messageCollector, &QFutureWatcherBase::resultsReadyAt, // this, &QmlTaskManager::displayResults); connect(&m_messageCollector, &QFutureWatcherBase::finished, this, &QmlTaskManager::displayAllResults); m_updateDelay.setInterval(500); m_updateDelay.setSingleShot(true); connect(&m_updateDelay, &QTimer::timeout, this, [this] { updateMessagesNow(); }); } static Tasks convertToTasks(const QList &messages, const FilePath &fileName, Core::Id category) { Tasks result; foreach (const DiagnosticMessage &msg, messages) { Task::TaskType type = msg.isError() ? Task::Error : Task::Warning; Task task(type, msg.message, fileName, msg.loc.startLine, category); result += task; } return result; } static Tasks convertToTasks(const QList &messages, const FilePath &fileName, Core::Id category) { QList diagnostics; foreach (const StaticAnalysis::Message &msg, messages) diagnostics += msg.toDiagnosticMessage(); return convertToTasks(diagnostics, fileName, category); } void QmlTaskManager::collectMessages( QFutureInterface &future, Snapshot snapshot, QList projectInfos, ViewerContext vContext, bool updateSemantic) { foreach (const ModelManagerInterface::ProjectInfo &info, projectInfos) { QHash > linkMessages; ContextPtr context; if (updateSemantic) { QmlJS::Link link(snapshot, vContext, QmlJS::LibraryInfo()); context = link(&linkMessages); } foreach (const QString &fileName, info.sourceFiles) { Document::Ptr document = snapshot.document(fileName); if (!document) continue; FileErrorMessages result; result.fileName = fileName; if (document->language().isFullySupportedLanguage()) { result.tasks = convertToTasks(document->diagnosticMessages(), FilePath::fromString(fileName), Constants::TASK_CATEGORY_QML); if (updateSemantic) { result.tasks += convertToTasks(linkMessages.value(fileName), FilePath::fromString(fileName), Constants::TASK_CATEGORY_QML_ANALYSIS); Check checker(document, context); result.tasks += convertToTasks(checker(), FilePath::fromString(fileName), Constants::TASK_CATEGORY_QML_ANALYSIS); } } if (!result.tasks.isEmpty()) future.reportResult(result); if (future.isCanceled()) break; } } } void QmlTaskManager::updateMessages() { m_updateDelay.start(); } void QmlTaskManager::updateSemanticMessagesNow() { updateMessagesNow(true); } void QmlTaskManager::updateMessagesNow(bool updateSemantic) { // don't restart a small update if a big one is running if (!updateSemantic && m_updatingSemantic) return; m_updatingSemantic = updateSemantic; // abort any update that's going on already m_messageCollector.cancel(); removeAllTasks(updateSemantic); ModelManagerInterface *modelManager = ModelManagerInterface::instance(); // process them QFuture future = Utils::runAsync( &collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(), modelManager->defaultVContext(Dialect::AnyLanguage), updateSemantic); m_messageCollector.setFuture(future); } void QmlTaskManager::documentsRemoved(const QStringList &path) { foreach (const QString &item, path) removeTasksForFile(item); } void QmlTaskManager::displayResults(int begin, int end) { for (int i = begin; i < end; ++i) { FileErrorMessages result = m_messageCollector.resultAt(i); foreach (const Task &task, result.tasks) { insertTask(task); } } } void QmlTaskManager::displayAllResults() { displayResults(0, m_messageCollector.future().resultCount()); m_updatingSemantic = false; } void QmlTaskManager::insertTask(const Task &task) { Tasks tasks = m_docsWithTasks.value(task.file.toString()); tasks.append(task); m_docsWithTasks.insert(task.file.toString(), tasks); TaskHub::addTask(task); } void QmlTaskManager::removeTasksForFile(const QString &fileName) { if (m_docsWithTasks.contains(fileName)) { const Tasks tasks = m_docsWithTasks.value(fileName); foreach (const Task &task, tasks) TaskHub::removeTask(task); m_docsWithTasks.remove(fileName); } } void QmlTaskManager::removeAllTasks(bool clearSemantic) { TaskHub::clearTasks(Constants::TASK_CATEGORY_QML); if (clearSemantic) TaskHub::clearTasks(Constants::TASK_CATEGORY_QML_ANALYSIS); m_docsWithTasks.clear(); } } // Internal } // QmlProjectManager