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"