File indexing completed on 2024-05-05 04:39:30

0001 /*
0002     SPDX-FileCopyrightText: 2017 Anton Anikin <anton.anikin@htower.ru>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "problemmodel.h"
0008 
0009 #include "plugin.h"
0010 #include "utils.h"
0011 
0012 #include <interfaces/icore.h>
0013 #include <interfaces/ilanguagecontroller.h>
0014 #include <interfaces/iproject.h>
0015 #include <language/editor/documentrange.h>
0016 #include <shell/problemmodelset.h>
0017 
0018 #include <KLocalizedString>
0019 
0020 namespace cppcheck
0021 {
0022 
0023 inline KDevelop::ProblemModelSet* problemModelSet()
0024 {
0025     return KDevelop::ICore::self()->languageController()->problemModelSet();
0026 }
0027 
0028 namespace Strings {
0029 QString problemModelId() { return QStringLiteral("Cppcheck"); }
0030 }
0031 
0032 ProblemModel::ProblemModel(Plugin* plugin)
0033     : KDevelop::ProblemModel(plugin)
0034     , m_plugin(plugin)
0035     , m_project(nullptr)
0036     , m_pathLocation(KDevelop::DocumentRange::invalid())
0037 {
0038     setFeatures(CanDoFullUpdate | ScopeFilter | SeverityFilter | Grouping | CanByPassScopeFilter);
0039     reset();
0040     problemModelSet()->addModel(Strings::problemModelId(), i18n("Cppcheck"), this);
0041 }
0042 
0043 ProblemModel::~ProblemModel()
0044 {
0045     problemModelSet()->removeModel(Strings::problemModelId());
0046 }
0047 
0048 KDevelop::IProject* ProblemModel::project() const
0049 {
0050     return m_project;
0051 }
0052 
0053 void ProblemModel::fixProblemFinalLocation(KDevelop::IProblem::Ptr problem)
0054 {
0055     // Fix problems with incorrect range, which produced by cppcheck's errors
0056     // without <location> element. In this case location automatically gets "/".
0057     // To avoid this we set current analysis path as problem location.
0058 
0059     if (problem->finalLocation().document.isEmpty()) {
0060         problem->setFinalLocation(m_pathLocation);
0061     }
0062 
0063     const auto& diagnostics = problem->diagnostics();
0064     for (auto& diagnostic : diagnostics) {
0065         fixProblemFinalLocation(diagnostic);
0066     }
0067 }
0068 
0069 bool ProblemModel::problemExists(KDevelop::IProblem::Ptr newProblem)
0070 {
0071     for (auto problem : qAsConst(m_problems)) {
0072         if (newProblem->source() == problem->source() &&
0073             newProblem->severity() == problem->severity() &&
0074             newProblem->finalLocation() == problem->finalLocation() &&
0075             newProblem->description() == problem->description() &&
0076             newProblem->explanation() == problem->explanation())
0077             return true;
0078     }
0079 
0080     return false;
0081 }
0082 
0083 void ProblemModel::setMessage(const QString& message)
0084 {
0085     setPlaceholderText(message, m_pathLocation, i18n("Cppcheck"));
0086 }
0087 
0088 void ProblemModel::addProblems(const QVector<KDevelop::IProblem::Ptr>& problems)
0089 {
0090     static int maxLength = 0;
0091 
0092     if (m_problems.isEmpty()) {
0093         maxLength = 0;
0094     }
0095 
0096     for (auto problem : problems) {
0097         fixProblemFinalLocation(problem);
0098 
0099         if (problemExists(problem)) {
0100             continue;
0101         }
0102 
0103         m_problems.append(problem);
0104         addProblem(problem);
0105 
0106         // This performs adjusting of columns width in the ProblemsView
0107         if (maxLength < problem->description().length()) {
0108             maxLength = problem->description().length();
0109             setProblems(m_problems);
0110         }
0111     }
0112 }
0113 
0114 void ProblemModel::setProblems()
0115 {
0116     setMessage(i18n("Analysis completed, no problems detected."));
0117     setProblems(m_problems);
0118 }
0119 
0120 void ProblemModel::reset()
0121 {
0122     reset(nullptr, QString());
0123 }
0124 
0125 void ProblemModel::reset(KDevelop::IProject* project, const QString& path)
0126 {
0127     m_project = project;
0128 
0129     m_path = path;
0130     m_pathLocation.document = KDevelop::IndexedString(m_path);
0131 
0132     clearProblems();
0133     m_problems.clear();
0134 
0135     QString tooltip;
0136     if (m_project) {
0137         setMessage(i18n("Analysis started..."));
0138         tooltip = i18nc("@info:tooltip %1 is the path of the file", "Re-run last Cppcheck analysis (%1)", prettyPathName(m_path));
0139     } else {
0140         tooltip = i18nc("@info:tooltip", "Re-run last Cppcheck analysis");
0141     }
0142 
0143     setFullUpdateTooltip(tooltip);
0144 }
0145 
0146 void ProblemModel::show()
0147 {
0148     problemModelSet()->showModel(Strings::problemModelId());
0149 }
0150 
0151 void ProblemModel::forceFullUpdate()
0152 {
0153     if (m_project && !m_plugin->isRunning()) {
0154         m_plugin->runCppcheck(m_project, m_path);
0155     }
0156 }
0157 
0158 }
0159 
0160 #include "moc_problemmodel.cpp"