diff --git a/src/config/checkgroup.cpp b/src/config/checkgroup.cpp index 19ff2832f0..aec3977808 100644 --- a/src/config/checkgroup.cpp +++ b/src/config/checkgroup.cpp @@ -1,302 +1,303 @@ /* * This file is part of KDevelop * * Copyright 2018 Friedrich W. H. Kossebau * * 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 "checkgroup.h" // plugin #include +#include // Qt #include namespace ClangTidy { CheckGroup* CheckGroup::fromPlainList(const QStringList& checks) { auto* result = new CheckGroup; // root group cannot inherit result->m_groupEnabledState = Disabled; for (const auto& checkName : checks) { result->addCheck(checkName); } return result; } CheckGroup::CheckGroup(const QString& name, CheckGroup* superGroup) : m_superGroup(superGroup) , m_prefix(name) { } CheckGroup::~CheckGroup() { qDeleteAll(m_subGroups); } void CheckGroup::addCheck(const QString& checkName) { const int nextSplitOffset = checkName.indexOf(QRegularExpression(QStringLiteral("[-.]")), m_prefix.length()); // 1. check if looking at last section, if so add to current group if (nextSplitOffset < 0) { m_checks.append(checkName); m_checksEnabledStates.append(EnabledInherited); return; } // 2. check if existing subgroup for prefix, if so add to that // include separator into subgroup name const QStringRef subGroupName = checkName.leftRef(nextSplitOffset + 1); - for (auto* subGroup : m_subGroups) { + for (auto* subGroup : qAsConst(m_subGroups)) { if (subGroup->prefix() == subGroupName) { subGroup->addCheck(checkName); return; } } // 3. check if existing check with same prefix, if so create subgroup for them for (int i = 0; i < m_checks.size(); ++i) { const auto& listedCheckName = m_checks[i]; if (listedCheckName.startsWith(subGroupName)) { auto* newSubGroup = new CheckGroup(subGroupName.toString(), this); newSubGroup->addCheck(listedCheckName); newSubGroup->addCheck(checkName); m_subGroups.append(newSubGroup); m_checks.removeAt(i); m_checksEnabledStates.removeAt(i); return; } } // 4. add to current group m_checks.append(checkName); m_checksEnabledStates.append(EnabledInherited); } void CheckGroup::setEnabledChecks(const QStringList& rules) { // TODO: optimize & check first rule if not matching all resetEnabledState(Disabled); for (const auto& rule : rules) { int matchStartPos = 0; EnabledState enabledState = Enabled; if (rule.startsWith(QLatin1Char('-'))) { matchStartPos = 1; enabledState = Disabled; } applyEnabledRule(rule.midRef(matchStartPos), enabledState); } m_enabledChecksCountDirty = true; setEnabledChecksCountDirtyInSubGroups(); } void CheckGroup::applyEnabledRule(const QStringRef& rule, EnabledState enabledState) { // this group? if (rule == wildCardText()) { resetEnabledState(enabledState); return; } - for (auto* subGroup : m_subGroups) { + for (auto* subGroup : qAsConst(m_subGroups)) { if (rule.startsWith(subGroup->prefix())) { subGroup->applyEnabledRule(rule, enabledState); return; } } for (int i = 0; i < m_checks.size(); ++i) { if (m_checks[i] == rule) { m_checksEnabledStates[i] = enabledState; return; } } } void CheckGroup::resetEnabledState(EnabledState enabledState) { m_groupEnabledState = enabledState; - for (auto* subGroup : m_subGroups) { + for (auto* subGroup : qAsConst(m_subGroups)) { subGroup->resetEnabledState(EnabledInherited); } m_checksEnabledStates.fill(EnabledInherited); } QStringList CheckGroup::enabledChecksRules() const { QStringList result; collectEnabledChecks(result); return result; } void CheckGroup::collectEnabledChecks(QStringList& enabledChecks) const { const auto effectiveGroupEnabledState = this->effectiveGroupEnabledState(); const bool appendGroupRule = (!m_superGroup) || (m_superGroup->effectiveGroupEnabledState() != effectiveGroupEnabledState); if (appendGroupRule) { QString rule = wildCardText(); if (effectiveGroupEnabledState == CheckGroup::Disabled) { rule.prepend(QLatin1Char('-')); } enabledChecks.append(rule); } for (const auto* subGroup : m_subGroups) { subGroup->collectEnabledChecks(enabledChecks); } for (int i = 0; i < m_checks.size(); ++i) { const auto effectiveCheckEnabledState = this->effectiveCheckEnabledState(i); if (effectiveGroupEnabledState != effectiveCheckEnabledState) { QString rule = m_checks.at(i); if (effectiveCheckEnabledState == CheckGroup::Disabled) { rule.prepend(QLatin1Char('-')); } enabledChecks.append(rule); } } } const QString& CheckGroup::prefix() const { return m_prefix; } QString CheckGroup::wildCardText() const { return m_prefix + QLatin1Char('*'); } const QStringList& CheckGroup::checkNames() const { return m_checks; } const QVector& CheckGroup::subGroups() const { return m_subGroups; } CheckGroup * CheckGroup::superGroup() const { return m_superGroup; } CheckGroup::EnabledState CheckGroup::groupEnabledState() const { return m_groupEnabledState; } CheckGroup::EnabledState CheckGroup::effectiveGroupEnabledState() const { EnabledState result = m_groupEnabledState; if (result == EnabledInherited) { Q_ASSERT(m_superGroup); result = m_superGroup->effectiveGroupEnabledState(); } return result; } CheckGroup::EnabledState CheckGroup::checkEnabledState(int index) const { return m_checksEnabledStates.at(index); } CheckGroup::EnabledState CheckGroup::effectiveCheckEnabledState(int index) const { EnabledState result = m_checksEnabledStates.at(index); if (result == EnabledInherited) { result = effectiveGroupEnabledState(); } return result; } void CheckGroup::setGroupEnabledState(CheckGroup::EnabledState groupEnabledState) { const int oldEffectiveGroupEnabledState = effectiveGroupEnabledState(); m_groupEnabledState = groupEnabledState; if (oldEffectiveGroupEnabledState != effectiveGroupEnabledState()) { setEnabledChecksCountDirtyInSuperGroups(); setEnabledChecksCountDirtyInSubGroups(); } } void CheckGroup::setCheckEnabledState(int index, CheckGroup::EnabledState checkEnabledState) { const int oldEffectiveCheckEnabledState = effectiveCheckEnabledState(index); m_checksEnabledStates[index] = checkEnabledState; if (oldEffectiveCheckEnabledState != effectiveCheckEnabledState(index)) { setEnabledChecksCountDirtyInSuperGroups(); } } int CheckGroup::enabledChecksCount() const { if (m_enabledChecksCountDirty) { m_enabledChecksCount = 0; for (auto* subGroup : m_subGroups) { m_enabledChecksCount += subGroup->enabledChecksCount(); } for (int i = 0; i < m_checks.size(); ++i) { if (effectiveCheckEnabledState(i) == Enabled) { ++m_enabledChecksCount; } } m_enabledChecksCountDirty = false; } return m_enabledChecksCount; } void CheckGroup::setEnabledChecksCountDirtyInSuperGroups() { auto* checkGroup = this; while (checkGroup) { checkGroup->m_enabledChecksCountDirty = true; checkGroup = checkGroup->superGroup(); } } void CheckGroup::setEnabledChecksCountDirtyInSubGroups() { - for (auto* subGroup : m_subGroups) { + for (auto* subGroup : qAsConst(m_subGroups)) { subGroup->m_enabledChecksCountDirty = true; subGroup->setEnabledChecksCountDirtyInSubGroups(); } } } diff --git a/src/parsers/clangtidyparser.cpp b/src/parsers/clangtidyparser.cpp index ee39f0f56c..81ab37c01a 100644 --- a/src/parsers/clangtidyparser.cpp +++ b/src/parsers/clangtidyparser.cpp @@ -1,114 +1,116 @@ /* * 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 "clangtidyparser.h" +// plugin +#include // KDevPlatform #include #include #include // Qt #include namespace ClangTidy { using KDevelop::IProblem; using KDevelop::DetectedProblem; using KDevelop::DocumentRange; using KDevelop::IndexedString; /** * Convert the value of attribute of element from clang-tidy'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(QStringLiteral("%1").arg(input.toHtmlEscaped())); output.replace(QStringLiteral("\\012"), QStringLiteral("\n")); if (output.count(QLatin1Char('\n')) >= 2) { output.replace(output.indexOf(QLatin1Char('\n')), 1, QStringLiteral("
"));
         output.replace(output.lastIndexOf(QLatin1Char('\n')), 1, QStringLiteral("

")); } return output; } ClangTidyParser::ClangTidyParser(QObject* parent) : QObject(parent) { } void ClangTidyParser::parse() { // (1filename ) (2lin) (3col) (4s) (5d) (6explain) QRegularExpression regex(QStringLiteral("(\\/.+\\.[ch]{1,2}[px]{0,2}):(\\d+):(\\d+): (.+): (.+) (\\[.+\\])")); - for (const auto& line : m_stdout) { + for (const auto& line : qAsConst(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.capturedRef(6) + QLatin1Char('\n')); DocumentRange range; range.document = IndexedString(smatch.captured(1)); range.setBothColumns(smatch.capturedRef(3).toInt() - 1); range.setBothLines(smatch.capturedRef(2).toInt() - 1); problem->setFinalLocation(range); const auto sev = smatch.capturedRef(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(); const QString extendedExplanation = problem->explanation() + QLatin1Char('\n') + line; problem->setExplanation(extendedExplanation); } else { continue; } } } } // namespace ClangTidy diff --git a/src/qtcompat_p.h b/src/qtcompat_p.h new file mode 100644 index 0000000000..881b1146a3 --- /dev/null +++ b/src/qtcompat_p.h @@ -0,0 +1,43 @@ +/* + * This file is part of KDevelop + * + * Copyright 2018 Friedrich W. H. Kossebau + * + * 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. + */ + +#ifndef CLANGTIDY_QTCOMPAT_P_H +#define CLANGTIDY_QTCOMPAT_P_H + +#include + +#if QT_VERSION < QT_VERSION_CHECK(5,7,0) +namespace QtPrivate +{ +template struct QAddConst { + typedef const T Type; +}; +} + +// this adds const to non-const objects (like std::as_const) +template +Q_DECL_CONSTEXPR typename QtPrivate::QAddConst::Type &qAsConst(T &t) Q_DECL_NOTHROW { return t; } +// prevent rvalue arguments: +template +void qAsConst(const T &&) Q_DECL_EQ_DELETE; +#endif + +#endif