1 /*
2     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
3     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
4 
5     SPDX-License-Identifier: LGPL-2.0-only
6 */
7 
8 #include "identifier.h"
9 
10 #include <QHash>
11 #include "stringhelpers.h"
12 #include "appendedlist_static.h"
13 #include "serialization/itemrepository.h"
14 #include "util/kdevhash.h"
15 #include <debug.h>
16 
17 #include <serialization/indexedstring.h>
18 #include <utility>
19 
20 #define ifDebug(x)
21 
22 namespace KDevelop {
23 template <bool dynamic = false>
24 class IdentifierPrivate
25 {
26 public:
IdentifierPrivate()27     IdentifierPrivate()
28     {
29     }
30 
31     template <bool rhsDynamic>
IdentifierPrivate(const IdentifierPrivate<rhsDynamic> & rhs)32     explicit IdentifierPrivate(const IdentifierPrivate<rhsDynamic>& rhs)
33         : m_unique(rhs.m_unique)
34         , m_identifier(rhs.m_identifier)
35         , m_refCount(0)
36         , m_hash(rhs.m_hash)
37     {
38         copyListsFrom(rhs);
39     }
40 
~IdentifierPrivate()41     ~IdentifierPrivate()
42     {
43         templateIdentifiersList.free(const_cast<IndexedTypeIdentifier*>(templateIdentifiers()));
44     }
45 
46     IdentifierPrivate& operator=(const IdentifierPrivate& rhs) = delete;
47 
48     //Flags the stored hash-value invalid
clearHash()49     void clearHash()
50     {
51         //This is always called on an object private to an Identifier, so there is no threading-problem.
52         Q_ASSERT(dynamic);
53         m_hash = 0;
54     }
55 
hash() const56     uint hash() const
57     {
58         // Since this only needs reading and the data needs not to be private, this may be called by
59         // multiple threads simultaneously, so computeHash() must be thread-safe.
60         if (!m_hash && dynamic)
61             computeHash();
62         return m_hash;
63     }
64 
65     int m_unique = 0;
66     IndexedString m_identifier;
67     uint m_refCount = 0;
68 
69     START_APPENDED_LISTS_STATIC(IdentifierPrivate)
70 
APPENDED_LIST_FIRST_STATIC(IndexedTypeIdentifier,templateIdentifiers)71     APPENDED_LIST_FIRST_STATIC(IndexedTypeIdentifier, templateIdentifiers)
72 
73     END_APPENDED_LISTS_STATIC(templateIdentifiers)
74 
75     uint itemSize() const
76     {
77         return sizeof(IdentifierPrivate<false> ) + lastOffsetBehind();
78     }
79 
computeHash() const80     void computeHash() const
81     {
82         Q_ASSERT(dynamic);
83         //this must stay thread-safe(may be called by multiple threads at a time)
84         //The thread-safety is given because all threads will have the same result, and it will only be written once at the end.
85         KDevHash kdevhash;
86         kdevhash << m_identifier.hash() << m_unique;
87         FOREACH_FUNCTION_STATIC(const IndexedTypeIdentifier &templateIdentifier, templateIdentifiers)
88         kdevhash << templateIdentifier.hash();
89         m_hash = kdevhash;
90     }
91 
92     mutable uint m_hash = 0;
93 };
94 
95 using DynamicIdentifierPrivate = IdentifierPrivate<true>;
96 using ConstantIdentifierPrivate = IdentifierPrivate<false>;
97 
98 struct IdentifierItemRequest
99 {
IdentifierItemRequestKDevelop::IdentifierItemRequest100     IdentifierItemRequest(const DynamicIdentifierPrivate& identifier)
101         : m_identifier(identifier)
102     {
103         identifier.hash(); //Make sure the hash is valid by calling this
104     }
105 
106     enum {
107         AverageSize = sizeof(IdentifierPrivate<false> ) + 4
108     };
109 
110     //Should return the hash-value associated with this request(For example the hash of a string)
hashKDevelop::IdentifierItemRequest111     uint hash() const
112     {
113         return m_identifier.hash();
114     }
115 
116     //Should return the size of an item created with createItem
itemSizeKDevelop::IdentifierItemRequest117     uint itemSize() const
118     {
119         return m_identifier.itemSize();
120     }
121     //Should create an item where the information of the requested item is permanently stored. The pointer
122     //@param item equals an allocated range with the size of itemSize().
createItemKDevelop::IdentifierItemRequest123     void createItem(ConstantIdentifierPrivate* item) const
124     {
125         new (item) ConstantIdentifierPrivate(m_identifier);
126     }
127 
persistentKDevelop::IdentifierItemRequest128     static bool persistent(const ConstantIdentifierPrivate* item)
129     {
130         return ( bool )item->m_refCount;
131     }
132 
destroyKDevelop::IdentifierItemRequest133     static void destroy(ConstantIdentifierPrivate* item, AbstractItemRepository&)
134     {
135         item->~ConstantIdentifierPrivate();
136     }
137 
138     //Should return whether the here requested item equals the given item
equalsKDevelop::IdentifierItemRequest139     bool equals(const ConstantIdentifierPrivate* item) const
140     {
141         return item->m_hash == m_identifier.m_hash
142                && item->m_unique == m_identifier.m_unique
143                && item->m_identifier == m_identifier.m_identifier
144                && m_identifier.listsEqual(*item);
145     }
146 
147     const DynamicIdentifierPrivate& m_identifier;
148 };
149 
150 using IdentifierRepository = RepositoryManager<ItemRepository<ConstantIdentifierPrivate, IdentifierItemRequest>, false>;
identifierRepository()151 static IdentifierRepository& identifierRepository()
152 {
153     static IdentifierRepository identifierRepositoryObject(QStringLiteral("Identifier Repository"));
154     return identifierRepositoryObject;
155 }
156 
emptyConstantIdentifierPrivateIndex()157 static uint emptyConstantIdentifierPrivateIndex()
158 {
159     static const uint index = identifierRepository()->index(DynamicIdentifierPrivate());
160     return index;
161 }
162 
emptyConstantIdentifierPrivate()163 static const ConstantIdentifierPrivate* emptyConstantIdentifierPrivate()
164 {
165     static const ConstantIdentifierPrivate item;
166     return &item;
167 }
168 
isEmpty() const169 bool IndexedIdentifier::isEmpty() const
170 {
171     return m_index == emptyConstantIdentifierPrivateIndex();
172 }
173 
174 /**
175  * Before something is modified in QualifiedIdentifierPrivate, it must be made sure that
176  * it is private to the QualifiedIdentifier it is used in(@see QualifiedIdentifier::prepareWrite)
177  */
178 template <bool dynamic>
179 class QualifiedIdentifierPrivate
180 {
181 public:
QualifiedIdentifierPrivate()182     QualifiedIdentifierPrivate()
183         : m_explicitlyGlobal(false)
184         , m_isExpression(false)
185 
186     {
187     }
188 
189     template <bool rhsDynamic>
QualifiedIdentifierPrivate(const QualifiedIdentifierPrivate<rhsDynamic> & rhs)190     explicit QualifiedIdentifierPrivate(const QualifiedIdentifierPrivate<rhsDynamic>& rhs)
191         : m_explicitlyGlobal(rhs.m_explicitlyGlobal)
192         , m_isExpression(rhs.m_isExpression)
193         , m_hash(rhs.m_hash)
194         , m_refCount(0)
195     {
196         copyListsFrom(rhs);
197     }
198 
~QualifiedIdentifierPrivate()199     ~QualifiedIdentifierPrivate()
200     {
201         identifiersList.free(const_cast<IndexedIdentifier*>(identifiers()));
202     }
203 
204     QualifiedIdentifierPrivate& operator=(const QualifiedIdentifierPrivate& rhs) = delete;
205 
206     bool m_explicitlyGlobal : 1;
207     bool m_isExpression : 1;
208     mutable uint m_hash = 0;
209     uint m_refCount = 0;
210 
211     START_APPENDED_LISTS_STATIC(QualifiedIdentifierPrivate)
212 
APPENDED_LIST_FIRST_STATIC(IndexedIdentifier,identifiers)213     APPENDED_LIST_FIRST_STATIC(IndexedIdentifier, identifiers)
214 
215     END_APPENDED_LISTS_STATIC(identifiers)
216 
217     uint itemSize() const
218     {
219         return sizeof(QualifiedIdentifierPrivate<false> ) + lastOffsetBehind();
220     }
221 
222     //Constructs m_identifiers
splitIdentifiers(const QString & str,int start)223     void splitIdentifiers(const QString& str, int start)
224     {
225         Q_ASSERT(dynamic);
226         uint currentStart = start;
227 
228         while (currentStart < ( uint )str.length()) {
229             identifiersList.append(IndexedIdentifier(Identifier(str, currentStart, &currentStart)));
230             while (currentStart < ( uint )str.length() && (str[currentStart] == QLatin1Char(' ')))
231                 ++currentStart;
232             currentStart += 2; //Skip "::"
233         }
234     }
235 
clearHash() const236     inline void clearHash() const
237     {
238         m_hash = 0;
239     }
240 
hash() const241     uint hash() const
242     {
243         if (m_hash == 0) {
244             KDevHash hash;
245 
246             quint32 bitfields = static_cast<quint32>(m_explicitlyGlobal)
247                                 | (m_isExpression << 1);
248             hash << bitfields << identifiersSize();
249             FOREACH_FUNCTION_STATIC(const IndexedIdentifier &identifier, identifiers) {
250                 hash << identifier.index();
251             }
252 
253             m_hash = hash;
254         }
255         return m_hash;
256     }
257 };
258 
259 using DynamicQualifiedIdentifierPrivate = QualifiedIdentifierPrivate<true>;
260 using ConstantQualifiedIdentifierPrivate = QualifiedIdentifierPrivate<false>;
261 
262 struct QualifiedIdentifierItemRequest
263 {
QualifiedIdentifierItemRequestKDevelop::QualifiedIdentifierItemRequest264     QualifiedIdentifierItemRequest(const DynamicQualifiedIdentifierPrivate& identifier)
265         : m_identifier(identifier)
266     {
267         identifier.hash(); //Make sure the hash is valid by calling this
268     }
269 
270     enum {
271         AverageSize = sizeof(QualifiedIdentifierPrivate<false> ) + 8
272     };
273 
274     //Should return the hash-value associated with this request(For example the hash of a string)
hashKDevelop::QualifiedIdentifierItemRequest275     uint hash() const
276     {
277         return m_identifier.hash();
278     }
279 
280     //Should return the size of an item created with createItem
itemSizeKDevelop::QualifiedIdentifierItemRequest281     uint itemSize() const
282     {
283         return m_identifier.itemSize();
284     }
285 
286     /**
287      * Should create an item where the information of the requested item is permanently stored. The pointer
288      * @param item equals an allocated range with the size of itemSize().
289      */
createItemKDevelop::QualifiedIdentifierItemRequest290     void createItem(ConstantQualifiedIdentifierPrivate* item) const
291     {
292         Q_ASSERT(shouldDoDUChainReferenceCounting(item));
293         Q_ASSERT(shouldDoDUChainReferenceCounting(reinterpret_cast<char*>(item) + (itemSize() - 1)));
294         new (item) ConstantQualifiedIdentifierPrivate(m_identifier);
295     }
296 
persistentKDevelop::QualifiedIdentifierItemRequest297     static bool persistent(const ConstantQualifiedIdentifierPrivate* item)
298     {
299         return ( bool )item->m_refCount;
300     }
301 
destroyKDevelop::QualifiedIdentifierItemRequest302     static void destroy(ConstantQualifiedIdentifierPrivate* item, AbstractItemRepository&)
303     {
304         Q_ASSERT(shouldDoDUChainReferenceCounting(item));
305         item->~ConstantQualifiedIdentifierPrivate();
306     }
307 
308     //Should return whether the here requested item equals the given item
equalsKDevelop::QualifiedIdentifierItemRequest309     bool equals(const ConstantQualifiedIdentifierPrivate* item) const
310     {
311         return item->m_explicitlyGlobal == m_identifier.m_explicitlyGlobal
312                && item->m_isExpression == m_identifier.m_isExpression
313                && item->m_hash == m_identifier.m_hash
314                && m_identifier.listsEqual(*item);
315     }
316 
317     const DynamicQualifiedIdentifierPrivate& m_identifier;
318 };
319 
320 using QualifiedIdentifierRepository = RepositoryManager<ItemRepository<ConstantQualifiedIdentifierPrivate,
321         QualifiedIdentifierItemRequest>, false>;
322 
qualifiedidentifierRepository()323 static QualifiedIdentifierRepository& qualifiedidentifierRepository()
324 {
325     static QualifiedIdentifierRepository repo(QStringLiteral("Qualified Identifier Repository"), 1,
326         []() -> AbstractRepositoryManager* {
327         return &identifierRepository();
328             });
329     return repo;
330 }
331 
emptyConstantQualifiedIdentifierPrivateIndex()332 static uint emptyConstantQualifiedIdentifierPrivateIndex()
333 {
334     static const uint index = qualifiedidentifierRepository()->index(DynamicQualifiedIdentifierPrivate());
335     return index;
336 }
337 
emptyConstantQualifiedIdentifierPrivate()338 static const ConstantQualifiedIdentifierPrivate* emptyConstantQualifiedIdentifierPrivate()
339 {
340     static const ConstantQualifiedIdentifierPrivate item;
341     return &item;
342 }
343 
Identifier(const Identifier & rhs)344 Identifier::Identifier(const Identifier& rhs)
345 {
346     rhs.makeConstant();
347     cd = rhs.cd;
348     m_index = rhs.m_index;
349 }
350 
Identifier(uint index)351 Identifier::Identifier(uint index)
352     : m_index(index)
353 {
354     Q_ASSERT(m_index);
355     cd = identifierRepository()->itemFromIndex(index);
356 }
357 
Identifier(const IndexedString & str)358 Identifier::Identifier(const IndexedString& str)
359 {
360     if (str.isEmpty()) {
361         m_index = emptyConstantIdentifierPrivateIndex();
362         cd = emptyConstantIdentifierPrivate();
363     } else {
364         m_index = 0;
365         dd = new IdentifierPrivate<true>;
366         dd->m_identifier = str;
367     }
368 }
369 
Identifier(const QString & id,uint start,uint * takenRange)370 Identifier::Identifier(const QString& id, uint start, uint* takenRange)
371 {
372     if (id.isEmpty()) {
373         m_index = emptyConstantIdentifierPrivateIndex();
374         cd = emptyConstantIdentifierPrivate();
375         return;
376     }
377 
378     m_index = 0;
379     dd = new IdentifierPrivate<true>;
380 
381     ///Extract template-parameters
382     ParamIterator paramIt(QStringLiteral("<>:"), id, start);
383     dd->m_identifier = IndexedString(paramIt.prefix().trimmed());
384     while (paramIt) {
385         appendTemplateIdentifier(IndexedTypeIdentifier(IndexedQualifiedIdentifier(QualifiedIdentifier(*paramIt))));
386         ++paramIt;
387     }
388 
389     if (takenRange)
390         *takenRange = paramIt.position();
391 }
392 
Identifier()393 Identifier::Identifier()
394     : m_index(emptyConstantIdentifierPrivateIndex())
395     , cd(emptyConstantIdentifierPrivate())
396 {
397 }
398 
operator =(const Identifier & rhs)399 Identifier& Identifier::operator=(const Identifier& rhs)
400 {
401     if (dd == rhs.dd && cd == rhs.cd)
402         return *this;
403 
404     if (!m_index)
405         delete dd;
406     dd = nullptr;
407 
408     rhs.makeConstant();
409     cd = rhs.cd;
410     m_index = rhs.m_index;
411     Q_ASSERT(cd);
412     return *this;
413 }
414 
Identifier(Identifier && rhs)415 Identifier::Identifier(Identifier&& rhs) Q_DECL_NOEXCEPT
416     : m_index(rhs.m_index)
417 {
418     if (m_index) {
419         cd = rhs.cd;
420     } else {
421         dd = rhs.dd;
422     }
423     rhs.cd = emptyConstantIdentifierPrivate();
424     rhs.m_index = emptyConstantIdentifierPrivateIndex();
425 }
426 
operator =(Identifier && rhs)427 Identifier& Identifier::operator=(Identifier&& rhs) Q_DECL_NOEXCEPT
428 {
429     if (dd == rhs.dd && cd == rhs.cd)
430         return *this;
431 
432     if (!m_index) {
433         delete dd;
434         dd = nullptr;
435     }
436 
437     m_index = rhs.m_index;
438 
439     if (m_index) {
440         cd = rhs.cd;
441     } else {
442         dd = rhs.dd;
443     }
444     rhs.cd = emptyConstantIdentifierPrivate();
445     rhs.m_index = emptyConstantIdentifierPrivateIndex();
446 
447     return *this;
448 }
449 
~Identifier()450 Identifier::~Identifier()
451 {
452     if (!m_index)
453         delete dd;
454 }
455 
nameEquals(const Identifier & rhs) const456 bool Identifier::nameEquals(const Identifier& rhs) const
457 {
458     return identifier() == rhs.identifier();
459 }
460 
hash() const461 uint Identifier::hash() const
462 {
463     if (!m_index)
464         return dd->hash();
465     else
466         return cd->hash();
467 }
468 
isEmpty() const469 bool Identifier::isEmpty() const
470 {
471     if (!m_index)
472         return dd->m_identifier.isEmpty() && dd->m_unique == 0 && dd->templateIdentifiersSize() == 0;
473     else
474         return cd->m_identifier.isEmpty() && cd->m_unique == 0 && cd->templateIdentifiersSize() == 0;
475 }
476 
unique(int token)477 Identifier Identifier::unique(int token)
478 {
479     Identifier ret;
480     ret.setUnique(token);
481     return ret;
482 }
483 
isUnique() const484 bool Identifier::isUnique() const
485 {
486     if (!m_index)
487         return dd->m_unique;
488     else
489         return cd->m_unique;
490 }
491 
uniqueToken() const492 int Identifier::uniqueToken() const
493 {
494     if (!m_index)
495         return dd->m_unique;
496     else
497         return cd->m_unique;
498 }
499 
setUnique(int token)500 void Identifier::setUnique(int token)
501 {
502     if (token != uniqueToken()) {
503         prepareWrite();
504         dd->m_unique = token;
505     }
506 }
507 
identifier() const508 const IndexedString Identifier::identifier() const
509 {
510     if (!m_index)
511         return dd->m_identifier;
512     else
513         return cd->m_identifier;
514 }
515 
setIdentifier(const QString & identifier)516 void Identifier::setIdentifier(const QString& identifier)
517 {
518     IndexedString id(identifier);
519     if (id != this->identifier()) {
520         prepareWrite();
521         dd->m_identifier = std::move(id);
522     }
523 }
524 
setIdentifier(const IndexedString & identifier)525 void Identifier::setIdentifier(const IndexedString& identifier)
526 {
527     if (identifier != this->identifier()) {
528         prepareWrite();
529         dd->m_identifier = identifier;
530     }
531 }
532 
templateIdentifier(int num) const533 IndexedTypeIdentifier Identifier::templateIdentifier(int num) const
534 {
535     if (!m_index)
536         return dd->templateIdentifiers()[num];
537     else
538         return cd->templateIdentifiers()[num];
539 }
540 
templateIdentifiersCount() const541 uint Identifier::templateIdentifiersCount() const
542 {
543     if (!m_index)
544         return dd->templateIdentifiersSize();
545     else
546         return cd->templateIdentifiersSize();
547 }
548 
appendTemplateIdentifier(const IndexedTypeIdentifier & identifier)549 void Identifier::appendTemplateIdentifier(const IndexedTypeIdentifier& identifier)
550 {
551     prepareWrite();
552     dd->templateIdentifiersList.append(identifier);
553 }
554 
clearTemplateIdentifiers()555 void Identifier::clearTemplateIdentifiers()
556 {
557     prepareWrite();
558     dd->templateIdentifiersList.clear();
559 }
560 
index() const561 uint Identifier::index() const
562 {
563     makeConstant();
564     Q_ASSERT(m_index);
565     return m_index;
566 }
567 
inRepository() const568 bool Identifier::inRepository() const
569 {
570     return m_index;
571 }
572 
setTemplateIdentifiers(const QList<IndexedTypeIdentifier> & templateIdentifiers)573 void Identifier::setTemplateIdentifiers(const QList<IndexedTypeIdentifier>& templateIdentifiers)
574 {
575     prepareWrite();
576     dd->templateIdentifiersList.clear();
577     for (const IndexedTypeIdentifier& id : templateIdentifiers) {
578         dd->templateIdentifiersList.append(id);
579     }
580 }
581 
toString(IdentifierStringFormattingOptions options) const582 QString Identifier::toString(IdentifierStringFormattingOptions options) const
583 {
584     QString ret = identifier().str();
585 
586     if (!options.testFlag(RemoveTemplateInformation) && templateIdentifiersCount()) {
587         QStringList templateIds;
588         templateIds.reserve(templateIdentifiersCount());
589         for (uint i = 0; i < templateIdentifiersCount(); ++i) {
590             templateIds.append(templateIdentifier(i).toString(options));
591         }
592 
593         ret += QLatin1String("< ") + templateIds.join(QLatin1String(", ")) + QLatin1String(" >");
594     }
595 
596     return ret;
597 }
598 
operator ==(const Identifier & rhs) const599 bool Identifier::operator==(const Identifier& rhs) const
600 {
601     return index() == rhs.index();
602 }
603 
operator !=(const Identifier & rhs) const604 bool Identifier::operator!=(const Identifier& rhs) const
605 {
606     return !operator==(rhs);
607 }
608 
index() const609 uint QualifiedIdentifier::index() const
610 {
611     makeConstant();
612     Q_ASSERT(m_index);
613     return m_index;
614 }
615 
makeConstant() const616 void Identifier::makeConstant() const
617 {
618     if (m_index)
619         return;
620     m_index = identifierRepository()->index(IdentifierItemRequest(*dd));
621     delete dd;
622     cd = identifierRepository()->itemFromIndex(m_index);
623 }
624 
prepareWrite()625 void Identifier::prepareWrite()
626 {
627     if (m_index) {
628         const IdentifierPrivate<false>* oldCc = cd;
629         dd = new IdentifierPrivate<true>;
630         dd->m_hash = oldCc->m_hash;
631         dd->m_unique = oldCc->m_unique;
632         dd->m_identifier = oldCc->m_identifier;
633         dd->copyListsFrom(*oldCc);
634         m_index = 0;
635     }
636 
637     dd->clearHash();
638 }
639 
inRepository() const640 bool QualifiedIdentifier::inRepository() const
641 {
642     if (m_index)
643         return true;
644     else
645         return ( bool )qualifiedidentifierRepository()->findIndex(QualifiedIdentifierItemRequest(*dd));
646 }
647 
QualifiedIdentifier(uint index)648 QualifiedIdentifier::QualifiedIdentifier(uint index)
649     : m_index(index)
650     , cd(qualifiedidentifierRepository()->itemFromIndex(index))
651 {
652 }
653 
QualifiedIdentifier(const QString & id,bool isExpression)654 QualifiedIdentifier::QualifiedIdentifier(const QString& id, bool isExpression)
655 {
656     if (id.isEmpty()) {
657         m_index = emptyConstantQualifiedIdentifierPrivateIndex();
658         cd = emptyConstantQualifiedIdentifierPrivate();
659         return;
660     }
661 
662     m_index = 0;
663     dd = new DynamicQualifiedIdentifierPrivate;
664 
665     if (isExpression) {
666         setIsExpression(true);
667         if (!id.isEmpty()) {
668             //Prevent tokenization, since we may lose information there
669             Identifier finishedId;
670             finishedId.setIdentifier(id);
671             push(finishedId);
672         }
673     } else {
674         if (id.startsWith(QLatin1String("::"))) {
675             dd->m_explicitlyGlobal = true;
676             dd->splitIdentifiers(id, 2);
677         } else {
678             dd->m_explicitlyGlobal = false;
679             dd->splitIdentifiers(id, 0);
680         }
681     }
682 }
683 
QualifiedIdentifier(const Identifier & id)684 QualifiedIdentifier::QualifiedIdentifier(const Identifier& id)
685 {
686     if (id.isEmpty()) {
687         m_index = emptyConstantQualifiedIdentifierPrivateIndex();
688         cd = emptyConstantQualifiedIdentifierPrivate();
689         return;
690     }
691 
692     m_index = 0;
693     dd = new DynamicQualifiedIdentifierPrivate;
694 
695     if (id.dd->m_identifier.str().isEmpty()) {
696         dd->m_explicitlyGlobal = true;
697     } else {
698         dd->m_explicitlyGlobal = false;
699         dd->identifiersList.append(IndexedIdentifier(id));
700     }
701 }
702 
QualifiedIdentifier()703 QualifiedIdentifier::QualifiedIdentifier()
704     : m_index(emptyConstantQualifiedIdentifierPrivateIndex())
705     , cd(emptyConstantQualifiedIdentifierPrivate())
706 {
707 }
708 
QualifiedIdentifier(const QualifiedIdentifier & id)709 QualifiedIdentifier::QualifiedIdentifier(const QualifiedIdentifier& id)
710 {
711     if (id.m_index) {
712         m_index = id.m_index;
713         cd = id.cd;
714     } else {
715         m_index = 0;
716         dd = new QualifiedIdentifierPrivate<true>(*id.dd);
717     }
718 }
719 
QualifiedIdentifier(QualifiedIdentifier && rhs)720 QualifiedIdentifier::QualifiedIdentifier(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT
721     : m_index(rhs.m_index)
722 {
723     if (m_index) {
724         cd = rhs.cd;
725     } else {
726         dd = rhs.dd;
727     }
728     rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex();
729     rhs.cd = emptyConstantQualifiedIdentifierPrivate();
730 }
731 
operator =(const QualifiedIdentifier & rhs)732 QualifiedIdentifier& QualifiedIdentifier::operator=(const QualifiedIdentifier& rhs)
733 {
734     if (dd == rhs.dd && cd == rhs.cd)
735         return *this;
736 
737     if (!m_index)
738         delete dd;
739     rhs.makeConstant();
740     cd = rhs.cd;
741     m_index = rhs.m_index;
742     return *this;
743 }
744 
operator =(QualifiedIdentifier && rhs)745 QualifiedIdentifier& QualifiedIdentifier::operator=(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT
746 {
747     if (!m_index)
748         delete dd;
749     m_index = rhs.m_index;
750     if (m_index) {
751         cd = rhs.cd;
752     } else {
753         dd = rhs.dd;
754     }
755     rhs.cd = emptyConstantQualifiedIdentifierPrivate();
756     rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex();
757     return *this;
758 }
759 
~QualifiedIdentifier()760 QualifiedIdentifier::~QualifiedIdentifier()
761 {
762     if (!m_index)
763         delete dd;
764 }
765 
toStringList(IdentifierStringFormattingOptions options) const766 QStringList QualifiedIdentifier::toStringList(IdentifierStringFormattingOptions options) const
767 {
768     QStringList ret;
769     ret.reserve(explicitlyGlobal() + count());
770     if (explicitlyGlobal())
771         ret.append(QString());
772 
773     if (m_index) {
774         ret.reserve(ret.size() + cd->identifiersSize());
775         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, cd->identifiers)
776         ret << index.identifier().toString(options);
777     } else {
778         ret.reserve(ret.size() + dd->identifiersSize());
779         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, dd->identifiers)
780         ret << index.identifier().toString(options);
781     }
782 
783     return ret;
784 }
785 
toString(IdentifierStringFormattingOptions options) const786 QString QualifiedIdentifier::toString(IdentifierStringFormattingOptions options) const
787 {
788     const QString doubleColon = QStringLiteral("::");
789 
790     QString ret;
791     if (!options.testFlag(RemoveExplicitlyGlobalPrefix) && explicitlyGlobal())
792         ret = doubleColon;
793 
794     QStringList identifiers;
795     if (m_index) {
796         identifiers.reserve(cd->identifiersSize());
797         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, cd->identifiers)
798         {
799             identifiers += index.identifier().toString(options);
800         }
801     } else {
802         identifiers.reserve(dd->identifiersSize());
803         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, dd->identifiers)
804         {
805             identifiers += index.identifier().toString(options);
806         }
807     }
808 
809     return ret + identifiers.join(doubleColon);
810 }
811 
merge(const QualifiedIdentifier & base) const812 QualifiedIdentifier QualifiedIdentifier::merge(const QualifiedIdentifier& base) const
813 {
814     QualifiedIdentifier ret(base);
815     ret.push(*this);
816     return ret;
817 }
818 
operator +(const QualifiedIdentifier & rhs) const819 QualifiedIdentifier QualifiedIdentifier::operator+(const QualifiedIdentifier& rhs) const
820 {
821     return rhs.merge(*this);
822 }
823 
operator +=(const QualifiedIdentifier & rhs)824 QualifiedIdentifier& QualifiedIdentifier::operator+=(const QualifiedIdentifier& rhs)
825 {
826     push(rhs);
827     return *this;
828 }
829 
operator +(const Identifier & rhs) const830 QualifiedIdentifier QualifiedIdentifier::operator+(const Identifier& rhs) const
831 {
832     QualifiedIdentifier ret(*this);
833     ret.push(rhs);
834     return ret;
835 }
836 
operator +=(const Identifier & rhs)837 QualifiedIdentifier& QualifiedIdentifier::operator+=(const Identifier& rhs)
838 {
839     push(rhs);
840     return *this;
841 }
842 
operator +(const IndexedIdentifier & rhs) const843 QualifiedIdentifier QualifiedIdentifier::operator+(const IndexedIdentifier& rhs) const
844 {
845     QualifiedIdentifier ret(*this);
846     ret.push(rhs);
847     return ret;
848 }
849 
operator +=(const IndexedIdentifier & rhs)850 QualifiedIdentifier& QualifiedIdentifier::operator+=(const IndexedIdentifier& rhs)
851 {
852     push(rhs);
853     return *this;
854 }
855 
isExpression() const856 bool QualifiedIdentifier::isExpression() const
857 {
858     if (m_index)
859         return cd->m_isExpression;
860     else
861         return dd->m_isExpression;
862 }
863 
setIsExpression(bool is)864 void QualifiedIdentifier::setIsExpression(bool is)
865 {
866     if (is != isExpression()) {
867         prepareWrite();
868         dd->m_isExpression = is;
869     }
870 }
871 
explicitlyGlobal() const872 bool QualifiedIdentifier::explicitlyGlobal() const
873 {
874     // True if started with "::"
875     if (m_index)
876         return cd->m_explicitlyGlobal;
877     else
878         return dd->m_explicitlyGlobal;
879 }
880 
setExplicitlyGlobal(bool eg)881 void QualifiedIdentifier::setExplicitlyGlobal(bool eg)
882 {
883     if (eg != explicitlyGlobal()) {
884         prepareWrite();
885         dd->m_explicitlyGlobal = eg;
886     }
887 }
888 
sameIdentifiers(const QualifiedIdentifier & rhs) const889 bool QualifiedIdentifier::sameIdentifiers(const QualifiedIdentifier& rhs) const
890 {
891     if (m_index && rhs.m_index)
892         return cd->listsEqual(*rhs.cd);
893     else if (m_index && !rhs.m_index)
894         return cd->listsEqual(*rhs.dd);
895     else if (!m_index && !rhs.m_index)
896         return dd->listsEqual(*rhs.dd);
897     else
898         return dd->listsEqual(*rhs.cd);
899 }
900 
operator ==(const QualifiedIdentifier & rhs) const901 bool QualifiedIdentifier::operator==(const QualifiedIdentifier& rhs) const
902 {
903     if (cd == rhs.cd)
904         return true;
905     return hash() == rhs.hash() && sameIdentifiers(rhs);
906 }
907 
operator !=(const QualifiedIdentifier & rhs) const908 bool QualifiedIdentifier::operator!=(const QualifiedIdentifier& rhs) const
909 {
910     return !operator==(rhs);
911 }
912 
beginsWith(const QualifiedIdentifier & other) const913 bool QualifiedIdentifier::beginsWith(const QualifiedIdentifier& other) const
914 {
915     uint c = count();
916     uint oc = other.count();
917 
918     for (uint i = 0; i < c && i < oc; ++i)
919         if (at(i) == other.at(i)) {
920             continue;
921         } else {
922             return false;
923         }
924 
925     return true;
926 }
927 
928 struct Visitor
929 {
VisitorKDevelop::Visitor930     Visitor(KDevVarLengthArray<QualifiedIdentifier>& target, uint hash)
931         : target(target)
932         , hash(hash)
933     {
934     }
935 
operator ()KDevelop::Visitor936     bool operator()(const ConstantQualifiedIdentifierPrivate* item, uint index) const
937     {
938         if (item->m_hash == hash)
939             target.append(QualifiedIdentifier(index));
940         return true;
941     }
942 
943     KDevVarLengthArray<QualifiedIdentifier>& target;
944     const uint hash;
945 };
946 
hash() const947 uint QualifiedIdentifier::hash() const
948 {
949     if (m_index)
950         return cd->hash();
951     else
952         return dd->hash();
953 }
954 
qHash(const IndexedTypeIdentifier & id)955 uint qHash(const IndexedTypeIdentifier& id)
956 {
957     return id.hash();
958 }
959 
qHash(const QualifiedIdentifier & id)960 uint qHash(const QualifiedIdentifier& id)
961 {
962     return id.hash();
963 }
964 
qHash(const Identifier & id)965 uint qHash(const Identifier& id)
966 {
967     return id.hash();
968 }
969 
isQualified() const970 bool QualifiedIdentifier::isQualified() const
971 {
972     return count() > 1 || explicitlyGlobal();
973 }
974 
push(const Identifier & id)975 void QualifiedIdentifier::push(const Identifier& id)
976 {
977     if (id.isEmpty())
978         return;
979 
980     push(IndexedIdentifier(id));
981 }
982 
push(const IndexedIdentifier & id)983 void QualifiedIdentifier::push(const IndexedIdentifier& id)
984 {
985     if (id.isEmpty()) {
986         return;
987     }
988 
989     prepareWrite();
990 
991     dd->identifiersList.append(id);
992 }
993 
push(const QualifiedIdentifier & id)994 void QualifiedIdentifier::push(const QualifiedIdentifier& id)
995 {
996     if (id.isEmpty()) {
997         return;
998     }
999 
1000     prepareWrite();
1001 
1002     if (id.m_index) {
1003         dd->identifiersList.append(id.cd->identifiers(), id.cd->identifiersSize());
1004     } else {
1005         dd->identifiersList.append(id.dd->identifiers(), id.dd->identifiersSize());
1006     }
1007 
1008     if (id.explicitlyGlobal()) {
1009         setExplicitlyGlobal(true);
1010     }
1011 }
1012 
pop()1013 void QualifiedIdentifier::pop()
1014 {
1015     prepareWrite();
1016     if (!dd->identifiersSize())
1017         return;
1018     dd->identifiersList.resize(dd->identifiersList.size() - 1);
1019 }
1020 
clear()1021 void QualifiedIdentifier::clear()
1022 {
1023     prepareWrite();
1024     dd->identifiersList.clear();
1025     dd->m_explicitlyGlobal = false;
1026     dd->m_isExpression = false;
1027 }
1028 
isEmpty() const1029 bool QualifiedIdentifier::isEmpty() const
1030 {
1031     if (m_index)
1032         return cd->identifiersSize() == 0;
1033     else
1034         return dd->identifiersSize() == 0;
1035 }
1036 
count() const1037 int QualifiedIdentifier::count() const
1038 {
1039     if (m_index)
1040         return cd->identifiersSize();
1041     else
1042         return dd->identifiersSize();
1043 }
1044 
first() const1045 Identifier QualifiedIdentifier::first() const
1046 {
1047     return indexedFirst().identifier();
1048 }
1049 
indexedFirst() const1050 IndexedIdentifier QualifiedIdentifier::indexedFirst() const
1051 {
1052     if ((m_index && cd->identifiersSize() == 0) || (!m_index && dd->identifiersSize() == 0))
1053         return IndexedIdentifier();
1054     else
1055         return indexedAt(0);
1056 }
1057 
last() const1058 Identifier QualifiedIdentifier::last() const
1059 {
1060     return indexedLast().identifier();
1061 }
1062 
indexedLast() const1063 IndexedIdentifier QualifiedIdentifier::indexedLast() const
1064 {
1065     uint c = count();
1066     if (c)
1067         return indexedAt(c - 1);
1068     else
1069         return IndexedIdentifier();
1070 }
1071 
top() const1072 Identifier QualifiedIdentifier::top() const
1073 {
1074     return last();
1075 }
1076 
mid(int pos,int len) const1077 QualifiedIdentifier QualifiedIdentifier::mid(int pos, int len) const
1078 {
1079     QualifiedIdentifier ret;
1080     if (pos == 0)
1081         ret.setExplicitlyGlobal(explicitlyGlobal());
1082 
1083     int cnt = ( int )count();
1084 
1085     if (len == -1)
1086         len = cnt - pos;
1087 
1088     if (pos + len > cnt)
1089         len -= cnt - (pos + len);
1090 
1091     for (int a = pos; a < pos + len; a++)
1092         ret.push(at(a));
1093 
1094     return ret;
1095 }
1096 
at(int i) const1097 Identifier QualifiedIdentifier::at(int i) const
1098 {
1099     return indexedAt(i).identifier();
1100 }
1101 
indexedAt(int i) const1102 IndexedIdentifier QualifiedIdentifier::indexedAt(int i) const
1103 {
1104     if (m_index) {
1105         Q_ASSERT(i >= 0 && i < ( int )cd->identifiersSize());
1106         return cd->identifiers()[i];
1107     } else {
1108         Q_ASSERT(i >= 0 && i < ( int )dd->identifiersSize());
1109         return dd->identifiers()[i];
1110     }
1111 }
1112 
makeConstant() const1113 void QualifiedIdentifier::makeConstant() const
1114 {
1115     if (m_index)
1116         return;
1117     m_index = qualifiedidentifierRepository()->index(QualifiedIdentifierItemRequest(*dd));
1118     delete dd;
1119     cd = qualifiedidentifierRepository()->itemFromIndex(m_index);
1120 }
1121 
prepareWrite()1122 void QualifiedIdentifier::prepareWrite()
1123 {
1124     if (m_index) {
1125         const QualifiedIdentifierPrivate<false>* oldCc = cd;
1126         dd = new QualifiedIdentifierPrivate<true>;
1127         dd->m_explicitlyGlobal = oldCc->m_explicitlyGlobal;
1128         dd->m_isExpression = oldCc->m_isExpression;
1129         dd->m_hash = oldCc->m_hash;
1130 
1131         dd->copyListsFrom(*oldCc);
1132         m_index = 0;
1133     }
1134 
1135     dd->clearHash();
1136 }
1137 
hash() const1138 uint IndexedTypeIdentifier::hash() const
1139 {
1140     quint32 bitfields = static_cast<quint32>(m_isConstant)
1141                         | (m_isReference << 1)
1142                         | (m_isRValue << 2)
1143                         | (m_isVolatile << 3)
1144                         | (m_pointerDepth << 4)
1145                         | (m_pointerConstMask << 9);
1146     return KDevHash() << m_identifier.index() << bitfields;
1147 }
1148 
operator ==(const IndexedTypeIdentifier & rhs) const1149 bool IndexedTypeIdentifier::operator==(const IndexedTypeIdentifier& rhs) const
1150 {
1151     return m_identifier == rhs.m_identifier
1152            && m_isConstant == rhs.m_isConstant
1153            && m_isReference == rhs.m_isReference
1154            && m_isRValue == rhs.m_isRValue
1155            && m_isVolatile == rhs.m_isVolatile
1156            && m_pointerConstMask == rhs.m_pointerConstMask
1157            && m_pointerDepth == rhs.m_pointerDepth;
1158 }
1159 
operator !=(const IndexedTypeIdentifier & rhs) const1160 bool IndexedTypeIdentifier::operator!=(const IndexedTypeIdentifier& rhs) const
1161 {
1162     return !operator==(rhs);
1163 }
1164 
isReference() const1165 bool IndexedTypeIdentifier::isReference() const
1166 {
1167     return m_isReference;
1168 }
1169 
setIsReference(bool isRef)1170 void IndexedTypeIdentifier::setIsReference(bool isRef)
1171 {
1172     m_isReference = isRef;
1173 }
1174 
isRValue() const1175 bool IndexedTypeIdentifier::isRValue() const
1176 {
1177     return m_isRValue;
1178 }
1179 
setIsRValue(bool isRVal)1180 void IndexedTypeIdentifier::setIsRValue(bool isRVal)
1181 {
1182     m_isRValue = isRVal;
1183 }
1184 
isConstant() const1185 bool IndexedTypeIdentifier::isConstant() const
1186 {
1187     return m_isConstant;
1188 }
1189 
setIsConstant(bool isConst)1190 void IndexedTypeIdentifier::setIsConstant(bool isConst)
1191 {
1192     m_isConstant = isConst;
1193 }
1194 
isVolatile() const1195 bool IndexedTypeIdentifier::isVolatile() const
1196 {
1197     return m_isVolatile;
1198 }
1199 
setIsVolatile(bool isVolatile)1200 void IndexedTypeIdentifier::setIsVolatile(bool isVolatile)
1201 {
1202     m_isVolatile = isVolatile;
1203 }
1204 
pointerDepth() const1205 int IndexedTypeIdentifier::pointerDepth() const
1206 {
1207     return m_pointerDepth;
1208 }
1209 
setPointerDepth(int depth)1210 void IndexedTypeIdentifier::setPointerDepth(int depth)
1211 {
1212     Q_ASSERT(depth <= 23 && depth >= 0);
1213     ///Clear the mask in removed fields
1214     for (int s = depth; s < ( int )m_pointerDepth; ++s)
1215         setIsConstPointer(s, false);
1216 
1217     m_pointerDepth = depth;
1218 }
1219 
isConstPointer(int depthNumber) const1220 bool IndexedTypeIdentifier::isConstPointer(int depthNumber) const
1221 {
1222     return m_pointerConstMask & (1 << depthNumber);
1223 }
1224 
setIsConstPointer(int depthNumber,bool constant)1225 void IndexedTypeIdentifier::setIsConstPointer(int depthNumber, bool constant)
1226 {
1227     if (constant)
1228         m_pointerConstMask |= (1 << depthNumber);
1229     else
1230         m_pointerConstMask &= (~(1 << depthNumber));
1231 }
1232 
toString(IdentifierStringFormattingOptions options) const1233 QString IndexedTypeIdentifier::toString(IdentifierStringFormattingOptions options) const
1234 {
1235     QString ret;
1236     if (isConstant())
1237         ret += QLatin1String("const ");
1238     if (isVolatile())
1239         ret += QLatin1String("volatile ");
1240 
1241     ret += m_identifier.identifier().toString(options);
1242     for (int a = 0; a < pointerDepth(); ++a) {
1243         ret += QLatin1Char('*');
1244         if (isConstPointer(a))
1245             ret += QLatin1String("const");
1246     }
1247 
1248     if (isRValue())
1249         ret += QLatin1String("&&");
1250     else if (isReference())
1251         ret += QLatin1Char('&');
1252     return ret;
1253 }
1254 
IndexedTypeIdentifier(const IndexedQualifiedIdentifier & identifier)1255 IndexedTypeIdentifier::IndexedTypeIdentifier(const IndexedQualifiedIdentifier& identifier)
1256     : m_identifier(identifier)
1257     , m_isConstant(false)
1258     , m_isReference(false)
1259     , m_isRValue(false)
1260     , m_isVolatile(false)
1261     , m_pointerDepth(0)
1262     , m_pointerConstMask(0)
1263 { }
1264 
IndexedTypeIdentifier(const QString & identifier,bool isExpression)1265 IndexedTypeIdentifier::IndexedTypeIdentifier(const QString& identifier, bool isExpression)
1266     : m_identifier(QualifiedIdentifier(identifier, isExpression))
1267     , m_isConstant(false)
1268     , m_isReference(false)
1269     , m_isRValue(false)
1270     , m_isVolatile(false)
1271     , m_pointerDepth(0)
1272     , m_pointerConstMask(0)
1273 { }
1274 
IndexedIdentifier()1275 IndexedIdentifier::IndexedIdentifier()
1276     : m_index(emptyConstantIdentifierPrivateIndex())
1277 {
1278     if (shouldDoDUChainReferenceCounting(this)) {
1279         QMutexLocker lock(identifierRepository()->mutex());
1280         increase(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1281     }
1282 }
1283 
IndexedIdentifier(const Identifier & id)1284 IndexedIdentifier::IndexedIdentifier(const Identifier& id)
1285     : m_index(id.index())
1286 {
1287     if (shouldDoDUChainReferenceCounting(this)) {
1288         QMutexLocker lock(identifierRepository()->mutex());
1289         increase(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1290     }
1291 }
1292 
IndexedIdentifier(const IndexedIdentifier & rhs)1293 IndexedIdentifier::IndexedIdentifier(const IndexedIdentifier& rhs)
1294     : m_index(rhs.m_index)
1295 {
1296     if (shouldDoDUChainReferenceCounting(this)) {
1297         QMutexLocker lock(identifierRepository()->mutex());
1298         increase(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1299     }
1300 }
1301 
IndexedIdentifier(IndexedIdentifier && rhs)1302 IndexedIdentifier::IndexedIdentifier(IndexedIdentifier&& rhs) Q_DECL_NOEXCEPT
1303     : m_index(rhs.m_index)
1304 {
1305     rhs.m_index = emptyConstantIdentifierPrivateIndex();
1306 }
1307 
~IndexedIdentifier()1308 IndexedIdentifier::~IndexedIdentifier()
1309 {
1310     if (shouldDoDUChainReferenceCounting(this)) {
1311         QMutexLocker lock(identifierRepository()->mutex());
1312         decrease(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1313     }
1314 }
1315 
operator =(const Identifier & id)1316 IndexedIdentifier& IndexedIdentifier::operator=(const Identifier& id)
1317 {
1318     if (shouldDoDUChainReferenceCounting(this)) {
1319         QMutexLocker lock(identifierRepository()->mutex());
1320         decrease(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1321     }
1322 
1323     m_index = id.index();
1324 
1325     if (shouldDoDUChainReferenceCounting(this)) {
1326         QMutexLocker lock(identifierRepository()->mutex());
1327         increase(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1328     }
1329     return *this;
1330 }
1331 
operator =(IndexedIdentifier && rhs)1332 IndexedIdentifier& IndexedIdentifier::operator=(IndexedIdentifier&& rhs) Q_DECL_NOEXCEPT
1333 {
1334     if (shouldDoDUChainReferenceCounting(this)) {
1335         QMutexLocker lock(identifierRepository()->mutex());
1336         ifDebug(qCDebug(LANGUAGE) << "decreasing"; )
1337 
1338         decrease(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1339     } else if (shouldDoDUChainReferenceCounting(&rhs)) {
1340         QMutexLocker lock(identifierRepository()->mutex());
1341         ifDebug(qCDebug(LANGUAGE) << "decreasing"; )
1342 
1343         decrease(identifierRepository()->dynamicItemFromIndexSimple(rhs.m_index)->m_refCount, rhs.m_index);
1344     }
1345 
1346     m_index = rhs.m_index;
1347     rhs.m_index = emptyConstantIdentifierPrivateIndex();
1348 
1349     if (shouldDoDUChainReferenceCounting(this) && !(shouldDoDUChainReferenceCounting(&rhs))) {
1350         QMutexLocker lock(identifierRepository()->mutex());
1351         ifDebug(qCDebug(LANGUAGE) << "increasing"; )
1352 
1353         increase(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1354     }
1355 
1356     return *this;
1357 }
1358 
operator =(const IndexedIdentifier & id)1359 IndexedIdentifier& IndexedIdentifier::operator=(const IndexedIdentifier& id)
1360 {
1361     if (shouldDoDUChainReferenceCounting(this)) {
1362         QMutexLocker lock(identifierRepository()->mutex());
1363         decrease(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1364     }
1365 
1366     m_index = id.m_index;
1367 
1368     if (shouldDoDUChainReferenceCounting(this)) {
1369         QMutexLocker lock(identifierRepository()->mutex());
1370         increase(identifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1371     }
1372     return *this;
1373 }
1374 
operator ==(const IndexedIdentifier & rhs) const1375 bool IndexedIdentifier::operator==(const IndexedIdentifier& rhs) const
1376 {
1377     return m_index == rhs.m_index;
1378 }
1379 
operator !=(const IndexedIdentifier & rhs) const1380 bool IndexedIdentifier::operator!=(const IndexedIdentifier& rhs) const
1381 {
1382     return m_index != rhs.m_index;
1383 }
1384 
operator ==(const Identifier & id) const1385 bool IndexedIdentifier::operator==(const Identifier& id) const
1386 {
1387     return m_index == id.index();
1388 }
1389 
identifier() const1390 Identifier IndexedIdentifier::identifier() const
1391 {
1392     return Identifier(m_index);
1393 }
1394 
operator Identifier() const1395 IndexedIdentifier::operator Identifier() const
1396 {
1397     return Identifier(m_index);
1398 }
1399 
isValid() const1400 bool IndexedQualifiedIdentifier::isValid() const
1401 {
1402     return m_index != emptyConstantQualifiedIdentifierPrivateIndex();
1403 }
1404 
isEmpty() const1405 bool IndexedQualifiedIdentifier::isEmpty() const
1406 {
1407     return m_index == emptyConstantQualifiedIdentifierPrivateIndex();
1408 }
1409 
1410 int cnt = 0;
1411 
identifier() const1412 IndexedQualifiedIdentifier IndexedTypeIdentifier::identifier() const
1413 {
1414     return m_identifier;
1415 }
1416 
setIdentifier(const IndexedQualifiedIdentifier & id)1417 void IndexedTypeIdentifier::setIdentifier(const IndexedQualifiedIdentifier& id)
1418 {
1419     m_identifier = id;
1420 }
1421 
IndexedQualifiedIdentifier()1422 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier()
1423     : m_index(emptyConstantQualifiedIdentifierPrivateIndex())
1424 {
1425     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ")" << identifier().toString() << m_index; )
1426 
1427     if (shouldDoDUChainReferenceCounting(this)) {
1428         ifDebug(qCDebug(LANGUAGE) << "increasing"; )
1429 
1430         //qCDebug(LANGUAGE) << "(" << ++cnt << ")" << this << identifier().toString() << "inc" << index;
1431         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1432         increase(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1433     }
1434 }
1435 
IndexedQualifiedIdentifier(const QualifiedIdentifier & id)1436 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(const QualifiedIdentifier& id)
1437     : m_index(id.index())
1438 {
1439     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ")" << identifier().toString() << m_index; )
1440 
1441     if (shouldDoDUChainReferenceCounting(this)) {
1442         ifDebug(qCDebug(LANGUAGE) << "increasing"; )
1443         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1444         increase(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1445     }
1446 }
1447 
IndexedQualifiedIdentifier(const IndexedQualifiedIdentifier & id)1448 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(const IndexedQualifiedIdentifier& id)
1449     : m_index(id.m_index)
1450 {
1451     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ")" << identifier().toString() << m_index; )
1452 
1453     if (shouldDoDUChainReferenceCounting(this)) {
1454         ifDebug(qCDebug(LANGUAGE) << "increasing"; )
1455 
1456         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1457         increase(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1458     }
1459 }
1460 
IndexedQualifiedIdentifier(IndexedQualifiedIdentifier && rhs)1461 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(IndexedQualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT
1462     : m_index(rhs.m_index)
1463 {
1464     rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex();
1465 }
1466 
operator =(const QualifiedIdentifier & id)1467 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(const QualifiedIdentifier& id)
1468 {
1469     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ")" << identifier().toString() << m_index; )
1470 
1471     if (shouldDoDUChainReferenceCounting(this)) {
1472         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1473 
1474         ifDebug(qCDebug(LANGUAGE) << "decreasing"; )
1475         decrease(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1476 
1477         m_index = id.index();
1478 
1479         ifDebug(qCDebug(LANGUAGE) << m_index << "increasing"; )
1480         increase(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1481     } else {
1482         m_index = id.index();
1483     }
1484 
1485     return *this;
1486 }
1487 
operator =(const IndexedQualifiedIdentifier & rhs)1488 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(const IndexedQualifiedIdentifier& rhs)
1489 {
1490     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ")" << identifier().toString() << m_index; )
1491 
1492     if (shouldDoDUChainReferenceCounting(this)) {
1493         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1494         ifDebug(qCDebug(LANGUAGE) << "decreasing"; )
1495 
1496         decrease(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1497 
1498         m_index = rhs.m_index;
1499 
1500         ifDebug(qCDebug(LANGUAGE) << m_index << "increasing"; )
1501         increase(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1502     } else {
1503         m_index = rhs.m_index;
1504     }
1505 
1506     return *this;
1507 }
1508 
operator =(IndexedQualifiedIdentifier && rhs)1509 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(IndexedQualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT
1510 {
1511     if (shouldDoDUChainReferenceCounting(this)) {
1512         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1513         ifDebug(qCDebug(LANGUAGE) << "decreasing"; )
1514 
1515         decrease(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1516     } else if (shouldDoDUChainReferenceCounting(&rhs)) {
1517         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1518         ifDebug(qCDebug(LANGUAGE) << "decreasing"; )
1519 
1520         decrease(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(rhs.m_index)->m_refCount, rhs.m_index);
1521     }
1522 
1523     m_index = rhs.m_index;
1524     rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex();
1525 
1526     if (shouldDoDUChainReferenceCounting(this) && !(shouldDoDUChainReferenceCounting(&rhs))) {
1527         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1528         ifDebug(qCDebug(LANGUAGE) << "increasing"; )
1529 
1530         increase(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1531     }
1532 
1533     return *this;
1534 }
1535 
~IndexedQualifiedIdentifier()1536 IndexedQualifiedIdentifier::~IndexedQualifiedIdentifier()
1537 {
1538     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ")" << identifier().toString() << index; )
1539     if (shouldDoDUChainReferenceCounting(this)) {
1540         ifDebug(qCDebug(LANGUAGE) << index << "decreasing"; )
1541         QMutexLocker lock(qualifiedidentifierRepository()->mutex());
1542         decrease(qualifiedidentifierRepository()->dynamicItemFromIndexSimple(m_index)->m_refCount, m_index);
1543     }
1544 }
1545 
operator ==(const IndexedQualifiedIdentifier & rhs) const1546 bool IndexedQualifiedIdentifier::operator==(const IndexedQualifiedIdentifier& rhs) const
1547 {
1548     return m_index == rhs.m_index;
1549 }
1550 
operator ==(const QualifiedIdentifier & id) const1551 bool IndexedQualifiedIdentifier::operator==(const QualifiedIdentifier& id) const
1552 {
1553     return m_index == id.index();
1554 }
1555 
identifier() const1556 QualifiedIdentifier IndexedQualifiedIdentifier::identifier() const
1557 {
1558     return QualifiedIdentifier(m_index);
1559 }
1560 
operator QualifiedIdentifier() const1561 IndexedQualifiedIdentifier::operator QualifiedIdentifier() const
1562 {
1563     return QualifiedIdentifier(m_index);
1564 }
1565 
initIdentifierRepository()1566 void initIdentifierRepository()
1567 {
1568     emptyConstantIdentifierPrivateIndex();
1569     emptyConstantIdentifierPrivate();
1570     emptyConstantQualifiedIdentifierPrivateIndex();
1571     emptyConstantQualifiedIdentifierPrivate();
1572 }
1573 }
1574 
operator <<(QDebug s,const KDevelop::Identifier & identifier)1575 QDebug operator<<(QDebug s, const KDevelop::Identifier& identifier)
1576 {
1577     s.nospace() << identifier.toString();
1578     return s.space();
1579 }
1580 
operator <<(QDebug s,const KDevelop::QualifiedIdentifier & identifier)1581 QDebug operator<<(QDebug s, const KDevelop::QualifiedIdentifier& identifier)
1582 {
1583     s.nospace() << identifier.toString();
1584     return s.space();
1585 }
1586