kde-extraapps/kdevplatform/language/duchain/problem.cpp
2015-07-26 14:23:17 +03:00

257 lines
6.8 KiB
C++

/* This file is part of KDevelop
Copyright 2007 Hamish Rodda <rodda@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "problem.h"
#include "duchainregister.h"
#include "topducontextdynamicdata.h"
#include "topducontext.h"
#include "topducontextdata.h"
#include "duchain.h"
#include "duchainlock.h"
#include <interfaces/iassistant.h>
#include <KLocalizedString>
namespace KDevelop {
REGISTER_DUCHAIN_ITEM(Problem);
DEFINE_LIST_MEMBER_HASH(ProblemData, diagnostics, LocalIndexedProblem)
}
using namespace KDevelop;
LocalIndexedProblem::LocalIndexedProblem(const ProblemPointer& problem, const TopDUContext* top)
: m_index(problem->m_indexInTopContext)
{
ENSURE_CHAIN_READ_LOCKED
// ensure child problems are properly serialized before we serialize the parent problem
if (static_cast<uint>(problem->m_diagnostics.size()) != problem->d_func()->diagnosticsSize()) {
// see below, the diagnostic size is kept in sync by the mutable API of Problem
Q_ASSERT(!problem->diagnostics().isEmpty());
// the const cast is ugly but we don't really "change" the state as observed from the outside
auto& serialized = const_cast<Problem*>(problem.data())->d_func_dynamic()->diagnosticsList();
Q_ASSERT(serialized.isEmpty());
foreach(const ProblemPointer& child, problem->m_diagnostics) {
serialized << LocalIndexedProblem(child, top);
}
}
if (!m_index) {
m_index = top->m_dynamicData->allocateProblemIndex(problem);
}
}
ProblemPointer LocalIndexedProblem::data(const TopDUContext* top) const
{
if (!m_index) {
return {};
}
return top->m_dynamicData->getProblemForIndex(m_index);
}
Problem::Problem()
: DUChainBase(*new ProblemData)
, m_topContext(nullptr)
, m_indexInTopContext(0)
{
d_func_dynamic()->setClassId(this);
}
Problem::Problem(ProblemData& data)
: DUChainBase(data)
, m_topContext(nullptr)
, m_indexInTopContext(0)
{
}
Problem::~Problem()
{
}
TopDUContext* Problem::topContext() const
{
return m_topContext.data();
}
IndexedString Problem::url() const
{
return d_func()->url;
}
DocumentRange Problem::finalLocation() const
{
return DocumentRange(d_func()->url, rangeInCurrentRevision());
}
void Problem::setFinalLocation(const DocumentRange& location)
{
setRange(transformToLocalRevision(location));
d_func_dynamic()->url = location.document;
}
QList<ProblemPointer> Problem::diagnostics() const
{
return m_diagnostics;
}
void Problem::setDiagnostics(const QList<ProblemPointer>& diagnostics)
{
m_diagnostics = diagnostics;
// keep serialization in sync, see also LocalIndexedProblem ctor above
d_func_dynamic()->diagnosticsList().clear();
}
void Problem::addDiagnostic(const ProblemPointer& diagnostic)
{
m_diagnostics << diagnostic;
}
void Problem::clearDiagnostics()
{
m_diagnostics.clear();
// keep serialization in sync, see also LocalIndexedProblem ctor above
d_func_dynamic()->diagnosticsList().clear();
}
QString Problem::description() const
{
return d_func()->description.str();
}
void Problem::setDescription(const QString& description)
{
d_func_dynamic()->description = IndexedString(description);
}
QString Problem::explanation() const
{
return d_func()->explanation.str();
}
void Problem::setExplanation(const QString& explanation)
{
d_func_dynamic()->explanation = IndexedString(explanation);
}
ProblemData::Source Problem::source() const
{
return d_func()->source;
}
void Problem::setSource(ProblemData::Source source)
{
d_func_dynamic()->source = source;
}
KSharedPtr<IAssistant> Problem::solutionAssistant() const
{
return {};
}
ProblemData::Severity Problem::severity() const
{
return d_func()->severity;
}
void Problem::setSeverity(ProblemData::Severity severity)
{
d_func_dynamic()->severity = severity;
}
QString Problem::severityString() const
{
switch(severity()) {
case ProblemData::Error:
return i18n("Error");
case ProblemData::Warning:
return i18n("Warning");
case ProblemData::Hint:
return i18n("Hint");
}
return QString();
}
QString Problem::sourceString() const
{
switch (source()) {
case ProblemData::Disk:
return i18n("Disk");
case ProblemData::Preprocessor:
return i18n("Preprocessor");
case ProblemData::Lexer:
return i18n("Lexer");
case ProblemData::Parser:
return i18n("Parser");
case ProblemData::DUChainBuilder:
return i18n("Definition-Use Chain");
case ProblemData::SemanticAnalysis:
return i18n("Semantic Analysis");
case ProblemData::ToDo:
return i18n("TODO");
case ProblemData::Unknown:
default:
return i18n("Unknown");
}
}
QString Problem::toString() const
{
return QString("%1: %2 in %3:[(%4,%5),(%6,%7)]: %8 (found by %9)")
.arg(severityString())
.arg(description())
.arg(url().str())
.arg(range().start.line)
.arg(range().start.column)
.arg(range().end.line)
.arg(range().end.column)
.arg((explanation().isEmpty() ? QString("<no explanation>") : explanation()))
.arg(sourceString());
}
void Problem::rebuildDynamicData(DUContext* parent, uint ownIndex)
{
auto top = dynamic_cast<TopDUContext*>(parent);
Q_ASSERT(top);
m_topContext = top;
m_indexInTopContext = ownIndex;
// deserialize child diagnostics here, as the top-context might get unloaded
// but we still want to keep the child-diagnostics in-tact, as one would assume
// a shared-ptr works.
const auto data = d_func();
m_diagnostics.reserve(data->diagnosticsSize());
for (uint i = 0; i < data->diagnosticsSize(); ++i) {
m_diagnostics << ProblemPointer(data->diagnostics()[i].data(top));
}
DUChainBase::rebuildDynamicData(parent, ownIndex);
}
QDebug operator<<(QDebug s, const Problem& problem)
{
s.nospace() << problem.toString();
return s.space();
}
QDebug operator<<(QDebug s, const ProblemPointer& problem)
{
s.nospace() << problem->toString();
return s.space();
}