File indexing completed on 2024-05-05 04:39:49
0001 /* 0002 SPDX-FileCopyrightText: 2008 Hamish Rodda <rodda@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "overridespage.h" 0008 #include "ui_overridevirtuals.h" 0009 #include "debug.h" 0010 0011 #include <language/duchain/duchain.h> 0012 #include <language/duchain/persistentsymboltable.h> 0013 #include <language/duchain/duchainlock.h> 0014 #include <language/duchain/types/alltypes.h> 0015 #include <language/duchain/classmemberdeclaration.h> 0016 #include <language/duchain/abstractfunctiondeclaration.h> 0017 #include <language/duchain/duchainutils.h> 0018 #include <language/duchain/classfunctiondeclaration.h> 0019 0020 #include <QTreeWidget> 0021 #include <QTreeWidgetItem> 0022 #include <QHeaderView> 0023 0024 using namespace KDevelop; 0025 0026 enum Column { 0027 ClassOrFunctionColumn, ///< Column represents either a base class item or a function item 0028 AccessColumn, ///< Column represents the access policy of a function 0029 PropertiesColumn ///< Column represents the properties of a function (e.g. if it's a ctor, dtor, signal, slot, ...) 0030 }; 0031 0032 static QString accessPolicyToString(Declaration::AccessPolicy accessPolicy) 0033 { 0034 switch (accessPolicy) { 0035 case Declaration::DefaultAccess: 0036 case Declaration::Public: 0037 return i18nc("@item access policy", "Public"); 0038 case Declaration::Protected: 0039 return i18nc("@item access policy", "Protected"); 0040 case Declaration::Private: 0041 return i18nc("@item access policy", "Private"); 0042 } 0043 Q_UNREACHABLE(); 0044 } 0045 0046 static QString functionPropertiesToString(ClassFunctionDeclaration* decl) 0047 { 0048 Q_ASSERT(decl); 0049 QStringList properties; 0050 if (decl->isConstructor()) { 0051 properties << i18nc("@item function property", "Constructor"); 0052 } else if (decl->isDestructor()) { 0053 properties << i18nc("@item function property", "Destructor"); 0054 } else if (decl->isSignal()) { 0055 properties << i18nc("@item function property", "Signal"); 0056 } else if (decl->isSlot()) { 0057 properties << i18nc("@item function property", "Slot"); 0058 } else if (decl->isAbstract()) { 0059 properties << i18nc("@item function property", "Abstract function"); 0060 } 0061 return properties.join(QLatin1String(", ")); 0062 } 0063 0064 struct KDevelop::OverridesPagePrivate 0065 { 0066 OverridesPagePrivate() 0067 : overrides(nullptr) 0068 { 0069 } 0070 Ui::OverridesDialog* overrides; 0071 QMultiHash<Identifier, DeclarationPointer> overriddenFunctions; 0072 QMap<QTreeWidgetItem *, DeclarationPointer> declarationMap; 0073 QList<DeclarationPointer> chosenOverrides; 0074 }; 0075 0076 OverridesPage::OverridesPage(QWidget* parent) 0077 : QWidget(parent) 0078 , d(new OverridesPagePrivate) 0079 { 0080 d->overrides = new Ui::OverridesDialog; 0081 d->overrides->setupUi(this); 0082 0083 connect(d->overrides->selectAllPushButton, &QPushButton::pressed, this, &OverridesPage::selectAll); 0084 connect(d->overrides->deselectAllPushButton, &QPushButton::pressed, this, &OverridesPage::deselectAll); 0085 } 0086 0087 OverridesPage::~OverridesPage() 0088 { 0089 delete d->overrides; 0090 delete d; 0091 } 0092 0093 QList< DeclarationPointer > OverridesPage::selectedOverrides() const 0094 { 0095 QList<DeclarationPointer> declarations; 0096 0097 for (int i = 0; i < d->overrides->overridesTree->topLevelItemCount(); ++i) 0098 { 0099 QTreeWidgetItem* item = d->overrides->overridesTree->topLevelItem(i); 0100 for (int j = 0; j < item->childCount(); ++j) 0101 { 0102 QTreeWidgetItem* child = item->child(j); 0103 if (child->checkState(ClassOrFunctionColumn) == Qt::Checked) 0104 { 0105 qCDebug(PLUGIN_FILETEMPLATES) << "Adding declaration" << d->declarationMap[child]->toString(); 0106 declarations << d->declarationMap[child]; 0107 } 0108 } 0109 } 0110 0111 qCDebug(PLUGIN_FILETEMPLATES) << declarations.size(); 0112 return declarations; 0113 } 0114 0115 void OverridesPage::clear() 0116 { 0117 d->overriddenFunctions.clear(); 0118 overrideTree()->clear(); 0119 d->chosenOverrides.clear(); 0120 d->declarationMap.clear(); 0121 } 0122 0123 void OverridesPage::addBaseClasses(const QList<DeclarationPointer>& directBases, 0124 const QList<DeclarationPointer>& allBases) 0125 { 0126 DUChainReadLocker lock; 0127 0128 for (const DeclarationPointer& baseClass : allBases) { 0129 auto* classItem = new QTreeWidgetItem(overrideTree(), QStringList() << baseClass->qualifiedIdentifier().toString()); 0130 classItem->setIcon(ClassOrFunctionColumn, DUChainUtils::iconForDeclaration(baseClass.data())); 0131 0132 DUContext* context = baseClass->internalContext(); 0133 if (!context) { 0134 continue; 0135 } 0136 0137 //For this internal context get all the function declarations inside the class 0138 const auto localDeclarations = context->localDeclarations(); 0139 for (Declaration* childDeclaration : localDeclarations) { 0140 if (auto * func = dynamic_cast<AbstractFunctionDeclaration*>(childDeclaration)) 0141 { 0142 if (func->isVirtual()) 0143 { 0144 // Its a virtual function, add it to the list unless it's a destructor 0145 auto* cFunc = dynamic_cast<ClassFunctionDeclaration*>(childDeclaration); 0146 if (cFunc && !cFunc->isDestructor()) 0147 { 0148 addPotentialOverride(classItem, DeclarationPointer(childDeclaration)); 0149 } 0150 } 0151 else if (directBases.contains(baseClass)) 0152 { 0153 // add ctors of direct parents 0154 auto* cFunc = dynamic_cast<ClassFunctionDeclaration*>(childDeclaration); 0155 if (cFunc && cFunc->isConstructor()) 0156 { 0157 addPotentialOverride(classItem, DeclarationPointer(childDeclaration)); 0158 } 0159 } 0160 } 0161 } 0162 } 0163 0164 overrideTree()->expandAll(); 0165 overrideTree()->header()->resizeSections(QHeaderView::ResizeToContents); 0166 } 0167 0168 void OverridesPage::addPotentialOverride(QTreeWidgetItem* classItem, const DeclarationPointer& childDeclaration) 0169 { 0170 auto* function = dynamic_cast<ClassFunctionDeclaration*>(childDeclaration.data()); 0171 if (!function) { 0172 qCDebug(PLUGIN_FILETEMPLATES) << "Declaration is not a function:" << childDeclaration->identifier().toString(); 0173 return; 0174 } 0175 0176 if (function->accessPolicy() == Declaration::Private) { 0177 qCDebug(PLUGIN_FILETEMPLATES) << "Declaration is private, returning:" << function->identifier().toString(); 0178 return; 0179 } 0180 0181 qCDebug(PLUGIN_FILETEMPLATES) << childDeclaration->toString(); 0182 auto overridenFunctionIt = d->overriddenFunctions.constFind(childDeclaration->identifier()); 0183 if (overridenFunctionIt != d->overriddenFunctions.constEnd()) { 0184 for (; overridenFunctionIt != d->overriddenFunctions.constEnd(); ++overridenFunctionIt) { 0185 const DeclarationPointer& decl = *overridenFunctionIt; 0186 if (decl->indexedType() == childDeclaration->indexedType()) 0187 { 0188 qCDebug(PLUGIN_FILETEMPLATES) << "Declaration is already shown"; 0189 return; 0190 } 0191 } 0192 } 0193 0194 d->overriddenFunctions.insert(childDeclaration->identifier(), childDeclaration); 0195 0196 auto* overrideItem = new QTreeWidgetItem(classItem, QStringList() << childDeclaration->toString()); 0197 overrideItem->setFlags( Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable) ); 0198 overrideItem->setCheckState(ClassOrFunctionColumn, d->chosenOverrides.contains(childDeclaration) ? Qt::Checked : Qt::Unchecked); 0199 overrideItem->setIcon(ClassOrFunctionColumn, DUChainUtils::iconForDeclaration(childDeclaration.data())); 0200 overrideItem->setData(ClassOrFunctionColumn, Qt::UserRole, QVariant::fromValue(IndexedDeclaration(childDeclaration.data()))); 0201 overrideItem->setText(AccessColumn, accessPolicyToString(function->accessPolicy())); 0202 overrideItem->setText(PropertiesColumn, functionPropertiesToString(function)); 0203 0204 if (function->isAbstract()) { 0205 overrideItem->setIcon(ClassOrFunctionColumn, QIcon::fromTheme(QStringLiteral("flag-red"))); 0206 overrideItem->setCheckState(ClassOrFunctionColumn, Qt::Checked); 0207 classItem->removeChild(overrideItem); 0208 classItem->insertChild(0, overrideItem); 0209 } 0210 0211 d->declarationMap[overrideItem] = childDeclaration; 0212 } 0213 0214 QTreeWidget* OverridesPage::overrideTree() const 0215 { 0216 return d->overrides->overridesTree; 0217 } 0218 0219 QWidget* OverridesPage::extraFunctionsContainer() const 0220 { 0221 return d->overrides->extraFunctionWidget; 0222 } 0223 0224 void OverridesPage::selectAll() 0225 { 0226 for (int i = 0; i < d->overrides->overridesTree->topLevelItemCount(); ++i) { 0227 QTreeWidgetItem* item = d->overrides->overridesTree->topLevelItem(i); 0228 for (int j = 0; j < item->childCount(); ++j) 0229 item->child(j)->setCheckState(ClassOrFunctionColumn, Qt::Checked); 0230 } 0231 } 0232 0233 void OverridesPage::deselectAll() 0234 { 0235 for (int i = 0; i < d->overrides->overridesTree->topLevelItemCount(); ++i) { 0236 QTreeWidgetItem* item = d->overrides->overridesTree->topLevelItem(i); 0237 for (int j = 0; j < item->childCount(); ++j) 0238 item->child(j)->setCheckState(ClassOrFunctionColumn, Qt::Unchecked); 0239 } 0240 } 0241 0242 void OverridesPage::addCustomDeclarations (const QString& category, const QList<DeclarationPointer>& declarations) 0243 { 0244 qCDebug(PLUGIN_FILETEMPLATES) << category << declarations.size(); 0245 DUChainReadLocker lock(DUChain::lock()); 0246 0247 auto* item = new QTreeWidgetItem(overrideTree(), QStringList() << category); 0248 for (const DeclarationPointer& declaration : declarations) 0249 { 0250 addPotentialOverride(item, declaration); 0251 } 0252 0253 overrideTree()->expandAll(); 0254 overrideTree()->header()->resizeSections(QHeaderView::ResizeToContents); 0255 } 0256 0257 void OverridesPage::setFocusToFirstEditWidget() 0258 { 0259 d->overrides->overridesTree->setFocus(); 0260 } 0261 0262 #include "moc_overridespage.cpp"