File indexing completed on 2024-05-05 16:46:08
0001 /* 0002 SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org> 0003 SPDX-FileCopyrightText: 2015 Laszlo Kis-Adam <laszlo.kis-adam@kdemail.net> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "problemreportermodel.h" 0009 0010 #include <language/backgroundparser/backgroundparser.h> 0011 #include <language/duchain/duchain.h> 0012 #include <language/duchain/duchainlock.h> 0013 #include <language/duchain/parsingenvironment.h> 0014 #include <language/duchain/topducontext.h> 0015 #include <language/duchain/problem.h> 0016 #include <language/duchain/duchainutils.h> 0017 #include <language/assistant/staticassistantsmanager.h> 0018 0019 #include <QThread> 0020 #include <QTimer> 0021 0022 #include <serialization/indexedstring.h> 0023 0024 #include <shell/watcheddocumentset.h> 0025 #include <shell/filteredproblemstore.h> 0026 0027 #include <interfaces/icore.h> 0028 #include <interfaces/ilanguagecontroller.h> 0029 #include <interfaces/idocument.h> 0030 0031 using namespace KDevelop; 0032 0033 const int ProblemReporterModel::MinTimeout = 1000; 0034 const int ProblemReporterModel::MaxTimeout = 5000; 0035 0036 ProblemReporterModel::ProblemReporterModel(QObject* parent) 0037 : ProblemModel(parent, new FilteredProblemStore()) 0038 { 0039 setFeatures(CanDoFullUpdate | CanShowImports | ScopeFilter | SeverityFilter | ShowSource); 0040 0041 m_minTimer = new QTimer(this); 0042 m_minTimer->setInterval(MinTimeout); 0043 m_minTimer->setSingleShot(true); 0044 connect(m_minTimer, &QTimer::timeout, this, &ProblemReporterModel::timerExpired); 0045 m_maxTimer = new QTimer(this); 0046 m_maxTimer->setInterval(MaxTimeout); 0047 m_maxTimer->setSingleShot(true); 0048 connect(m_maxTimer, &QTimer::timeout, this, &ProblemReporterModel::timerExpired); 0049 connect(store(), &FilteredProblemStore::changed, this, &ProblemReporterModel::onProblemsChanged); 0050 connect(ICore::self()->languageController()->staticAssistantsManager(), &StaticAssistantsManager::problemsChanged, 0051 this, &ProblemReporterModel::onProblemsChanged); 0052 } 0053 0054 ProblemReporterModel::~ProblemReporterModel() 0055 { 0056 } 0057 0058 QVector<KDevelop::IProblem::Ptr> ProblemReporterModel::problems(const QSet<KDevelop::IndexedString>& docs) const 0059 { 0060 QVector<IProblem::Ptr> result; 0061 DUChainReadLocker lock; 0062 0063 for (const IndexedString& doc : docs) { 0064 if (doc.isEmpty()) 0065 continue; 0066 0067 TopDUContext* ctx = DUChain::self()->chainForDocument(doc); 0068 if (!ctx) 0069 continue; 0070 0071 const auto allProblems = DUChainUtils::allProblemsForContext(ctx); 0072 result.reserve(result.size() + allProblems.size()); 0073 for (const ProblemPointer& p : allProblems) { 0074 result.append(p); 0075 } 0076 } 0077 0078 return result; 0079 } 0080 0081 void ProblemReporterModel::forceFullUpdate() 0082 { 0083 Q_ASSERT(thread() == QThread::currentThread()); 0084 0085 QSet<IndexedString> documents = store()->documents()->get(); 0086 if (showImports()) 0087 documents += store()->documents()->imports(); 0088 0089 DUChainReadLocker lock(DUChain::lock()); 0090 for (const IndexedString& document : qAsConst(documents)) { 0091 if (document.isEmpty()) 0092 continue; 0093 0094 TopDUContext::Features updateType = TopDUContext::ForceUpdate; 0095 if (documents.size() == 1) 0096 updateType = TopDUContext::ForceUpdateRecursive; 0097 DUChain::self()->updateContextForUrl( 0098 document, updateType | TopDUContext::VisibleDeclarationsAndContexts); 0099 } 0100 } 0101 0102 void ProblemReporterModel::onProblemsChanged() 0103 { 0104 rebuildProblemList(); 0105 } 0106 0107 void ProblemReporterModel::timerExpired() 0108 { 0109 m_minTimer->stop(); 0110 m_maxTimer->stop(); 0111 rebuildProblemList(); 0112 } 0113 0114 void ProblemReporterModel::setCurrentDocument(KDevelop::IDocument* doc) 0115 { 0116 Q_ASSERT(thread() == QThread::currentThread()); 0117 0118 beginResetModel(); 0119 0120 /// Will trigger signal changed() if problems change 0121 store()->setCurrentDocument(IndexedString(doc->url())); 0122 endResetModel(); 0123 } 0124 0125 void ProblemReporterModel::problemsUpdated(const KDevelop::IndexedString& url) 0126 { 0127 Q_ASSERT(thread() == QThread::currentThread()); 0128 0129 // skip update for urls outside current scope 0130 if (!store()->documents()->get().contains(url) && 0131 !(showImports() && store()->documents()->imports().contains(url))) 0132 return; 0133 0134 /// m_minTimer will expire in MinTimeout unless some other parsing job finishes in this period. 0135 m_minTimer->start(); 0136 /// m_maxTimer will expire unconditionally in MaxTimeout 0137 if (!m_maxTimer->isActive()) { 0138 m_maxTimer->start(); 0139 } 0140 } 0141 0142 void ProblemReporterModel::rebuildProblemList() 0143 { 0144 /// No locking here, because it may be called from an already locked context 0145 beginResetModel(); 0146 0147 QVector<IProblem::Ptr> allProblems = problems(store()->documents()->get()); 0148 0149 if (showImports()) 0150 allProblems += problems(store()->documents()->imports()); 0151 0152 store()->setProblems(allProblems); 0153 0154 endResetModel(); 0155 } 0156 0157 #include "moc_problemreportermodel.cpp"