File indexing completed on 2024-05-12 04:37:41
0001 /* 0002 SPDX-FileCopyrightText: 2009 David Nolden <david.nolden.kdevelop@art-master.de> 0003 SPDX-FileCopyrightText: 2014 Kevin Funk <kfunk@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "staticassistantsmanager.h" 0009 #include <debug.h> 0010 0011 #include <KTextEditor/Document> 0012 #include <KTextEditor/View> 0013 0014 #include <interfaces/icore.h> 0015 #include <interfaces/idocumentcontroller.h> 0016 #include <interfaces/ilanguagecontroller.h> 0017 #include <interfaces/ilanguagesupport.h> 0018 0019 #include <language/duchain/duchainlock.h> 0020 #include <language/duchain/duchain.h> 0021 #include <language/duchain/declaration.h> 0022 #include <language/duchain/duchainutils.h> 0023 0024 #include <language/duchain/problem.h> 0025 #include <language/editor/documentrange.h> 0026 0027 using namespace KDevelop; 0028 using namespace KTextEditor; 0029 0030 class KDevelop::StaticAssistantsManagerPrivate 0031 { 0032 public: 0033 explicit StaticAssistantsManagerPrivate(StaticAssistantsManager* qq) 0034 : q(qq) 0035 { } 0036 0037 void updateReady(const IndexedString& document, const KDevelop::ReferencedTopDUContext& topContext); 0038 void documentLoaded(KDevelop::IDocument*); 0039 void textInserted(KTextEditor::Document* document, const Cursor& cursor, const QString& text); 0040 void textRemoved(KTextEditor::Document* document, const Range& cursor, const QString& removedText); 0041 0042 StaticAssistantsManager* q; 0043 0044 QVector<StaticAssistant::Ptr> m_registeredAssistants; 0045 }; 0046 0047 StaticAssistantsManager::StaticAssistantsManager(QObject* parent) 0048 : QObject(parent) 0049 , d_ptr(new StaticAssistantsManagerPrivate(this)) 0050 { 0051 Q_D(StaticAssistantsManager); 0052 0053 connect(KDevelop::ICore::self()->documentController(), 0054 &IDocumentController::documentLoaded, 0055 this, [this](IDocument* document) { 0056 Q_D(StaticAssistantsManager); 0057 d->documentLoaded(document); 0058 }); 0059 const auto documents = ICore::self()->documentController()->openDocuments(); 0060 for (IDocument* document : documents) { 0061 d->documentLoaded(document); 0062 } 0063 0064 connect(DUChain::self(), &DUChain::updateReady, 0065 this, &StaticAssistantsManager::notifyAssistants); 0066 } 0067 0068 StaticAssistantsManager::~StaticAssistantsManager() 0069 { 0070 } 0071 0072 void StaticAssistantsManager::registerAssistant(const StaticAssistant::Ptr& assistant) 0073 { 0074 Q_D(StaticAssistantsManager); 0075 0076 if (d->m_registeredAssistants.contains(assistant)) 0077 return; 0078 0079 d->m_registeredAssistants << assistant; 0080 } 0081 0082 void StaticAssistantsManager::unregisterAssistant(const StaticAssistant::Ptr& assistant) 0083 { 0084 Q_D(StaticAssistantsManager); 0085 0086 d->m_registeredAssistants.removeOne(assistant); 0087 } 0088 0089 QVector<StaticAssistant::Ptr> StaticAssistantsManager::registeredAssistants() const 0090 { 0091 Q_D(const StaticAssistantsManager); 0092 0093 return d->m_registeredAssistants; 0094 } 0095 0096 void StaticAssistantsManagerPrivate::documentLoaded(IDocument* document) 0097 { 0098 if (document->textDocument()) { 0099 auto doc = document->textDocument(); 0100 QObject::connect(doc, &KTextEditor::Document::textInserted, q, 0101 [&](KTextEditor::Document* doc, const Cursor& cursor, const QString& text) { 0102 textInserted(doc, cursor, text); 0103 }); 0104 QObject::connect(doc, &KTextEditor::Document::textRemoved, q, 0105 [&](KTextEditor::Document* doc, const Range& range, const QString& removedText) { 0106 textRemoved(doc, range, removedText); 0107 }); 0108 } 0109 } 0110 0111 void StaticAssistantsManagerPrivate::textInserted(Document* doc, const Cursor& cursor, const QString& text) 0112 { 0113 auto changed = false; 0114 for (auto& assistant : qAsConst(m_registeredAssistants)) { 0115 auto range = Range(cursor, cursor + Cursor(0, text.size())); 0116 auto wasUseful = assistant->isUseful(); 0117 assistant->textChanged(doc, range, {}); 0118 if (wasUseful != assistant->isUseful()) { 0119 changed = true; 0120 } 0121 } 0122 0123 if (changed) { 0124 Q_EMIT q->problemsChanged(IndexedString(doc->url())); 0125 } 0126 } 0127 0128 void StaticAssistantsManagerPrivate::textRemoved(Document* doc, const Range& range, 0129 const QString& removedText) 0130 { 0131 auto changed = false; 0132 for (auto& assistant : qAsConst(m_registeredAssistants)) { 0133 auto wasUseful = assistant->isUseful(); 0134 assistant->textChanged(doc, range, removedText); 0135 if (wasUseful != assistant->isUseful()) { 0136 changed = true; 0137 } 0138 } 0139 0140 if (changed) { 0141 Q_EMIT q->problemsChanged(IndexedString(doc->url())); 0142 } 0143 } 0144 0145 void StaticAssistantsManager::notifyAssistants(const IndexedString& url, 0146 const KDevelop::ReferencedTopDUContext& context) 0147 { 0148 Q_D(StaticAssistantsManager); 0149 0150 for (auto& assistant : qAsConst(d->m_registeredAssistants)) { 0151 assistant->updateReady(url, context); 0152 } 0153 } 0154 0155 QVector<KDevelop::Problem::Ptr> KDevelop::StaticAssistantsManager::problemsForContext( 0156 const KDevelop::ReferencedTopDUContext& top) const 0157 { 0158 Q_D(const StaticAssistantsManager); 0159 0160 View* view = ICore::self()->documentController()->activeTextDocumentView(); 0161 if (!view || !top || IndexedString(view->document()->url()) != top->url()) { 0162 return {}; 0163 } 0164 0165 auto doc = top->url(); 0166 auto language = ICore::self()->languageController()->languagesForUrl(doc.toUrl()).value(0); 0167 if (!language) { 0168 return {}; 0169 } 0170 0171 auto ret = QVector<KDevelop::Problem::Ptr>(); 0172 qCDebug(LANGUAGE) << "Trying to find assistants for language" << language->name(); 0173 for (const auto& assistant : qAsConst(d->m_registeredAssistants)) { 0174 if (assistant->supportedLanguage() != language) 0175 continue; 0176 0177 if (assistant->isUseful()) { 0178 qCDebug(LANGUAGE) << "assistant is now useful:" << assistant.data(); 0179 0180 auto p = new KDevelop::StaticAssistantProblem(); 0181 auto range = assistant->displayRange(); 0182 qCDebug(LANGUAGE) << "range:" << range; 0183 p->setFinalLocation(DocumentRange(doc, range)); 0184 p->setSource(KDevelop::IProblem::SemanticAnalysis); 0185 p->setSeverity(KDevelop::IProblem::Warning); 0186 p->setDescription(assistant->title()); 0187 p->setSolutionAssistant(IAssistant::Ptr(assistant.data())); 0188 0189 ret.append(KDevelop::Problem::Ptr(p)); 0190 } 0191 } 0192 0193 return ret; 0194 } 0195 0196 #include "moc_staticassistantsmanager.cpp"