diff --git a/src/parsers/clangtidyparser.cpp b/src/parsers/clangtidyparser.cpp index e01f22e1f5..ee466d9890 100644 --- a/src/parsers/clangtidyparser.cpp +++ b/src/parsers/clangtidyparser.cpp @@ -1,111 +1,113 @@ /* * This file is part of KDevelop * * Copyright 2016 Carlos Nihelton * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include +#include +#include #include #include "clangtidyparser.h" namespace ClangTidy { using KDevelop::IProblem; using KDevelop::DetectedProblem; using KDevelop::DocumentRange; using KDevelop::IndexedString; /** * Convert the value of attribute of element from clangtidy's * XML-output to 'good-looking' HTML-version. This is necessary because the * displaying of the original message is performed without line breaks - such * tooltips are uncomfortable to read, and large messages will not fit into the * screen. * * This function put the original message into tag that automatically * provides line wrapping by builtin capabilities of Qt library. The source text * also can contain tokens '\012' (line break) - they are present in the case of * source code examples. In such cases, the entire text between the first and * last tokens (i.e. source code) is placed into
 tag.
  *
  * @param[in] input the original value of  attribute
  * @return HTML version for displaying in problem's tooltip
  */
 QString verboseMessageToHtml(const QString& input)
 {
     QString output(QString("%1").arg(input.toHtmlEscaped()));
 
     output.replace("\\012", "\n");
 
     if (output.count('\n') >= 2) {
         output.replace(output.indexOf('\n'), 1, "
");
         output.replace(output.lastIndexOf('\n'), 1, "

"); } return output; } ClangTidyParser::ClangTidyParser(QObject* parent) : QObject(parent) { } void ClangTidyParser::parse() { QRegularExpression regex(QStringLiteral("(\\/.+\\.cpp):(\\d+):(\\d+): (.+): (.+) (\\[.+\\])")); for (auto line : m_stdout) { auto smatch = regex.match(line); if (smatch.hasMatch()) { IProblem::Ptr problem(new DetectedProblem()); problem->setSource(IProblem::Plugin); problem->setDescription(smatch.captured(5)); problem->setExplanation(smatch.captured(6) + '\n'); DocumentRange range; range.document = IndexedString(smatch.captured(1)); range.setBothColumns(smatch.captured(3).toInt() - 1); range.setBothLines(smatch.captured(2).toInt() - 1); problem->setFinalLocation(range); auto sev(smatch.captured(4)); IProblem::Severity erity; if (sev == QStringLiteral("error")) { erity = IProblem::Error; } else if (sev == QStringLiteral("warning")) { erity = IProblem::Warning; } else if (sev == QStringLiteral("note")) { erity = IProblem::Hint; } else { erity = IProblem::NoSeverity; } problem->setSeverity(erity); m_problems.push_back(problem); } else if (!m_problems.isEmpty()) { auto problem = m_problems.last(); line.prepend(problem->explanation() + '\n'); problem->setExplanation(line); } else continue; } } } // namespace ClangTidy diff --git a/tests/test_clangtidyjob.cpp b/tests/test_clangtidyjob.cpp index 0d03335a86..de1265337c 100644 --- a/tests/test_clangtidyjob.cpp +++ b/tests/test_clangtidyjob.cpp @@ -1,92 +1,93 @@ /* * This file is part of KDevelop * * Copyright 2016 Carlos Nihelton * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include +#include #include #include #include "job.h" #include "test_clangtidyjob.h" using namespace KDevelop; using namespace ClangTidy; class JobTester : public Job { public: JobTester(Job::Parameters params) : Job(params) { } using Job::processStdoutLines; using Job::processStderrLines; using Job::childProcessExited; QString standardOutput() const { return m_standardOutput.join('\n'); } }; void TestClangTidyJob::initTestCase() { AutoTestShell::init({ "kdevclangtidy" }); TestCore::initialize(Core::NoUi); } void TestClangTidyJob::cleanupTestCase() { TestCore::shutdown(); } void TestClangTidyJob::testJob() { QFile output_example_file("data/output_example"); output_example_file.open(QIODevice::ReadOnly); QTextStream ios(&output_example_file); QStringList stdoutOutput; QString line; while (ios.readLineInto(&line)) { stdoutOutput << line; } QVERIFY(!stdoutOutput.isEmpty()); Job::Parameters jobParams; JobTester jobTester(jobParams); jobTester.processStdoutLines(stdoutOutput); QCOMPARE(jobTester.standardOutput(), stdoutOutput.join('\n')); jobTester.childProcessExited(0, QProcess::NormalExit); auto problems = jobTester.problems(); QVERIFY(problems[0]->finalLocation().document.str().contains(QStringLiteral("/kdev-clang-tidy/src/plugin.cpp"))); QVERIFY( problems[0]->explanation().startsWith(QStringLiteral("[cppcoreguidelines-pro-bounds-array-to-pointer-decay]"))); QVERIFY(problems[1]->finalLocation().document.str().contains(QStringLiteral("/kdev-clang-tidy/src/plugin.cpp"))); QVERIFY( problems[1]->explanation().startsWith(QStringLiteral("[cppcoreguidelines-pro-bounds-array-to-pointer-decay]"))); QVERIFY(problems[2]->finalLocation().document.str().contains(QStringLiteral("/kdev-clang-tidy/src/plugin.cpp"))); QVERIFY( problems[2]->explanation().startsWith(QStringLiteral("[cppcoreguidelines-pro-bounds-array-to-pointer-decay]"))); } QTEST_GUILESS_MAIN(TestClangTidyJob); diff --git a/tests/test_clangtidyparser.cpp b/tests/test_clangtidyparser.cpp index 1aa35a656e..9f54863e20 100644 --- a/tests/test_clangtidyparser.cpp +++ b/tests/test_clangtidyparser.cpp @@ -1,100 +1,101 @@ /* * This file is part of KDevelop * * Copyright 2016 Carlos Nihelton * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "test_clangtidyparser.h" #include #include #include +#include #include #include #include #include "parsers/clangtidyparser.h" using namespace KDevelop; using namespace ClangTidy; void TestClangTidyParser::initTestCase() { AutoTestShell::init(); TestCore::initialize(Core::NoUi); } void TestClangTidyParser::cleanupTestCase() { TestCore::shutdown(); } void TestClangTidyParser::testParser() { // prepare QStringList from file to be parsed. QFile output_example_file("data/output_example"); output_example_file.open(QIODevice::ReadOnly); QTextStream ios(&output_example_file); QStringList clangtidy_example_output; QString line; while (ios.readLineInto(&line)) { clangtidy_example_output << line; } QVERIFY(!clangtidy_example_output.isEmpty()); ClangTidy::ClangTidyParser parser; parser.addData(clangtidy_example_output); parser.parse(); const auto problems = parser.problems(); QVERIFY(!problems.empty()); IProblem::Ptr p = problems[0]; QCOMPARE(p->description(), QStringLiteral("do not implicitly decay an array into a pointer; consider using " "gsl::array_view or an explicit cast instead")); QVERIFY(p->explanation().startsWith(QStringLiteral("[cppcoreguidelines-pro-bounds-array-to-pointer-decay]"))); QVERIFY(p->finalLocation().document.str().contains(QStringLiteral("/kdev-clang-tidy/src/plugin.cpp"))); QCOMPARE(p->finalLocation().start().line() + 1, 80); QCOMPARE(p->finalLocation().start().column() + 1, 5); QCOMPARE(p->severity(), IProblem::Warning); QCOMPARE(p->source(), IProblem::Plugin); // test problem with 2 elements p = problems[1]; QCOMPARE(p->description(), QStringLiteral("do not implicitly decay an array into a pointer; consider using " "gsl::array_view or an explicit cast instead")); QVERIFY(p->explanation().startsWith(QStringLiteral("[cppcoreguidelines-pro-bounds-array-to-pointer-decay]"))); QVERIFY(p->finalLocation().document.str().contains(QStringLiteral("/kdev-clang-tidy/src/plugin.cpp"))); QCOMPARE(p->finalLocation().start().line() + 1, 145); QCOMPARE(p->finalLocation().start().column() + 1, 9); QCOMPARE(p->severity(), IProblem::Warning); QCOMPARE(p->source(), IProblem::Plugin); // test problem with '\\012' tokens in verbose message p = problems[2]; QCOMPARE(p->description(), QStringLiteral("do not implicitly decay an array into a pointer; consider using " "gsl::array_view or an explicit cast instead")); QVERIFY(p->explanation().startsWith(QStringLiteral("[cppcoreguidelines-pro-bounds-array-to-pointer-decay]"))); QVERIFY(p->finalLocation().document.str().contains(QStringLiteral("/kdev-clang-tidy/src/plugin.cpp"))); QCOMPARE(p->finalLocation().start().line() + 1, 151); QCOMPARE(p->finalLocation().start().column() + 1, 9); QCOMPARE(p->severity(), IProblem::Warning); QCOMPARE(p->source(), IProblem::Plugin); } QTEST_GUILESS_MAIN(TestClangTidyParser);