1 /*
2     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden@kdevelop.org>
3     SPDX-FileCopyrightText: 2009 Lior Mualem <lior.m.kde@gmail.com>
4 
5     SPDX-License-Identifier: LGPL-2.0-only
6 */
7 
8 #include "classdeclaration.h"
9 #include "identifier.h"
10 #include <language/duchain/declaration.h>
11 #include <language/duchain/appendedlist.h>
12 #include <language/duchain/duchainregister.h>
13 #include "types/structuretype.h"
14 #include <debug.h>
15 
16 namespace KDevelop {
DEFINE_LIST_MEMBER_HASH(ClassDeclarationData,baseClasses,BaseClassInstance)17 DEFINE_LIST_MEMBER_HASH(ClassDeclarationData, baseClasses, BaseClassInstance)
18 
19 ClassDeclaration::ClassDeclaration(const KDevelop::RangeInRevision& range, DUContext* context)
20     : ClassMemberDeclaration(*new ClassDeclarationData, range)
21 {
22     d_func_dynamic()->setClassId(this);
23     setContext(context);
24 }
25 
ClassDeclaration(ClassDeclarationData & data,const KDevelop::RangeInRevision & range,DUContext * context)26 ClassDeclaration::ClassDeclaration(ClassDeclarationData& data, const KDevelop::RangeInRevision& range,
27                                    DUContext* context)
28     : ClassMemberDeclaration(data, range)
29 {
30     setContext(context);
31 }
32 
ClassDeclaration(ClassDeclarationData & data)33 ClassDeclaration::ClassDeclaration(ClassDeclarationData& data)
34     : ClassMemberDeclaration(data)
35 {
36 }
37 
38 REGISTER_DUCHAIN_ITEM(ClassDeclaration);
39 
clearBaseClasses()40 void ClassDeclaration::clearBaseClasses()
41 {
42     d_func_dynamic()->baseClassesList().clear();
43 }
44 
baseClassesSize() const45 uint ClassDeclaration::baseClassesSize() const
46 {
47     return d_func()->baseClassesSize();
48 }
49 
baseClasses() const50 const BaseClassInstance* ClassDeclaration::baseClasses() const
51 {
52     return d_func()->baseClasses();
53 }
54 
addBaseClass(const BaseClassInstance & klass)55 void ClassDeclaration::addBaseClass(const BaseClassInstance& klass)
56 {
57     d_func_dynamic()->baseClassesList().append(klass);
58 }
59 
replaceBaseClass(uint n,const BaseClassInstance & klass)60 void ClassDeclaration::replaceBaseClass(uint n, const BaseClassInstance& klass)
61 {
62     Q_ASSERT(n <= d_func()->baseClassesSize());
63     d_func_dynamic()->baseClassesList()[n] = klass;
64 }
65 
~ClassDeclaration()66 ClassDeclaration::~ClassDeclaration()
67 {
68 }
69 
ClassDeclaration(const ClassDeclaration & rhs)70 ClassDeclaration::ClassDeclaration(const ClassDeclaration& rhs)
71     : ClassMemberDeclaration(*new ClassDeclarationData(*rhs.d_func()))
72 {
73     d_func_dynamic()->setClassId(this);
74 }
75 
clonePrivate() const76 Declaration* ClassDeclaration::clonePrivate() const
77 {
78     return new ClassDeclaration(*this);
79 }
80 
81 namespace {
isPublicBaseClassInternal(const ClassDeclaration * self,ClassDeclaration * base,const KDevelop::TopDUContext * topContext,int * baseConversionLevels,int depth,QSet<const ClassDeclaration * > * checked)82 bool isPublicBaseClassInternal(const ClassDeclaration* self, ClassDeclaration* base,
83                                const KDevelop::TopDUContext* topContext,
84                                int* baseConversionLevels, int depth, QSet<const ClassDeclaration*>* checked)
85 {
86     if (checked) {
87         if (checked->contains(self))
88             return false;
89         checked->insert(self);
90     } else if (depth > 3) {
91         //Too much depth, to prevent endless recursion, we control the recursion using the 'checked' set
92         QSet<const ClassDeclaration*> checkedSet;
93         return isPublicBaseClassInternal(self, base, topContext, baseConversionLevels, depth, &checkedSet);
94     }
95 
96     if (baseConversionLevels)
97         *baseConversionLevels = 0;
98 
99     if (self->indexedType() == base->indexedType())
100         return true;
101 
102     FOREACH_FUNCTION(const BaseClassInstance &b, self->baseClasses)
103     {
104         if (baseConversionLevels)
105             ++(*baseConversionLevels);
106         //qCDebug(LANGUAGE) << "public base of" << c->toString() << "is" << b.baseClass->toString();
107         if (b.access != KDevelop::Declaration::Private) {
108             int nextBaseConversion = 0;
109             if (StructureType::Ptr c = b.baseClass.type<StructureType>()) {
110                 auto* decl = dynamic_cast<ClassDeclaration*>(c->declaration(topContext));
111                 if (decl &&
112                     isPublicBaseClassInternal(decl, base, topContext, &nextBaseConversion, depth + 1, checked)) {
113                     if (baseConversionLevels)
114                         *baseConversionLevels += nextBaseConversion;
115                     return true;
116                 }
117             }
118         }
119         if (baseConversionLevels)
120             --(*baseConversionLevels);
121     }
122     return false;
123 }
124 }
125 
isPublicBaseClass(ClassDeclaration * base,const KDevelop::TopDUContext * topContext,int * baseConversionLevels) const126 bool ClassDeclaration::isPublicBaseClass(ClassDeclaration* base, const KDevelop::TopDUContext* topContext,
127                                          int* baseConversionLevels) const
128 {
129     return isPublicBaseClassInternal(this, base, topContext, baseConversionLevels, 0, nullptr);
130 }
131 
toString() const132 QString ClassDeclaration::toString() const
133 {
134     QString ret;
135     switch (classModifier()) {
136     case ClassDeclarationData::None:
137         //nothing
138         break;
139     case ClassDeclarationData::Abstract:
140         ret += QLatin1String("abstract ");
141         break;
142     case ClassDeclarationData::Final:
143         ret += QLatin1String("final ");
144         break;
145     }
146     switch (classType()) {
147     case ClassDeclarationData::Class:
148         ret += QLatin1String("class ");
149         break;
150     case ClassDeclarationData::Interface:
151         ret += QLatin1String("interface ");
152         break;
153     case ClassDeclarationData::Trait:
154         ret += QLatin1String("trait ");
155         break;
156     case ClassDeclarationData::Union:
157         ret += QLatin1String("union ");
158         break;
159     case ClassDeclarationData::Struct:
160         ret += QLatin1String("struct ");
161         break;
162     }
163     return ret + identifier().toString();
164 }
165 
classType() const166 ClassDeclarationData::ClassType ClassDeclaration::classType() const
167 {
168     return d_func()->m_classType;
169 }
170 
setClassType(ClassDeclarationData::ClassType type)171 void ClassDeclaration::setClassType(ClassDeclarationData::ClassType type)
172 {
173     d_func_dynamic()->m_classType = type;
174 }
175 
classModifier() const176 ClassDeclarationData::ClassModifier ClassDeclaration::classModifier() const
177 {
178     return d_func()->m_classModifier;
179 }
180 
setClassModifier(ClassDeclarationData::ClassModifier modifier)181 void ClassDeclaration::setClassModifier(ClassDeclarationData::ClassModifier modifier)
182 {
183     d_func_dynamic()->m_classModifier = modifier;
184 }
185 }
186