File indexing completed on 2024-05-12 04:39:22

0001 /*
0002     SPDX-FileCopyrightText: 2016 Carlos Nihelton <carlosnsoliveira@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "clangtidyparser.h"
0008 
0009 // KDevPlatform
0010 #include <language/editor/documentrange.h>
0011 #include <serialization/indexedstring.h>
0012 #include <shell/problem.h>
0013 
0014 namespace ClangTidy
0015 {
0016 using KDevelop::IProblem;
0017 using KDevelop::DetectedProblem;
0018 using KDevelop::DocumentRange;
0019 using KDevelop::IndexedString;
0020 /**
0021  * Convert the value of <verbose> attribute of <error> element from clang-tidy's
0022  * XML-output to 'good-looking' HTML-version. This is necessary because the
0023  * displaying of the original message is performed without line breaks - such
0024  * tooltips are uncomfortable to read, and large messages will not fit into the
0025  * screen.
0026  *
0027  * This function put the original message into \<html\> tag that automatically
0028  * provides line wrapping by builtin capabilities of Qt library. The source text
0029  * also can contain tokens '\012' (line break) - they are present in the case of
0030  * source code examples. In such cases, the entire text between the first and
0031  * last tokens (i.e. source code) is placed into \<pre\> tag.
0032  *
0033  * @param[in] input the original value of <verbose> attribute
0034  * @return HTML version for displaying in problem's tooltip
0035  */
0036 QString verboseMessageToHtml(const QString& input)
0037 {
0038     QString output(QStringLiteral("<html>%1</html>").arg(input.toHtmlEscaped()));
0039 
0040     output.replace(QLatin1String("\\012"), QLatin1String("\n"));
0041 
0042     if (output.count(QLatin1Char('\n')) >= 2) {
0043         output.replace(output.indexOf(QLatin1Char('\n')), 1, QStringLiteral("<pre>"));
0044         output.replace(output.lastIndexOf(QLatin1Char('\n')), 1, QStringLiteral("</pre><br>"));
0045     }
0046 
0047     return output;
0048 }
0049 
0050 ClangTidyParser::ClangTidyParser(QObject* parent)
0051     : QObject(parent)
0052       //                            (1 filename                              ) (2ln) (3cl)  (4se)  (5d) (6expln)
0053     , m_hitRegExp(QStringLiteral(R"(((?:[A-Za-z]:\\|\/).+\.[ch]{1,2}[px]{0,2}):(\d+):(\d+): (.+?): (.+) (\[.+\]))"))
0054 {
0055 }
0056 
0057 void ClangTidyParser::addData(const QStringList& stdoutList)
0058 {
0059     QVector<KDevelop::IProblem::Ptr> problems;
0060 
0061     for (const auto& line : qAsConst(stdoutList)) {
0062         auto smatch = m_hitRegExp.match(line);
0063 
0064         if (!smatch.hasMatch()) {
0065             continue;
0066         }
0067 
0068         IProblem::Ptr problem(new DetectedProblem());
0069         problem->setSource(IProblem::Plugin);
0070         problem->setDescription(smatch.captured(5));
0071         problem->setExplanation(smatch.captured(6));
0072 
0073         DocumentRange range;
0074         range.document = IndexedString(smatch.captured(1));
0075         range.setBothColumns(smatch.capturedRef(3).toInt() - 1);
0076         range.setBothLines(smatch.capturedRef(2).toInt() - 1);
0077         problem->setFinalLocation(range);
0078 
0079         const auto sev = smatch.capturedRef(4);
0080         const IProblem::Severity erity =
0081             (sev == QLatin1String("error")) ?   IProblem::Error :
0082             (sev == QLatin1String("warning")) ? IProblem::Warning :
0083             (sev == QLatin1String("note")) ?    IProblem::Hint :
0084             /* else */                          IProblem::NoSeverity;
0085         problem->setSeverity(erity);
0086 
0087         problems.append(problem);
0088     }
0089 
0090     if (!problems.isEmpty()) {
0091         emit problemsDetected(problems);
0092     }
0093 }
0094 
0095 } // namespace ClangTidy
0096 
0097 #include "moc_clangtidyparser.cpp"