File indexing completed on 2024-05-12 04:38:04
0001 /* 0002 SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "problem.h" 0008 0009 #include "duchainregister.h" 0010 #include "topducontextdynamicdata.h" 0011 #include "topducontext.h" 0012 #include "topducontextdata.h" 0013 #include "duchain.h" 0014 #include "duchainlock.h" 0015 0016 #include <editor/documentrange.h> 0017 0018 #include <interfaces/iassistant.h> 0019 0020 #include <KLocalizedString> 0021 0022 namespace KDevelop { 0023 REGISTER_DUCHAIN_ITEM(Problem); 0024 DEFINE_LIST_MEMBER_HASH(ProblemData, diagnostics, LocalIndexedProblem) 0025 } 0026 0027 using namespace KDevelop; 0028 0029 LocalIndexedProblem::LocalIndexedProblem(const ProblemPointer& problem, const TopDUContext* top) 0030 : m_index(problem->m_indexInTopContext) 0031 { 0032 ENSURE_CHAIN_READ_LOCKED 0033 // ensure child problems are properly serialized before we serialize the parent problem 0034 // see below, the diagnostic size is kept in sync by the mutable API of Problem 0035 // the const cast is ugly but we don't really "change" the state as observed from the outside 0036 auto& serialized = const_cast<Problem*>(problem.data())->d_func_dynamic()->diagnosticsList(); 0037 serialized.clear(); 0038 serialized.reserve(problem->m_diagnostics.size()); 0039 for (const ProblemPointer& child : qAsConst(problem->m_diagnostics)) { 0040 serialized << LocalIndexedProblem(child, top); 0041 } 0042 0043 if (!m_index) { 0044 m_index = top->m_dynamicData->allocateProblemIndex(problem); 0045 } 0046 } 0047 0048 ProblemPointer LocalIndexedProblem::data(const TopDUContext* top) const 0049 { 0050 if (!m_index) { 0051 return {}; 0052 } 0053 return top->m_dynamicData->problemForIndex(m_index); 0054 } 0055 0056 Problem::Problem() 0057 : DUChainBase(*new ProblemData) 0058 { 0059 d_func_dynamic()->setClassId(this); 0060 } 0061 0062 Problem::Problem(ProblemData& data) 0063 : DUChainBase(data) 0064 { 0065 } 0066 0067 Problem::~Problem() 0068 { 0069 } 0070 0071 TopDUContext* Problem::topContext() const 0072 { 0073 return m_topContext.data(); 0074 } 0075 0076 IndexedString Problem::url() const 0077 { 0078 return d_func()->url; 0079 } 0080 0081 DocumentRange Problem::finalLocation() const 0082 { 0083 return DocumentRange(d_func()->url, d_func()->m_range.castToSimpleRange()); 0084 } 0085 0086 void Problem::setFinalLocation(const DocumentRange& location) 0087 { 0088 setRange(RangeInRevision::castFromSimpleRange(location)); 0089 d_func_dynamic()->url = location.document; 0090 } 0091 0092 IProblem::FinalLocationMode Problem::finalLocationMode() const 0093 { 0094 return d_func()->finalLocationMode; 0095 } 0096 0097 void Problem::setFinalLocationMode(IProblem::FinalLocationMode mode) 0098 { 0099 d_func_dynamic()->finalLocationMode = mode; 0100 } 0101 0102 void Problem::clearDiagnostics() 0103 { 0104 m_diagnostics.clear(); 0105 // keep serialization in sync, see also LocalIndexedProblem ctor above 0106 d_func_dynamic()->diagnosticsList().clear(); 0107 } 0108 0109 QVector<IProblem::Ptr> Problem::diagnostics() const 0110 { 0111 QVector<IProblem::Ptr> vector; 0112 0113 for (const auto& ptr : qAsConst(m_diagnostics)) { 0114 vector.push_back(ptr); 0115 } 0116 0117 return vector; 0118 } 0119 0120 void Problem::setDiagnostics(const QVector<IProblem::Ptr>& diagnostics) 0121 { 0122 clearDiagnostics(); 0123 0124 for (const IProblem::Ptr& problem : diagnostics) { 0125 addDiagnostic(problem); 0126 } 0127 } 0128 0129 void Problem::addDiagnostic(const IProblem::Ptr& diagnostic) 0130 { 0131 auto* problem = dynamic_cast<Problem*>(diagnostic.data()); 0132 Q_ASSERT(problem != nullptr); 0133 0134 ProblemPointer ptr(problem); 0135 0136 m_diagnostics << ptr; 0137 } 0138 0139 QString Problem::description() const 0140 { 0141 return d_func()->description.str(); 0142 } 0143 0144 void Problem::setDescription(const QString& description) 0145 { 0146 d_func_dynamic()->description = IndexedString(description); 0147 } 0148 0149 QString Problem::explanation() const 0150 { 0151 return d_func()->explanation.str(); 0152 } 0153 0154 void Problem::setExplanation(const QString& explanation) 0155 { 0156 d_func_dynamic()->explanation = IndexedString(explanation); 0157 } 0158 0159 IProblem::Source Problem::source() const 0160 { 0161 return d_func()->source; 0162 } 0163 0164 void Problem::setSource(IProblem::Source source) 0165 { 0166 d_func_dynamic()->source = source; 0167 } 0168 0169 QExplicitlySharedDataPointer<IAssistant> Problem::solutionAssistant() const 0170 { 0171 return {}; 0172 } 0173 0174 IProblem::Severity Problem::severity() const 0175 { 0176 return d_func()->severity; 0177 } 0178 0179 void Problem::setSeverity(Severity severity) 0180 { 0181 d_func_dynamic()->severity = severity; 0182 } 0183 0184 QString Problem::severityString() const 0185 { 0186 switch (severity()) { 0187 case IProblem::NoSeverity: 0188 return {}; 0189 case IProblem::Error: 0190 return i18n("Error"); 0191 case IProblem::Warning: 0192 return i18n("Warning"); 0193 case IProblem::Hint: 0194 return i18n("Hint"); 0195 } 0196 return QString(); 0197 } 0198 0199 QString Problem::sourceString() const 0200 { 0201 switch (source()) { 0202 case IProblem::Disk: 0203 return i18n("Disk"); 0204 case IProblem::Preprocessor: 0205 return i18n("Preprocessor"); 0206 case IProblem::Lexer: 0207 return i18n("Lexer"); 0208 case IProblem::Parser: 0209 return i18n("Parser"); 0210 case IProblem::DUChainBuilder: 0211 return i18n("Definition-Use Chain"); 0212 case IProblem::SemanticAnalysis: 0213 return i18n("Semantic analysis"); 0214 case IProblem::ToDo: 0215 return i18n("To-do"); 0216 case IProblem::Unknown: 0217 default: 0218 return i18n("Unknown"); 0219 } 0220 } 0221 0222 QString Problem::toString() const 0223 { 0224 return i18nc("<severity>: <description> in <url>:[<range>]: <explanation> (found by <source>)", 0225 "%1: %2 in %3:[(%4,%5),(%6,%7)]: %8 (found by %9)", 0226 severityString(), 0227 description(), 0228 url().str(), 0229 range().start.line, 0230 range().start.column, 0231 range().end.line, 0232 range().end.column, 0233 (explanation().isEmpty() ? i18n("<no explanation>") : explanation()), 0234 sourceString()); 0235 } 0236 0237 void Problem::rebuildDynamicData(DUContext* parent, uint ownIndex) 0238 { 0239 auto top = dynamic_cast<TopDUContext*>(parent); 0240 Q_ASSERT(top); 0241 0242 m_topContext = top; 0243 m_indexInTopContext = ownIndex; 0244 0245 // deserialize child diagnostics here, as the top-context might get unloaded 0246 // but we still want to keep the child-diagnostics in-tact, as one would assume 0247 // a shared-ptr works. 0248 const auto data = d_func(); 0249 m_diagnostics.reserve(data->diagnosticsSize()); 0250 for (uint i = 0; i < data->diagnosticsSize(); ++i) { 0251 m_diagnostics << ProblemPointer(data->diagnostics()[i].data(top)); 0252 } 0253 0254 DUChainBase::rebuildDynamicData(parent, ownIndex); 0255 } 0256 0257 QDebug operator<<(QDebug s, const Problem& problem) 0258 { 0259 s.nospace() << problem.toString(); 0260 return s.space(); 0261 } 0262 0263 QDebug operator<<(QDebug s, const ProblemPointer& problem) 0264 { 0265 if (!problem) { 0266 s.nospace() << "<invalid problem>"; 0267 } else { 0268 s.nospace() << problem->toString(); 0269 } 0270 return s.space(); 0271 }