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