File indexing completed on 2024-04-28 04:37:17
0001 /* 0002 SPDX-FileCopyrightText: 2015 Laszlo Kis-Adam <laszlo.kis-adam@kdemail.net> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "filteredproblemstore.h" 0008 0009 #include "problem.h" 0010 #include "watcheddocumentset.h" 0011 #include "problemstorenode.h" 0012 0013 #include <language/editor/documentrange.h> 0014 0015 #include <KLocalizedString> 0016 0017 using namespace KDevelop; 0018 0019 namespace 0020 { 0021 0022 /// Adds diagnostics as sub-nodes 0023 void addDiagnostics(ProblemStoreNode *node, const QVector<IProblem::Ptr> &diagnostics) 0024 { 0025 for (const IProblem::Ptr& ptr : diagnostics) { 0026 auto *child = new ProblemNode(node, ptr); 0027 node->addChild(child); 0028 0029 addDiagnostics(child, ptr->diagnostics()); 0030 } 0031 } 0032 0033 /** 0034 * @brief Base class for grouping strategy classes 0035 * 0036 * These classes build the problem tree based on the respective strategies 0037 */ 0038 class GroupingStrategy 0039 { 0040 public: 0041 explicit GroupingStrategy( ProblemStoreNode *root ) 0042 : m_rootNode(root) 0043 , m_groupedRootNode(new ProblemStoreNode()) 0044 { 0045 } 0046 0047 virtual ~GroupingStrategy(){ 0048 } 0049 0050 /// Add a problem to the appropriate group 0051 virtual void addProblem(const IProblem::Ptr &problem) = 0; 0052 0053 /// Find the specified noe 0054 const ProblemStoreNode* findNode(int row, ProblemStoreNode *parent = nullptr) const 0055 { 0056 if (parent == nullptr) 0057 return m_groupedRootNode->child(row); 0058 else 0059 return parent->child(row); 0060 } 0061 0062 /// Returns the number of children nodes 0063 int count(ProblemStoreNode *parent = nullptr) 0064 { 0065 if (parent == nullptr) 0066 return m_groupedRootNode->count(); 0067 else 0068 return parent->count(); 0069 } 0070 0071 /// Clears the problems 0072 virtual void clear() 0073 { 0074 m_groupedRootNode->clear(); 0075 } 0076 0077 protected: 0078 ProblemStoreNode* const m_rootNode; 0079 QScopedPointer<ProblemStoreNode> m_groupedRootNode; 0080 }; 0081 0082 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 0083 0084 /// Implements no grouping strategy, that is just stores the problems without any grouping 0085 class NoGroupingStrategy final : public GroupingStrategy 0086 { 0087 public: 0088 explicit NoGroupingStrategy(ProblemStoreNode *root) 0089 : GroupingStrategy(root) 0090 { 0091 } 0092 0093 void addProblem(const IProblem::Ptr &problem) override 0094 { 0095 auto *node = new ProblemNode(m_groupedRootNode.data(), problem); 0096 addDiagnostics(node, problem->diagnostics()); 0097 m_groupedRootNode->addChild(node); 0098 0099 } 0100 0101 }; 0102 0103 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 0104 0105 /// Implements grouping based on path 0106 class PathGroupingStrategy final : public GroupingStrategy 0107 { 0108 public: 0109 explicit PathGroupingStrategy(ProblemStoreNode *root) 0110 : GroupingStrategy(root) 0111 { 0112 } 0113 0114 void addProblem(const IProblem::Ptr &problem) override 0115 { 0116 QString path = problem->finalLocation().document.str(); 0117 0118 /// See if we already have this path 0119 const auto childrenNodes = m_groupedRootNode->children(); 0120 auto it = std::find_if(childrenNodes.begin(), childrenNodes.end(), [&](ProblemStoreNode* node) { 0121 return (node->label() == path); 0122 }); 0123 ProblemStoreNode* parent = (it != childrenNodes.end()) ? *it : nullptr; 0124 0125 /// If not add it! 0126 if (parent == nullptr) { 0127 parent = new LabelNode(m_groupedRootNode.data(), path); 0128 m_groupedRootNode->addChild(parent); 0129 } 0130 0131 auto *node = new ProblemNode(parent, problem); 0132 addDiagnostics(node, problem->diagnostics()); 0133 parent->addChild(node); 0134 } 0135 0136 }; 0137 0138 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 0139 0140 /// Implements grouping based on severity 0141 class SeverityGroupingStrategy final : public GroupingStrategy 0142 { 0143 public: 0144 enum SeverityGroups 0145 { 0146 GroupError = 0, 0147 GroupWarning = 1, 0148 GroupHint = 2 0149 }; 0150 0151 explicit SeverityGroupingStrategy(ProblemStoreNode *root) 0152 : GroupingStrategy(root) 0153 { 0154 /// Create the groups on construction, so there's no need to search for them on addition 0155 m_groupedRootNode->addChild(new LabelNode(m_groupedRootNode.data(), i18n("Error"))); 0156 m_groupedRootNode->addChild(new LabelNode(m_groupedRootNode.data(), i18n("Warning"))); 0157 m_groupedRootNode->addChild(new LabelNode(m_groupedRootNode.data(), i18n("Hint"))); 0158 } 0159 0160 void addProblem(const IProblem::Ptr &problem) override 0161 { 0162 ProblemStoreNode *parent = nullptr; 0163 0164 switch (problem->severity()) { 0165 case IProblem::Error: parent = m_groupedRootNode->child(GroupError); break; 0166 case IProblem::Warning: parent = m_groupedRootNode->child(GroupWarning); break; 0167 case IProblem::Hint: parent = m_groupedRootNode->child(GroupHint); break; 0168 default: break; 0169 } 0170 0171 auto *node = new ProblemNode(m_groupedRootNode.data(), problem); 0172 addDiagnostics(node, problem->diagnostics()); 0173 parent->addChild(node); 0174 } 0175 0176 void clear() override 0177 { 0178 m_groupedRootNode->child(GroupError)->clear(); 0179 m_groupedRootNode->child(GroupWarning)->clear(); 0180 m_groupedRootNode->child(GroupHint)->clear(); 0181 } 0182 }; 0183 0184 } 0185 0186 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 0187 0188 namespace KDevelop 0189 { 0190 0191 class FilteredProblemStorePrivate 0192 { 0193 public: 0194 explicit FilteredProblemStorePrivate(FilteredProblemStore* q) 0195 : q(q) 0196 , m_strategy(new NoGroupingStrategy(q->rootNode())) 0197 , m_grouping(NoGrouping) 0198 { 0199 } 0200 0201 /// Tells if the problem matches the filters 0202 bool match(const IProblem::Ptr &problem) const; 0203 0204 FilteredProblemStore* const q; 0205 QScopedPointer<GroupingStrategy> m_strategy; 0206 GroupingMethod m_grouping; 0207 }; 0208 0209 FilteredProblemStore::FilteredProblemStore(QObject *parent) 0210 : ProblemStore(parent) 0211 , d_ptr(new FilteredProblemStorePrivate(this)) 0212 { 0213 } 0214 0215 FilteredProblemStore::~FilteredProblemStore() 0216 { 0217 } 0218 0219 void FilteredProblemStore::addProblem(const IProblem::Ptr &problem) 0220 { 0221 Q_D(FilteredProblemStore); 0222 0223 ProblemStore::addProblem(problem); 0224 0225 if (d->match(problem)) 0226 d->m_strategy->addProblem(problem); 0227 } 0228 0229 const ProblemStoreNode* FilteredProblemStore::findNode(int row, ProblemStoreNode *parent) const 0230 { 0231 Q_D(const FilteredProblemStore); 0232 0233 return d->m_strategy->findNode(row, parent); 0234 } 0235 0236 int FilteredProblemStore::count(ProblemStoreNode *parent) const 0237 { 0238 Q_D(const FilteredProblemStore); 0239 0240 return d->m_strategy->count(parent); 0241 } 0242 0243 void FilteredProblemStore::clear() 0244 { 0245 Q_D(FilteredProblemStore); 0246 0247 d->m_strategy->clear(); 0248 ProblemStore::clear(); 0249 } 0250 0251 void FilteredProblemStore::rebuild() 0252 { 0253 Q_D(FilteredProblemStore); 0254 0255 emit beginRebuild(); 0256 0257 d->m_strategy->clear(); 0258 0259 const auto childrenNodes = rootNode()->children(); 0260 for (ProblemStoreNode* node : childrenNodes) { 0261 IProblem::Ptr problem = node->problem(); 0262 if (d->match(problem)) { 0263 d->m_strategy->addProblem(problem); 0264 } 0265 } 0266 0267 emit endRebuild(); 0268 } 0269 0270 void FilteredProblemStore::setGrouping(int grouping) 0271 { 0272 Q_D(FilteredProblemStore); 0273 0274 auto g = GroupingMethod(grouping); 0275 if(g == d->m_grouping) 0276 return; 0277 0278 d->m_grouping = g; 0279 0280 switch (g) { 0281 case NoGrouping: d->m_strategy.reset(new NoGroupingStrategy(rootNode())); break; 0282 case PathGrouping: d->m_strategy.reset(new PathGroupingStrategy(rootNode())); break; 0283 case SeverityGrouping: d->m_strategy.reset(new SeverityGroupingStrategy(rootNode())); break; 0284 } 0285 0286 rebuild(); 0287 emit changed(); 0288 } 0289 0290 int FilteredProblemStore::grouping() const 0291 { 0292 Q_D(const FilteredProblemStore); 0293 0294 return d->m_grouping; 0295 } 0296 0297 bool FilteredProblemStorePrivate::match(const IProblem::Ptr &problem) const 0298 { 0299 if (q->scope() != ProblemScope::BypassScopeFilter && 0300 !q->documents()->get().contains(problem.data()->finalLocation().document) && 0301 !(q->showImports() && q->documents()->imports().contains(problem.data()->finalLocation().document))) 0302 return false; 0303 0304 if(problem->severity()!=IProblem::NoSeverity) 0305 { 0306 /// If the problem severity isn't in the filter severities it's discarded 0307 if(!q->severities().testFlag(problem->severity())) 0308 return false; 0309 } 0310 else 0311 { 0312 if(!q->severities().testFlag(IProblem::Hint))//workaround for problems without correctly set severity 0313 return false; 0314 } 0315 0316 return true; 0317 } 0318 0319 } 0320 0321 #include "moc_filteredproblemstore.cpp"