File indexing completed on 2024-05-12 04:37:56

0001 /*
0002     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden@kdevelop.org>
0003     SPDX-FileCopyrightText: 2009 Lior Mualem <lior.m.kde@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "classdeclaration.h"
0009 #include "identifier.h"
0010 #include <language/duchain/declaration.h>
0011 #include <language/duchain/appendedlist.h>
0012 #include <language/duchain/duchainregister.h>
0013 #include "types/structuretype.h"
0014 #include <debug.h>
0015 
0016 namespace KDevelop {
0017 DEFINE_LIST_MEMBER_HASH(ClassDeclarationData, baseClasses, BaseClassInstance)
0018 
0019 ClassDeclaration::ClassDeclaration(const KDevelop::RangeInRevision& range, DUContext* context)
0020     : ClassMemberDeclaration(*new ClassDeclarationData, range)
0021 {
0022     d_func_dynamic()->setClassId(this);
0023     setContext(context);
0024 }
0025 
0026 ClassDeclaration::ClassDeclaration(ClassDeclarationData& data, const KDevelop::RangeInRevision& range,
0027                                    DUContext* context)
0028     : ClassMemberDeclaration(data, range)
0029 {
0030     setContext(context);
0031 }
0032 
0033 ClassDeclaration::ClassDeclaration(ClassDeclarationData& data)
0034     : ClassMemberDeclaration(data)
0035 {
0036 }
0037 
0038 REGISTER_DUCHAIN_ITEM(ClassDeclaration);
0039 
0040 void ClassDeclaration::clearBaseClasses()
0041 {
0042     d_func_dynamic()->baseClassesList().clear();
0043 }
0044 
0045 uint ClassDeclaration::baseClassesSize() const
0046 {
0047     return d_func()->baseClassesSize();
0048 }
0049 
0050 const BaseClassInstance* ClassDeclaration::baseClasses() const
0051 {
0052     return d_func()->baseClasses();
0053 }
0054 
0055 void ClassDeclaration::addBaseClass(const BaseClassInstance& klass)
0056 {
0057     d_func_dynamic()->baseClassesList().append(klass);
0058 }
0059 
0060 void ClassDeclaration::replaceBaseClass(uint n, const BaseClassInstance& klass)
0061 {
0062     Q_ASSERT(n <= d_func()->baseClassesSize());
0063     d_func_dynamic()->baseClassesList()[n] = klass;
0064 }
0065 
0066 ClassDeclaration::~ClassDeclaration()
0067 {
0068 }
0069 
0070 ClassDeclaration::ClassDeclaration(const ClassDeclaration& rhs)
0071     : ClassMemberDeclaration(*new ClassDeclarationData(*rhs.d_func()))
0072 {
0073     d_func_dynamic()->setClassId(this);
0074 }
0075 
0076 Declaration* ClassDeclaration::clonePrivate() const
0077 {
0078     return new ClassDeclaration(*this);
0079 }
0080 
0081 namespace {
0082 bool isPublicBaseClassInternal(const ClassDeclaration* self, ClassDeclaration* base,
0083                                const KDevelop::TopDUContext* topContext,
0084                                int* baseConversionLevels, int depth, QSet<const ClassDeclaration*>* checked)
0085 {
0086     if (checked) {
0087         if (checked->contains(self))
0088             return false;
0089         checked->insert(self);
0090     } else if (depth > 3) {
0091         //Too much depth, to prevent endless recursion, we control the recursion using the 'checked' set
0092         QSet<const ClassDeclaration*> checkedSet;
0093         return isPublicBaseClassInternal(self, base, topContext, baseConversionLevels, depth, &checkedSet);
0094     }
0095 
0096     if (baseConversionLevels)
0097         *baseConversionLevels = 0;
0098 
0099     if (self->indexedType() == base->indexedType())
0100         return true;
0101 
0102     FOREACH_FUNCTION(const BaseClassInstance &b, self->baseClasses)
0103     {
0104         if (baseConversionLevels)
0105             ++(*baseConversionLevels);
0106         //qCDebug(LANGUAGE) << "public base of" << c->toString() << "is" << b.baseClass->toString();
0107         if (b.access != KDevelop::Declaration::Private) {
0108             int nextBaseConversion = 0;
0109             if (StructureType::Ptr c = b.baseClass.type<StructureType>()) {
0110                 auto* decl = dynamic_cast<ClassDeclaration*>(c->declaration(topContext));
0111                 if (decl &&
0112                     isPublicBaseClassInternal(decl, base, topContext, &nextBaseConversion, depth + 1, checked)) {
0113                     if (baseConversionLevels)
0114                         *baseConversionLevels += nextBaseConversion;
0115                     return true;
0116                 }
0117             }
0118         }
0119         if (baseConversionLevels)
0120             --(*baseConversionLevels);
0121     }
0122     return false;
0123 }
0124 }
0125 
0126 bool ClassDeclaration::isPublicBaseClass(ClassDeclaration* base, const KDevelop::TopDUContext* topContext,
0127                                          int* baseConversionLevels) const
0128 {
0129     return isPublicBaseClassInternal(this, base, topContext, baseConversionLevels, 0, nullptr);
0130 }
0131 
0132 QString ClassDeclaration::toString() const
0133 {
0134     QString ret;
0135     switch (classModifier()) {
0136     case ClassDeclarationData::None:
0137         //nothing
0138         break;
0139     case ClassDeclarationData::Abstract:
0140         ret += QLatin1String("abstract ");
0141         break;
0142     case ClassDeclarationData::Final:
0143         ret += QLatin1String("final ");
0144         break;
0145     }
0146     switch (classType()) {
0147     case ClassDeclarationData::Class:
0148         ret += QLatin1String("class ");
0149         break;
0150     case ClassDeclarationData::Interface:
0151         ret += QLatin1String("interface ");
0152         break;
0153     case ClassDeclarationData::Trait:
0154         ret += QLatin1String("trait ");
0155         break;
0156     case ClassDeclarationData::Union:
0157         ret += QLatin1String("union ");
0158         break;
0159     case ClassDeclarationData::Struct:
0160         ret += QLatin1String("struct ");
0161         break;
0162     }
0163     return ret + identifier().toString();
0164 }
0165 
0166 ClassDeclarationData::ClassType ClassDeclaration::classType() const
0167 {
0168     return d_func()->m_classType;
0169 }
0170 
0171 void ClassDeclaration::setClassType(ClassDeclarationData::ClassType type)
0172 {
0173     d_func_dynamic()->m_classType = type;
0174 }
0175 
0176 ClassDeclarationData::ClassModifier ClassDeclaration::classModifier() const
0177 {
0178     return d_func()->m_classModifier;
0179 }
0180 
0181 void ClassDeclaration::setClassModifier(ClassDeclarationData::ClassModifier modifier)
0182 {
0183     d_func_dynamic()->m_classModifier = modifier;
0184 }
0185 }