File indexing completed on 2024-05-12 04:39:20
0001 /* 0002 SPDX-FileCopyrightText: 2018 Friedrich W. H. Kossebau <kossebau@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "checkgroup.h" 0008 0009 // plugin 0010 #include <debug.h> 0011 // Qt 0012 #include <QRegularExpression> 0013 0014 namespace ClangTidy 0015 { 0016 0017 CheckGroup* CheckGroup::fromPlainList(const QStringList& checks) 0018 { 0019 auto* result = new CheckGroup; 0020 // root group cannot inherit 0021 result->m_groupEnabledState = Disabled; 0022 0023 for (const auto& checkName : checks) { 0024 result->addCheck(checkName); 0025 } 0026 0027 return result; 0028 } 0029 0030 CheckGroup::CheckGroup(const QString& name, CheckGroup* superGroup) 0031 : m_superGroup(superGroup) 0032 , m_prefix(name) 0033 { 0034 } 0035 0036 CheckGroup::~CheckGroup() 0037 { 0038 qDeleteAll(m_subGroups); 0039 } 0040 0041 0042 void CheckGroup::addCheck(const QString& checkName) 0043 { 0044 const int nextSplitOffset = checkName.indexOf(QRegularExpression(QStringLiteral("[-.]")), m_prefix.length()); 0045 0046 // 1. check if looking at last section, if so add to current group 0047 if (nextSplitOffset < 0) { 0048 m_checks.append(checkName); 0049 m_checksEnabledStates.append(EnabledInherited); 0050 return; 0051 } 0052 0053 // 2. check if existing subgroup for prefix, if so add to that 0054 // include separator into subgroup name 0055 const QStringRef subGroupName = checkName.leftRef(nextSplitOffset + 1); 0056 for (auto* subGroup : qAsConst(m_subGroups)) { 0057 if (subGroup->prefix() == subGroupName) { 0058 subGroup->addCheck(checkName); 0059 return; 0060 } 0061 } 0062 0063 // 3. check if existing check with same prefix, if so create subgroup for them 0064 for (int i = 0; i < m_checks.size(); ++i) { 0065 const auto& listedCheckName = m_checks[i]; 0066 if (listedCheckName.startsWith(subGroupName)) { 0067 auto* newSubGroup = new CheckGroup(subGroupName.toString(), this); 0068 newSubGroup->addCheck(listedCheckName); 0069 newSubGroup->addCheck(checkName); 0070 m_subGroups.append(newSubGroup); 0071 m_checks.removeAt(i); 0072 m_checksEnabledStates.removeAt(i); 0073 return; 0074 } 0075 } 0076 0077 // 4. add to current group 0078 m_checks.append(checkName); 0079 m_checksEnabledStates.append(EnabledInherited); 0080 } 0081 0082 void CheckGroup::setEnabledChecks(const QStringList& rules) 0083 { 0084 // TODO: optimize & check first rule if not matching all 0085 resetEnabledState(Disabled); 0086 0087 for (const auto& rule : rules) { 0088 int matchStartPos = 0; 0089 EnabledState enabledState = Enabled; 0090 if (rule.startsWith(QLatin1Char('-'))) { 0091 matchStartPos = 1; 0092 enabledState = Disabled; 0093 } 0094 applyEnabledRule(rule.midRef(matchStartPos), enabledState); 0095 } 0096 0097 m_enabledChecksCountDirty = true; 0098 setEnabledChecksCountDirtyInSubGroups(); 0099 } 0100 0101 void CheckGroup::applyEnabledRule(const QStringRef& rule, EnabledState enabledState) 0102 { 0103 // this group? 0104 if (rule == wildCardText()) { 0105 resetEnabledState(enabledState); 0106 return; 0107 } 0108 0109 for (auto* subGroup : qAsConst(m_subGroups)) { 0110 if (rule.startsWith(subGroup->prefix())) { 0111 subGroup->applyEnabledRule(rule, enabledState); 0112 return; 0113 } 0114 } 0115 0116 for (int i = 0; i < m_checks.size(); ++i) { 0117 if (m_checks[i] == rule) { 0118 m_checksEnabledStates[i] = enabledState; 0119 return; 0120 } 0121 } 0122 } 0123 0124 void CheckGroup::resetEnabledState(EnabledState enabledState) 0125 { 0126 m_groupEnabledState = enabledState; 0127 0128 for (auto* subGroup : qAsConst(m_subGroups)) { 0129 subGroup->resetEnabledState(EnabledInherited); 0130 } 0131 m_checksEnabledStates.fill(EnabledInherited); 0132 } 0133 0134 QStringList CheckGroup::enabledChecksRules() const 0135 { 0136 QStringList result; 0137 collectEnabledChecks(result); 0138 return result; 0139 } 0140 0141 void CheckGroup::collectEnabledChecks(QStringList& enabledChecks) const 0142 { 0143 const auto effectiveGroupEnabledState = this->effectiveGroupEnabledState(); 0144 0145 const bool appendGroupRule = 0146 (!m_superGroup) || 0147 (m_superGroup->effectiveGroupEnabledState() != effectiveGroupEnabledState); 0148 if (appendGroupRule) { 0149 QString rule = wildCardText(); 0150 if (effectiveGroupEnabledState == CheckGroup::Disabled) { 0151 rule.prepend(QLatin1Char('-')); 0152 } 0153 enabledChecks.append(rule); 0154 } 0155 0156 for (const auto* subGroup : m_subGroups) { 0157 subGroup->collectEnabledChecks(enabledChecks); 0158 } 0159 0160 for (int i = 0; i < m_checks.size(); ++i) { 0161 const auto effectiveCheckEnabledState = this->effectiveCheckEnabledState(i); 0162 if (effectiveGroupEnabledState != effectiveCheckEnabledState) { 0163 QString rule = m_checks.at(i); 0164 if (effectiveCheckEnabledState == CheckGroup::Disabled) { 0165 rule.prepend(QLatin1Char('-')); 0166 } 0167 enabledChecks.append(rule); 0168 } 0169 } 0170 } 0171 0172 const QString& CheckGroup::prefix() const 0173 { 0174 return m_prefix; 0175 } 0176 0177 QString CheckGroup::wildCardText() const 0178 { 0179 return m_prefix + QLatin1Char('*'); 0180 } 0181 0182 const QStringList& CheckGroup::checkNames() const 0183 { 0184 return m_checks; 0185 } 0186 0187 const QVector<CheckGroup*>& CheckGroup::subGroups() const 0188 { 0189 return m_subGroups; 0190 } 0191 0192 CheckGroup * CheckGroup::superGroup() const 0193 { 0194 return m_superGroup; 0195 } 0196 0197 CheckGroup::EnabledState CheckGroup::groupEnabledState() const 0198 { 0199 return m_groupEnabledState; 0200 } 0201 0202 CheckGroup::EnabledState CheckGroup::effectiveGroupEnabledState() const 0203 { 0204 EnabledState result = m_groupEnabledState; 0205 if (result == EnabledInherited) { 0206 Q_ASSERT(m_superGroup); 0207 result = m_superGroup->effectiveGroupEnabledState(); 0208 } 0209 return result; 0210 } 0211 0212 CheckGroup::EnabledState CheckGroup::checkEnabledState(int index) const 0213 { 0214 return m_checksEnabledStates.at(index); 0215 } 0216 0217 CheckGroup::EnabledState CheckGroup::effectiveCheckEnabledState(int index) const 0218 { 0219 EnabledState result = m_checksEnabledStates.at(index); 0220 if (result == EnabledInherited) { 0221 result = effectiveGroupEnabledState(); 0222 } 0223 return result; 0224 } 0225 0226 void CheckGroup::setGroupEnabledState(CheckGroup::EnabledState groupEnabledState) 0227 { 0228 const int oldEffectiveGroupEnabledState = effectiveGroupEnabledState(); 0229 0230 m_groupEnabledState = groupEnabledState; 0231 0232 if (oldEffectiveGroupEnabledState != effectiveGroupEnabledState()) { 0233 setEnabledChecksCountDirtyInSuperGroups(); 0234 setEnabledChecksCountDirtyInSubGroups(); 0235 } 0236 } 0237 0238 0239 void CheckGroup::setCheckEnabledState(int index, CheckGroup::EnabledState checkEnabledState) 0240 { 0241 const int oldEffectiveCheckEnabledState = effectiveCheckEnabledState(index); 0242 0243 m_checksEnabledStates[index] = checkEnabledState; 0244 0245 if (oldEffectiveCheckEnabledState != effectiveCheckEnabledState(index)) { 0246 setEnabledChecksCountDirtyInSuperGroups(); 0247 } 0248 } 0249 0250 void CheckGroup::updateData() const 0251 { 0252 if (m_enabledChecksCountDirty) { 0253 m_enabledChecksCount = 0; 0254 m_hasSubGroupWithExplicitEnabledState = false; 0255 0256 for (auto* subGroup : m_subGroups) { 0257 m_enabledChecksCount += subGroup->enabledChecksCount(); 0258 m_hasSubGroupWithExplicitEnabledState |= subGroup->hasSubGroupWithExplicitEnabledState(); 0259 m_hasSubGroupWithExplicitEnabledState |= (subGroup->groupEnabledState() != EnabledInherited); 0260 } 0261 0262 for (int i = 0; i < m_checks.size(); ++i) { 0263 if (effectiveCheckEnabledState(i) == Enabled) { 0264 ++m_enabledChecksCount; 0265 } 0266 m_hasSubGroupWithExplicitEnabledState |= (m_checksEnabledStates[i] != EnabledInherited); 0267 } 0268 m_enabledChecksCountDirty = false; 0269 } 0270 } 0271 0272 int CheckGroup::enabledChecksCount() const 0273 { 0274 updateData(); 0275 return m_enabledChecksCount; 0276 } 0277 0278 bool CheckGroup::hasSubGroupWithExplicitEnabledState() const 0279 { 0280 updateData(); 0281 return m_hasSubGroupWithExplicitEnabledState; 0282 } 0283 0284 void CheckGroup::setEnabledChecksCountDirtyInSuperGroups() 0285 { 0286 auto* checkGroup = this; 0287 while (checkGroup) { 0288 checkGroup->m_enabledChecksCountDirty = true; 0289 checkGroup = checkGroup->superGroup(); 0290 } 0291 } 0292 0293 void CheckGroup::setEnabledChecksCountDirtyInSubGroups() 0294 { 0295 for (auto* subGroup : qAsConst(m_subGroups)) { 0296 subGroup->m_enabledChecksCountDirty = true; 0297 subGroup->setEnabledChecksCountDirtyInSubGroups(); 0298 } 0299 } 0300 0301 }