File indexing completed on 2024-05-12 04:38:02
0001 /* 0002 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> 0003 SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "identifier.h" 0009 0010 #include <QHash> 0011 #include "stringhelpers.h" 0012 #include "appendedlist_static.h" 0013 #include "serialization/itemrepository.h" 0014 #include "serialization/itemrepositoryreferencecounting.h" 0015 #include <serialization/repositorymanager.h> 0016 #include "util/kdevhash.h" 0017 #include <debug.h> 0018 0019 #include <serialization/indexedstring.h> 0020 #include <utility> 0021 0022 #define ifDebug(x) void() 0023 0024 namespace KDevelop { 0025 template <bool dynamic = false> 0026 class IdentifierPrivate 0027 { 0028 public: 0029 IdentifierPrivate() 0030 { 0031 } 0032 0033 template <bool rhsDynamic> 0034 explicit IdentifierPrivate(const IdentifierPrivate<rhsDynamic>& rhs) 0035 : m_unique(rhs.m_unique) 0036 , m_identifier(rhs.m_identifier) 0037 , m_refCount(0) 0038 , m_hash(rhs.m_hash) 0039 { 0040 copyListsFrom(rhs); 0041 } 0042 0043 ~IdentifierPrivate() 0044 { 0045 templateIdentifiersList.free(const_cast<IndexedTypeIdentifier*>(templateIdentifiers())); 0046 } 0047 0048 IdentifierPrivate& operator=(const IdentifierPrivate& rhs) = delete; 0049 0050 //Flags the stored hash-value invalid 0051 void clearHash() 0052 { 0053 //This is always called on an object private to an Identifier, so there is no threading-problem. 0054 Q_ASSERT(dynamic); 0055 m_hash = 0; 0056 } 0057 0058 uint hash() const 0059 { 0060 // Since this only needs reading and the data needs not to be private, this may be called by 0061 // multiple threads simultaneously, so computeHash() must be thread-safe. 0062 if (!m_hash && dynamic) 0063 computeHash(); 0064 return m_hash; 0065 } 0066 0067 int m_unique = 0; 0068 IndexedString m_identifier; 0069 uint m_refCount = 0; 0070 0071 START_APPENDED_LISTS_STATIC(IdentifierPrivate) 0072 0073 APPENDED_LIST_FIRST_STATIC(IndexedTypeIdentifier, templateIdentifiers) 0074 0075 END_APPENDED_LISTS_STATIC(templateIdentifiers) 0076 0077 uint itemSize() const 0078 { 0079 return sizeof(IdentifierPrivate<false> ) + lastOffsetBehind(); 0080 } 0081 0082 void computeHash() const 0083 { 0084 Q_ASSERT(dynamic); 0085 //this must stay thread-safe(may be called by multiple threads at a time) 0086 //The thread-safety is given because all threads will have the same result, and it will only be written once at the end. 0087 KDevHash kdevhash; 0088 kdevhash << m_identifier.hash() << m_unique; 0089 FOREACH_FUNCTION_STATIC(const IndexedTypeIdentifier &templateIdentifier, templateIdentifiers) 0090 kdevhash << templateIdentifier.hash(); 0091 m_hash = kdevhash; 0092 } 0093 0094 mutable uint m_hash = 0; 0095 }; 0096 0097 using DynamicIdentifierPrivate = IdentifierPrivate<true>; 0098 using ConstantIdentifierPrivate = IdentifierPrivate<false>; 0099 0100 struct IdentifierItemRequest 0101 { 0102 IdentifierItemRequest(const DynamicIdentifierPrivate& identifier) 0103 : m_identifier(identifier) 0104 { 0105 identifier.hash(); //Make sure the hash is valid by calling this 0106 } 0107 0108 enum { 0109 AverageSize = sizeof(IdentifierPrivate<false> ) + 4 0110 }; 0111 0112 //Should return the hash-value associated with this request(For example the hash of a string) 0113 uint hash() const 0114 { 0115 return m_identifier.hash(); 0116 } 0117 0118 //Should return the size of an item created with createItem 0119 uint itemSize() const 0120 { 0121 return m_identifier.itemSize(); 0122 } 0123 //Should create an item where the information of the requested item is permanently stored. The pointer 0124 //@param item equals an allocated range with the size of itemSize(). 0125 void createItem(ConstantIdentifierPrivate* item) const 0126 { 0127 new (item) ConstantIdentifierPrivate(m_identifier); 0128 } 0129 0130 static bool persistent(const ConstantIdentifierPrivate* item) 0131 { 0132 return ( bool )item->m_refCount; 0133 } 0134 0135 static void destroy(ConstantIdentifierPrivate* item, AbstractItemRepository&) 0136 { 0137 item->~ConstantIdentifierPrivate(); 0138 } 0139 0140 //Should return whether the here requested item equals the given item 0141 bool equals(const ConstantIdentifierPrivate* item) const 0142 { 0143 return item->m_hash == m_identifier.m_hash 0144 && item->m_unique == m_identifier.m_unique 0145 && item->m_identifier == m_identifier.m_identifier 0146 && m_identifier.listsEqual(*item); 0147 } 0148 0149 const DynamicIdentifierPrivate& m_identifier; 0150 }; 0151 0152 using IdentifierRepository = ItemRepository<ConstantIdentifierPrivate, IdentifierItemRequest, true, QRecursiveMutex>; 0153 using IdentifierRepositoryManager = RepositoryManager<IdentifierRepository, false>; 0154 0155 template <> 0156 class ItemRepositoryFor<IndexedIdentifier> 0157 { 0158 friend struct LockedItemRepository; 0159 static IdentifierRepository& repo() 0160 { 0161 static QRecursiveMutex mutex; 0162 static IdentifierRepositoryManager manager(QStringLiteral("Identifier Repository"), &mutex); 0163 return *manager.repository(); 0164 } 0165 0166 public: 0167 static auto* mutex() { return repo().mutex(); } 0168 }; 0169 0170 static uint emptyConstantIdentifierPrivateIndex() 0171 { 0172 static const uint index = LockedItemRepository::write<IndexedIdentifier>( 0173 [](IdentifierRepository& repo) { return repo.index(DynamicIdentifierPrivate()); }); 0174 return index; 0175 } 0176 0177 static const ConstantIdentifierPrivate* emptyConstantIdentifierPrivate() 0178 { 0179 static const ConstantIdentifierPrivate item; 0180 return &item; 0181 } 0182 0183 bool IndexedIdentifier::isEmpty() const 0184 { 0185 return m_index == emptyConstantIdentifierPrivateIndex(); 0186 } 0187 0188 /** 0189 * Before something is modified in QualifiedIdentifierPrivate, it must be made sure that 0190 * it is private to the QualifiedIdentifier it is used in(@see QualifiedIdentifier::prepareWrite) 0191 */ 0192 template <bool dynamic> 0193 class QualifiedIdentifierPrivate 0194 { 0195 public: 0196 QualifiedIdentifierPrivate() 0197 : m_explicitlyGlobal(false) 0198 , m_isExpression(false) 0199 0200 { 0201 } 0202 0203 template <bool rhsDynamic> 0204 explicit QualifiedIdentifierPrivate(const QualifiedIdentifierPrivate<rhsDynamic>& rhs) 0205 : m_explicitlyGlobal(rhs.m_explicitlyGlobal) 0206 , m_isExpression(rhs.m_isExpression) 0207 , m_hash(rhs.m_hash) 0208 , m_refCount(0) 0209 { 0210 copyListsFrom(rhs); 0211 } 0212 0213 ~QualifiedIdentifierPrivate() 0214 { 0215 identifiersList.free(const_cast<IndexedIdentifier*>(identifiers())); 0216 } 0217 0218 QualifiedIdentifierPrivate& operator=(const QualifiedIdentifierPrivate& rhs) = delete; 0219 0220 bool m_explicitlyGlobal : 1; 0221 bool m_isExpression : 1; 0222 mutable uint m_hash = 0; 0223 uint m_refCount = 0; 0224 0225 START_APPENDED_LISTS_STATIC(QualifiedIdentifierPrivate) 0226 0227 APPENDED_LIST_FIRST_STATIC(IndexedIdentifier, identifiers) 0228 0229 END_APPENDED_LISTS_STATIC(identifiers) 0230 0231 uint itemSize() const 0232 { 0233 return sizeof(QualifiedIdentifierPrivate<false> ) + lastOffsetBehind(); 0234 } 0235 0236 //Constructs m_identifiers 0237 void splitIdentifiers(QStringView str, int start) 0238 { 0239 Q_ASSERT(dynamic); 0240 uint currentStart = start; 0241 0242 while (currentStart < ( uint )str.length()) { 0243 identifiersList.append(IndexedIdentifier(Identifier(str, currentStart, ¤tStart))); 0244 while (currentStart < ( uint )str.length() && (str[currentStart] == QLatin1Char(' '))) 0245 ++currentStart; 0246 currentStart += 2; //Skip "::" 0247 } 0248 } 0249 0250 inline void clearHash() const 0251 { 0252 m_hash = 0; 0253 } 0254 0255 uint hash() const 0256 { 0257 if (m_hash == 0) { 0258 KDevHash hash; 0259 0260 quint32 bitfields = static_cast<quint32>(m_explicitlyGlobal) 0261 | (m_isExpression << 1); 0262 hash << bitfields << identifiersSize(); 0263 FOREACH_FUNCTION_STATIC(const IndexedIdentifier &identifier, identifiers) { 0264 hash << identifier.index(); 0265 } 0266 0267 m_hash = hash; 0268 } 0269 return m_hash; 0270 } 0271 }; 0272 0273 using DynamicQualifiedIdentifierPrivate = QualifiedIdentifierPrivate<true>; 0274 using ConstantQualifiedIdentifierPrivate = QualifiedIdentifierPrivate<false>; 0275 0276 struct QualifiedIdentifierItemRequest 0277 { 0278 QualifiedIdentifierItemRequest(const DynamicQualifiedIdentifierPrivate& identifier) 0279 : m_identifier(identifier) 0280 { 0281 identifier.hash(); //Make sure the hash is valid by calling this 0282 } 0283 0284 enum { 0285 AverageSize = sizeof(QualifiedIdentifierPrivate<false> ) + 8 0286 }; 0287 0288 //Should return the hash-value associated with this request(For example the hash of a string) 0289 uint hash() const 0290 { 0291 return m_identifier.hash(); 0292 } 0293 0294 //Should return the size of an item created with createItem 0295 uint itemSize() const 0296 { 0297 return m_identifier.itemSize(); 0298 } 0299 0300 /** 0301 * Should create an item where the information of the requested item is permanently stored. The pointer 0302 * @param item equals an allocated range with the size of itemSize(). 0303 */ 0304 void createItem(ConstantQualifiedIdentifierPrivate* item) const 0305 { 0306 Q_ASSERT(shouldDoDUChainReferenceCounting(item)); 0307 Q_ASSERT(shouldDoDUChainReferenceCounting(reinterpret_cast<char*>(item) + (itemSize() - 1))); 0308 new (item) ConstantQualifiedIdentifierPrivate(m_identifier); 0309 } 0310 0311 static bool persistent(const ConstantQualifiedIdentifierPrivate* item) 0312 { 0313 return ( bool )item->m_refCount; 0314 } 0315 0316 static void destroy(ConstantQualifiedIdentifierPrivate* item, AbstractItemRepository&) 0317 { 0318 Q_ASSERT(shouldDoDUChainReferenceCounting(item)); 0319 item->~ConstantQualifiedIdentifierPrivate(); 0320 } 0321 0322 //Should return whether the here requested item equals the given item 0323 bool equals(const ConstantQualifiedIdentifierPrivate* item) const 0324 { 0325 return item->m_explicitlyGlobal == m_identifier.m_explicitlyGlobal 0326 && item->m_isExpression == m_identifier.m_isExpression 0327 && item->m_hash == m_identifier.m_hash 0328 && m_identifier.listsEqual(*item); 0329 } 0330 0331 const DynamicQualifiedIdentifierPrivate& m_identifier; 0332 }; 0333 0334 using QualifiedIdentifierRepository 0335 = ItemRepository<ConstantQualifiedIdentifierPrivate, QualifiedIdentifierItemRequest, true, QRecursiveMutex>; 0336 using QualifiedIdentifierRepositoryManager = RepositoryManager<QualifiedIdentifierRepository, false>; 0337 0338 template <> 0339 class ItemRepositoryFor<IndexedQualifiedIdentifier> 0340 { 0341 friend struct LockedItemRepository; 0342 static QualifiedIdentifierRepository& repo() 0343 { 0344 static QualifiedIdentifierRepositoryManager manager(QStringLiteral("Qualified Identifier Repository"), 0345 ItemRepositoryFor<IndexedIdentifier>::mutex()); 0346 return *manager.repository(); 0347 } 0348 }; 0349 0350 static uint emptyConstantQualifiedIdentifierPrivateIndex() 0351 { 0352 static const uint index = LockedItemRepository::write<IndexedQualifiedIdentifier>( 0353 [](QualifiedIdentifierRepository& repo) { return repo.index(DynamicQualifiedIdentifierPrivate()); }); 0354 return index; 0355 } 0356 0357 static const ConstantQualifiedIdentifierPrivate* emptyConstantQualifiedIdentifierPrivate() 0358 { 0359 static const ConstantQualifiedIdentifierPrivate item; 0360 return &item; 0361 } 0362 0363 Identifier::Identifier(const Identifier& rhs) 0364 { 0365 rhs.makeConstant(); 0366 cd = rhs.cd; 0367 m_index = rhs.m_index; 0368 } 0369 0370 Identifier::Identifier(uint index) 0371 : m_index(index) 0372 { 0373 Q_ASSERT(m_index); 0374 cd = LockedItemRepository::read<IndexedIdentifier>( 0375 [index](const IdentifierRepository& repo) { return repo.itemFromIndex(index); }); 0376 } 0377 0378 Identifier::Identifier(const IndexedString& str) 0379 { 0380 if (str.isEmpty()) { 0381 m_index = emptyConstantIdentifierPrivateIndex(); 0382 cd = emptyConstantIdentifierPrivate(); 0383 } else { 0384 m_index = 0; 0385 dd = new IdentifierPrivate<true>; 0386 dd->m_identifier = str; 0387 } 0388 } 0389 0390 Identifier::Identifier(QStringView id, uint start, uint* takenRange) 0391 { 0392 if (id.isEmpty()) { 0393 m_index = emptyConstantIdentifierPrivateIndex(); 0394 cd = emptyConstantIdentifierPrivate(); 0395 return; 0396 } 0397 0398 m_index = 0; 0399 dd = new IdentifierPrivate<true>; 0400 0401 ///Extract template-parameters 0402 ParamIterator paramIt(u"<>:", id, start); 0403 dd->m_identifier = IndexedString(paramIt.prefix().trimmed()); 0404 while (paramIt) { 0405 appendTemplateIdentifier(IndexedTypeIdentifier(IndexedQualifiedIdentifier(QualifiedIdentifier(*paramIt)))); 0406 ++paramIt; 0407 } 0408 0409 if (takenRange) 0410 *takenRange = paramIt.position(); 0411 } 0412 0413 Identifier::Identifier() 0414 : m_index(emptyConstantIdentifierPrivateIndex()) 0415 , cd(emptyConstantIdentifierPrivate()) 0416 { 0417 } 0418 0419 Identifier& Identifier::operator=(const Identifier& rhs) 0420 { 0421 if (dd == rhs.dd && cd == rhs.cd) 0422 return *this; 0423 0424 if (!m_index) 0425 delete dd; 0426 dd = nullptr; 0427 0428 rhs.makeConstant(); 0429 cd = rhs.cd; 0430 m_index = rhs.m_index; 0431 Q_ASSERT(cd); 0432 return *this; 0433 } 0434 0435 Identifier::Identifier(Identifier&& rhs) Q_DECL_NOEXCEPT 0436 : m_index(rhs.m_index) 0437 { 0438 if (m_index) { 0439 cd = rhs.cd; 0440 } else { 0441 dd = rhs.dd; 0442 } 0443 rhs.cd = emptyConstantIdentifierPrivate(); 0444 rhs.m_index = emptyConstantIdentifierPrivateIndex(); 0445 } 0446 0447 Identifier& Identifier::operator=(Identifier&& rhs) Q_DECL_NOEXCEPT 0448 { 0449 if (dd == rhs.dd && cd == rhs.cd) 0450 return *this; 0451 0452 if (!m_index) { 0453 delete dd; 0454 dd = nullptr; 0455 } 0456 0457 m_index = rhs.m_index; 0458 0459 if (m_index) { 0460 cd = rhs.cd; 0461 } else { 0462 dd = rhs.dd; 0463 } 0464 rhs.cd = emptyConstantIdentifierPrivate(); 0465 rhs.m_index = emptyConstantIdentifierPrivateIndex(); 0466 0467 return *this; 0468 } 0469 0470 Identifier::~Identifier() 0471 { 0472 if (!m_index) 0473 delete dd; 0474 } 0475 0476 bool Identifier::nameEquals(const Identifier& rhs) const 0477 { 0478 return identifier() == rhs.identifier(); 0479 } 0480 0481 uint Identifier::hash() const 0482 { 0483 if (!m_index) 0484 return dd->hash(); 0485 else 0486 return cd->hash(); 0487 } 0488 0489 bool Identifier::isEmpty() const 0490 { 0491 if (!m_index) 0492 return dd->m_identifier.isEmpty() && dd->m_unique == 0 && dd->templateIdentifiersSize() == 0; 0493 else 0494 return cd->m_identifier.isEmpty() && cd->m_unique == 0 && cd->templateIdentifiersSize() == 0; 0495 } 0496 0497 Identifier Identifier::unique(int token) 0498 { 0499 Identifier ret; 0500 ret.setUnique(token); 0501 return ret; 0502 } 0503 0504 bool Identifier::isUnique() const 0505 { 0506 if (!m_index) 0507 return dd->m_unique; 0508 else 0509 return cd->m_unique; 0510 } 0511 0512 int Identifier::uniqueToken() const 0513 { 0514 if (!m_index) 0515 return dd->m_unique; 0516 else 0517 return cd->m_unique; 0518 } 0519 0520 void Identifier::setUnique(int token) 0521 { 0522 if (token != uniqueToken()) { 0523 prepareWrite(); 0524 dd->m_unique = token; 0525 } 0526 } 0527 0528 const IndexedString Identifier::identifier() const 0529 { 0530 if (!m_index) 0531 return dd->m_identifier; 0532 else 0533 return cd->m_identifier; 0534 } 0535 0536 void Identifier::setIdentifier(QStringView identifier) 0537 { 0538 IndexedString id(identifier); 0539 if (id != this->identifier()) { 0540 prepareWrite(); 0541 dd->m_identifier = std::move(id); 0542 } 0543 } 0544 0545 void Identifier::setIdentifier(const IndexedString& identifier) 0546 { 0547 if (identifier != this->identifier()) { 0548 prepareWrite(); 0549 dd->m_identifier = identifier; 0550 } 0551 } 0552 0553 IndexedTypeIdentifier Identifier::templateIdentifier(int num) const 0554 { 0555 if (!m_index) 0556 return dd->templateIdentifiers()[num]; 0557 else 0558 return cd->templateIdentifiers()[num]; 0559 } 0560 0561 uint Identifier::templateIdentifiersCount() const 0562 { 0563 if (!m_index) 0564 return dd->templateIdentifiersSize(); 0565 else 0566 return cd->templateIdentifiersSize(); 0567 } 0568 0569 void Identifier::appendTemplateIdentifier(const IndexedTypeIdentifier& identifier) 0570 { 0571 prepareWrite(); 0572 dd->templateIdentifiersList.append(identifier); 0573 } 0574 0575 void Identifier::clearTemplateIdentifiers() 0576 { 0577 prepareWrite(); 0578 dd->templateIdentifiersList.clear(); 0579 } 0580 0581 uint Identifier::index() const 0582 { 0583 makeConstant(); 0584 Q_ASSERT(m_index); 0585 return m_index; 0586 } 0587 0588 bool Identifier::inRepository() const 0589 { 0590 return m_index; 0591 } 0592 0593 void Identifier::setTemplateIdentifiers(const QList<IndexedTypeIdentifier>& templateIdentifiers) 0594 { 0595 prepareWrite(); 0596 dd->templateIdentifiersList.clear(); 0597 for (const IndexedTypeIdentifier& id : templateIdentifiers) { 0598 dd->templateIdentifiersList.append(id); 0599 } 0600 } 0601 0602 QString Identifier::toString(IdentifierStringFormattingOptions options) const 0603 { 0604 QString ret = identifier().str(); 0605 0606 if (!options.testFlag(RemoveTemplateInformation) && templateIdentifiersCount()) { 0607 QStringList templateIds; 0608 templateIds.reserve(templateIdentifiersCount()); 0609 for (uint i = 0; i < templateIdentifiersCount(); ++i) { 0610 templateIds.append(templateIdentifier(i).toString(options)); 0611 } 0612 0613 ret += QLatin1String("< ") + templateIds.join(QLatin1String(", ")) + QLatin1String(" >"); 0614 } 0615 0616 return ret; 0617 } 0618 0619 bool Identifier::isReserved() const 0620 { 0621 const auto str = identifier().str(); 0622 constexpr QLatin1Char underscore{'_'}; 0623 return str.size() >= 2 && str[0] == underscore && (str[1] == underscore || str[1].isUpper()); 0624 } 0625 0626 bool Identifier::operator==(const Identifier& rhs) const 0627 { 0628 return index() == rhs.index(); 0629 } 0630 0631 bool Identifier::operator!=(const Identifier& rhs) const 0632 { 0633 return !operator==(rhs); 0634 } 0635 0636 uint QualifiedIdentifier::index() const 0637 { 0638 makeConstant(); 0639 Q_ASSERT(m_index); 0640 return m_index; 0641 } 0642 0643 void Identifier::makeConstant() const 0644 { 0645 if (m_index) 0646 return; 0647 0648 LockedItemRepository::write<IndexedIdentifier>( 0649 [&, request = IdentifierItemRequest(*dd)](IdentifierRepository& repo) { 0650 m_index = repo.index(request); 0651 delete dd; 0652 cd = repo.itemFromIndex(m_index); 0653 }); 0654 } 0655 0656 void Identifier::prepareWrite() 0657 { 0658 if (m_index) { 0659 const IdentifierPrivate<false>* oldCc = cd; 0660 dd = new IdentifierPrivate<true>; 0661 dd->m_hash = oldCc->m_hash; 0662 dd->m_unique = oldCc->m_unique; 0663 dd->m_identifier = oldCc->m_identifier; 0664 dd->copyListsFrom(*oldCc); 0665 m_index = 0; 0666 } 0667 0668 dd->clearHash(); 0669 } 0670 0671 bool QualifiedIdentifier::inRepository() const 0672 { 0673 if (m_index) 0674 return true; 0675 0676 return LockedItemRepository::read<IndexedQualifiedIdentifier>( 0677 [&, request = QualifiedIdentifierItemRequest(*dd)](const QualifiedIdentifierRepository& repo) { 0678 return static_cast<bool>(repo.findIndex(request)); 0679 }); 0680 } 0681 0682 QualifiedIdentifier::QualifiedIdentifier(uint index) 0683 : m_index(index) 0684 , cd(LockedItemRepository::read<IndexedQualifiedIdentifier>( 0685 [index](const QualifiedIdentifierRepository& repo) { return repo.itemFromIndex(index); })) 0686 { 0687 } 0688 0689 QualifiedIdentifier::QualifiedIdentifier(QStringView id, bool isExpression) 0690 { 0691 if (id.isEmpty()) { 0692 m_index = emptyConstantQualifiedIdentifierPrivateIndex(); 0693 cd = emptyConstantQualifiedIdentifierPrivate(); 0694 return; 0695 } 0696 0697 m_index = 0; 0698 dd = new DynamicQualifiedIdentifierPrivate; 0699 0700 if (isExpression) { 0701 setIsExpression(true); 0702 if (!id.isEmpty()) { 0703 //Prevent tokenization, since we may lose information there 0704 Identifier finishedId; 0705 finishedId.setIdentifier(id); 0706 push(finishedId); 0707 } 0708 } else { 0709 if (id.startsWith(QLatin1String("::"))) { 0710 dd->m_explicitlyGlobal = true; 0711 dd->splitIdentifiers(id, 2); 0712 } else { 0713 dd->m_explicitlyGlobal = false; 0714 dd->splitIdentifiers(id, 0); 0715 } 0716 } 0717 } 0718 0719 QualifiedIdentifier::QualifiedIdentifier(const Identifier& id) 0720 { 0721 if (id.isEmpty()) { 0722 m_index = emptyConstantQualifiedIdentifierPrivateIndex(); 0723 cd = emptyConstantQualifiedIdentifierPrivate(); 0724 return; 0725 } 0726 0727 m_index = 0; 0728 dd = new DynamicQualifiedIdentifierPrivate; 0729 0730 if (id.dd->m_identifier.str().isEmpty()) { 0731 dd->m_explicitlyGlobal = true; 0732 } else { 0733 dd->m_explicitlyGlobal = false; 0734 dd->identifiersList.append(IndexedIdentifier(id)); 0735 } 0736 } 0737 0738 QualifiedIdentifier::QualifiedIdentifier() 0739 : m_index(emptyConstantQualifiedIdentifierPrivateIndex()) 0740 , cd(emptyConstantQualifiedIdentifierPrivate()) 0741 { 0742 } 0743 0744 QualifiedIdentifier::QualifiedIdentifier(const QualifiedIdentifier& id) 0745 { 0746 if (id.m_index) { 0747 m_index = id.m_index; 0748 cd = id.cd; 0749 } else { 0750 m_index = 0; 0751 dd = new QualifiedIdentifierPrivate<true>(*id.dd); 0752 } 0753 } 0754 0755 QualifiedIdentifier::QualifiedIdentifier(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT 0756 : m_index(rhs.m_index) 0757 { 0758 if (m_index) { 0759 cd = rhs.cd; 0760 } else { 0761 dd = rhs.dd; 0762 } 0763 rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex(); 0764 rhs.cd = emptyConstantQualifiedIdentifierPrivate(); 0765 } 0766 0767 QualifiedIdentifier& QualifiedIdentifier::operator=(const QualifiedIdentifier& rhs) 0768 { 0769 if (dd == rhs.dd && cd == rhs.cd) 0770 return *this; 0771 0772 if (!m_index) 0773 delete dd; 0774 rhs.makeConstant(); 0775 cd = rhs.cd; 0776 m_index = rhs.m_index; 0777 return *this; 0778 } 0779 0780 QualifiedIdentifier& QualifiedIdentifier::operator=(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT 0781 { 0782 if (!m_index) 0783 delete dd; 0784 m_index = rhs.m_index; 0785 if (m_index) { 0786 cd = rhs.cd; 0787 } else { 0788 dd = rhs.dd; 0789 } 0790 rhs.cd = emptyConstantQualifiedIdentifierPrivate(); 0791 rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex(); 0792 return *this; 0793 } 0794 0795 QualifiedIdentifier::~QualifiedIdentifier() 0796 { 0797 if (!m_index) 0798 delete dd; 0799 } 0800 0801 QStringList QualifiedIdentifier::toStringList(IdentifierStringFormattingOptions options) const 0802 { 0803 QStringList ret; 0804 ret.reserve(explicitlyGlobal() + count()); 0805 if (explicitlyGlobal()) 0806 ret.append(QString()); 0807 0808 if (m_index) { 0809 ret.reserve(ret.size() + cd->identifiersSize()); 0810 FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, cd->identifiers) 0811 ret << index.identifier().toString(options); 0812 } else { 0813 ret.reserve(ret.size() + dd->identifiersSize()); 0814 FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, dd->identifiers) 0815 ret << index.identifier().toString(options); 0816 } 0817 0818 return ret; 0819 } 0820 0821 QString QualifiedIdentifier::toString(IdentifierStringFormattingOptions options) const 0822 { 0823 const QString doubleColon = QStringLiteral("::"); 0824 0825 QString ret; 0826 if (!options.testFlag(RemoveExplicitlyGlobalPrefix) && explicitlyGlobal()) 0827 ret = doubleColon; 0828 0829 QStringList identifiers; 0830 if (m_index) { 0831 identifiers.reserve(cd->identifiersSize()); 0832 FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, cd->identifiers) 0833 { 0834 identifiers += index.identifier().toString(options); 0835 } 0836 } else { 0837 identifiers.reserve(dd->identifiersSize()); 0838 FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, dd->identifiers) 0839 { 0840 identifiers += index.identifier().toString(options); 0841 } 0842 } 0843 0844 return ret + identifiers.join(doubleColon); 0845 } 0846 0847 QualifiedIdentifier QualifiedIdentifier::merge(const QualifiedIdentifier& base) const 0848 { 0849 QualifiedIdentifier ret(base); 0850 ret.push(*this); 0851 return ret; 0852 } 0853 0854 QualifiedIdentifier QualifiedIdentifier::operator+(const QualifiedIdentifier& rhs) const 0855 { 0856 return rhs.merge(*this); 0857 } 0858 0859 QualifiedIdentifier& QualifiedIdentifier::operator+=(const QualifiedIdentifier& rhs) 0860 { 0861 push(rhs); 0862 return *this; 0863 } 0864 0865 QualifiedIdentifier QualifiedIdentifier::operator+(const Identifier& rhs) const 0866 { 0867 QualifiedIdentifier ret(*this); 0868 ret.push(rhs); 0869 return ret; 0870 } 0871 0872 QualifiedIdentifier& QualifiedIdentifier::operator+=(const Identifier& rhs) 0873 { 0874 push(rhs); 0875 return *this; 0876 } 0877 0878 QualifiedIdentifier QualifiedIdentifier::operator+(const IndexedIdentifier& rhs) const 0879 { 0880 QualifiedIdentifier ret(*this); 0881 ret.push(rhs); 0882 return ret; 0883 } 0884 0885 QualifiedIdentifier& QualifiedIdentifier::operator+=(const IndexedIdentifier& rhs) 0886 { 0887 push(rhs); 0888 return *this; 0889 } 0890 0891 bool QualifiedIdentifier::isExpression() const 0892 { 0893 if (m_index) 0894 return cd->m_isExpression; 0895 else 0896 return dd->m_isExpression; 0897 } 0898 0899 void QualifiedIdentifier::setIsExpression(bool is) 0900 { 0901 if (is != isExpression()) { 0902 prepareWrite(); 0903 dd->m_isExpression = is; 0904 } 0905 } 0906 0907 bool QualifiedIdentifier::explicitlyGlobal() const 0908 { 0909 // True if started with "::" 0910 if (m_index) 0911 return cd->m_explicitlyGlobal; 0912 else 0913 return dd->m_explicitlyGlobal; 0914 } 0915 0916 void QualifiedIdentifier::setExplicitlyGlobal(bool eg) 0917 { 0918 if (eg != explicitlyGlobal()) { 0919 prepareWrite(); 0920 dd->m_explicitlyGlobal = eg; 0921 } 0922 } 0923 0924 bool QualifiedIdentifier::sameIdentifiers(const QualifiedIdentifier& rhs) const 0925 { 0926 if (m_index && rhs.m_index) 0927 return cd->listsEqual(*rhs.cd); 0928 else if (m_index && !rhs.m_index) 0929 return cd->listsEqual(*rhs.dd); 0930 else if (!m_index && !rhs.m_index) 0931 return dd->listsEqual(*rhs.dd); 0932 else 0933 return dd->listsEqual(*rhs.cd); 0934 } 0935 0936 bool QualifiedIdentifier::operator==(const QualifiedIdentifier& rhs) const 0937 { 0938 if (cd == rhs.cd) 0939 return true; 0940 return hash() == rhs.hash() && sameIdentifiers(rhs); 0941 } 0942 0943 bool QualifiedIdentifier::operator!=(const QualifiedIdentifier& rhs) const 0944 { 0945 return !operator==(rhs); 0946 } 0947 0948 bool QualifiedIdentifier::beginsWith(const QualifiedIdentifier& other) const 0949 { 0950 uint c = count(); 0951 uint oc = other.count(); 0952 0953 for (uint i = 0; i < c && i < oc; ++i) 0954 if (at(i) == other.at(i)) { 0955 continue; 0956 } else { 0957 return false; 0958 } 0959 0960 return true; 0961 } 0962 0963 struct Visitor 0964 { 0965 Visitor(KDevVarLengthArray<QualifiedIdentifier>& target, uint hash) 0966 : target(target) 0967 , hash(hash) 0968 { 0969 } 0970 0971 bool operator()(const ConstantQualifiedIdentifierPrivate* item, uint index) const 0972 { 0973 if (item->m_hash == hash) 0974 target.append(QualifiedIdentifier(index)); 0975 return true; 0976 } 0977 0978 KDevVarLengthArray<QualifiedIdentifier>& target; 0979 const uint hash; 0980 }; 0981 0982 uint QualifiedIdentifier::hash() const 0983 { 0984 if (m_index) 0985 return cd->hash(); 0986 else 0987 return dd->hash(); 0988 } 0989 0990 uint qHash(const IndexedTypeIdentifier& id) 0991 { 0992 return id.hash(); 0993 } 0994 0995 uint qHash(const QualifiedIdentifier& id) 0996 { 0997 return id.hash(); 0998 } 0999 1000 uint qHash(const Identifier& id) 1001 { 1002 return id.hash(); 1003 } 1004 1005 bool QualifiedIdentifier::isQualified() const 1006 { 1007 return count() > 1 || explicitlyGlobal(); 1008 } 1009 1010 void QualifiedIdentifier::push(const Identifier& id) 1011 { 1012 if (id.isEmpty()) 1013 return; 1014 1015 push(IndexedIdentifier(id)); 1016 } 1017 1018 void QualifiedIdentifier::push(const IndexedIdentifier& id) 1019 { 1020 if (id.isEmpty()) { 1021 return; 1022 } 1023 1024 prepareWrite(); 1025 1026 dd->identifiersList.append(id); 1027 } 1028 1029 void QualifiedIdentifier::push(const QualifiedIdentifier& id) 1030 { 1031 if (id.isEmpty()) { 1032 return; 1033 } 1034 1035 prepareWrite(); 1036 1037 if (id.m_index) { 1038 dd->identifiersList.append(id.cd->identifiers(), id.cd->identifiersSize()); 1039 } else { 1040 dd->identifiersList.append(id.dd->identifiers(), id.dd->identifiersSize()); 1041 } 1042 1043 if (id.explicitlyGlobal()) { 1044 setExplicitlyGlobal(true); 1045 } 1046 } 1047 1048 void QualifiedIdentifier::pop() 1049 { 1050 prepareWrite(); 1051 if (!dd->identifiersSize()) 1052 return; 1053 dd->identifiersList.resize(dd->identifiersList.size() - 1); 1054 } 1055 1056 void QualifiedIdentifier::clear() 1057 { 1058 prepareWrite(); 1059 dd->identifiersList.clear(); 1060 dd->m_explicitlyGlobal = false; 1061 dd->m_isExpression = false; 1062 } 1063 1064 bool QualifiedIdentifier::isEmpty() const 1065 { 1066 if (m_index) 1067 return cd->identifiersSize() == 0; 1068 else 1069 return dd->identifiersSize() == 0; 1070 } 1071 1072 int QualifiedIdentifier::count() const 1073 { 1074 if (m_index) 1075 return cd->identifiersSize(); 1076 else 1077 return dd->identifiersSize(); 1078 } 1079 1080 Identifier QualifiedIdentifier::first() const 1081 { 1082 return indexedFirst().identifier(); 1083 } 1084 1085 IndexedIdentifier QualifiedIdentifier::indexedFirst() const 1086 { 1087 if ((m_index && cd->identifiersSize() == 0) || (!m_index && dd->identifiersSize() == 0)) 1088 return IndexedIdentifier(); 1089 else 1090 return indexedAt(0); 1091 } 1092 1093 Identifier QualifiedIdentifier::last() const 1094 { 1095 return indexedLast().identifier(); 1096 } 1097 1098 IndexedIdentifier QualifiedIdentifier::indexedLast() const 1099 { 1100 uint c = count(); 1101 if (c) 1102 return indexedAt(c - 1); 1103 else 1104 return IndexedIdentifier(); 1105 } 1106 1107 Identifier QualifiedIdentifier::top() const 1108 { 1109 return last(); 1110 } 1111 1112 QualifiedIdentifier QualifiedIdentifier::mid(int pos, int len) const 1113 { 1114 QualifiedIdentifier ret; 1115 if (pos == 0) 1116 ret.setExplicitlyGlobal(explicitlyGlobal()); 1117 1118 int cnt = ( int )count(); 1119 1120 if (len == -1) 1121 len = cnt - pos; 1122 1123 if (pos + len > cnt) 1124 len -= cnt - (pos + len); 1125 1126 for (int a = pos; a < pos + len; a++) 1127 ret.push(at(a)); 1128 1129 return ret; 1130 } 1131 1132 Identifier QualifiedIdentifier::at(int i) const 1133 { 1134 return indexedAt(i).identifier(); 1135 } 1136 1137 IndexedIdentifier QualifiedIdentifier::indexedAt(int i) const 1138 { 1139 if (m_index) { 1140 Q_ASSERT(i >= 0 && i < ( int )cd->identifiersSize()); 1141 return cd->identifiers()[i]; 1142 } else { 1143 Q_ASSERT(i >= 0 && i < ( int )dd->identifiersSize()); 1144 return dd->identifiers()[i]; 1145 } 1146 } 1147 1148 void QualifiedIdentifier::makeConstant() const 1149 { 1150 if (m_index) 1151 return; 1152 1153 LockedItemRepository::write<IndexedQualifiedIdentifier>( 1154 [&, request = QualifiedIdentifierItemRequest(*dd)](QualifiedIdentifierRepository& repo) { 1155 m_index = repo.index(request); 1156 delete dd; 1157 cd = repo.itemFromIndex(m_index); 1158 }); 1159 } 1160 1161 void QualifiedIdentifier::prepareWrite() 1162 { 1163 if (m_index) { 1164 const QualifiedIdentifierPrivate<false>* oldCc = cd; 1165 dd = new QualifiedIdentifierPrivate<true>; 1166 dd->m_explicitlyGlobal = oldCc->m_explicitlyGlobal; 1167 dd->m_isExpression = oldCc->m_isExpression; 1168 dd->m_hash = oldCc->m_hash; 1169 1170 dd->copyListsFrom(*oldCc); 1171 m_index = 0; 1172 } 1173 1174 dd->clearHash(); 1175 } 1176 1177 uint IndexedTypeIdentifier::hash() const 1178 { 1179 quint32 bitfields = static_cast<quint32>(m_isConstant) 1180 | (m_isReference << 1) 1181 | (m_isRValue << 2) 1182 | (m_isVolatile << 3) 1183 | (m_pointerDepth << 4) 1184 | (m_pointerConstMask << 9); 1185 return KDevHash() << m_identifier.index() << bitfields; 1186 } 1187 1188 bool IndexedTypeIdentifier::operator==(const IndexedTypeIdentifier& rhs) const 1189 { 1190 return m_identifier == rhs.m_identifier 1191 && m_isConstant == rhs.m_isConstant 1192 && m_isReference == rhs.m_isReference 1193 && m_isRValue == rhs.m_isRValue 1194 && m_isVolatile == rhs.m_isVolatile 1195 && m_pointerConstMask == rhs.m_pointerConstMask 1196 && m_pointerDepth == rhs.m_pointerDepth; 1197 } 1198 1199 bool IndexedTypeIdentifier::operator!=(const IndexedTypeIdentifier& rhs) const 1200 { 1201 return !operator==(rhs); 1202 } 1203 1204 bool IndexedTypeIdentifier::isReference() const 1205 { 1206 return m_isReference; 1207 } 1208 1209 void IndexedTypeIdentifier::setIsReference(bool isRef) 1210 { 1211 m_isReference = isRef; 1212 } 1213 1214 bool IndexedTypeIdentifier::isRValue() const 1215 { 1216 return m_isRValue; 1217 } 1218 1219 void IndexedTypeIdentifier::setIsRValue(bool isRVal) 1220 { 1221 m_isRValue = isRVal; 1222 } 1223 1224 bool IndexedTypeIdentifier::isConstant() const 1225 { 1226 return m_isConstant; 1227 } 1228 1229 void IndexedTypeIdentifier::setIsConstant(bool isConst) 1230 { 1231 m_isConstant = isConst; 1232 } 1233 1234 bool IndexedTypeIdentifier::isVolatile() const 1235 { 1236 return m_isVolatile; 1237 } 1238 1239 void IndexedTypeIdentifier::setIsVolatile(bool isVolatile) 1240 { 1241 m_isVolatile = isVolatile; 1242 } 1243 1244 int IndexedTypeIdentifier::pointerDepth() const 1245 { 1246 return m_pointerDepth; 1247 } 1248 1249 void IndexedTypeIdentifier::setPointerDepth(int depth) 1250 { 1251 Q_ASSERT(depth <= 23 && depth >= 0); 1252 ///Clear the mask in removed fields 1253 for (int s = depth; s < ( int )m_pointerDepth; ++s) 1254 setIsConstPointer(s, false); 1255 1256 m_pointerDepth = depth; 1257 } 1258 1259 bool IndexedTypeIdentifier::isConstPointer(int depthNumber) const 1260 { 1261 return m_pointerConstMask & (1 << depthNumber); 1262 } 1263 1264 void IndexedTypeIdentifier::setIsConstPointer(int depthNumber, bool constant) 1265 { 1266 if (constant) 1267 m_pointerConstMask |= (1 << depthNumber); 1268 else 1269 m_pointerConstMask &= (~(1 << depthNumber)); 1270 } 1271 1272 QString IndexedTypeIdentifier::toString(IdentifierStringFormattingOptions options) const 1273 { 1274 QString ret; 1275 if (isConstant()) 1276 ret += QLatin1String("const "); 1277 if (isVolatile()) 1278 ret += QLatin1String("volatile "); 1279 1280 ret += m_identifier.identifier().toString(options); 1281 for (int a = 0; a < pointerDepth(); ++a) { 1282 ret += QLatin1Char('*'); 1283 if (isConstPointer(a)) 1284 ret += QLatin1String("const"); 1285 } 1286 1287 if (isRValue()) 1288 ret += QLatin1String("&&"); 1289 else if (isReference()) 1290 ret += QLatin1Char('&'); 1291 return ret; 1292 } 1293 1294 IndexedTypeIdentifier::IndexedTypeIdentifier(const IndexedQualifiedIdentifier& identifier) 1295 : m_identifier(identifier) 1296 , m_isConstant(false) 1297 , m_isReference(false) 1298 , m_isRValue(false) 1299 , m_isVolatile(false) 1300 , m_pointerDepth(0) 1301 , m_pointerConstMask(0) 1302 { } 1303 1304 IndexedTypeIdentifier::IndexedTypeIdentifier(QStringView identifier, bool isExpression) 1305 : m_identifier(QualifiedIdentifier(identifier, isExpression)) 1306 , m_isConstant(false) 1307 , m_isReference(false) 1308 , m_isRValue(false) 1309 , m_isVolatile(false) 1310 , m_pointerDepth(0) 1311 , m_pointerConstMask(0) 1312 { } 1313 1314 // NOTE: the definitions of ItemRepositoryReferenceCounting's inc(), dec() and setIndex() are so 1315 // complex that they can throw exceptions for many reasons. Yet some special member functions of 1316 // Indexed[Qualified]Identifier, which call them, are implicitly (the destructors) or explicitly 1317 // noexcept. The noexcept-ness of these functions is important for correctness and performance. 1318 // This is safe at the moment, because the entire KDevPlatformLanguage library, that contains these 1319 // classes, is compiled with exceptions disabled (-fno-exceptions), which already prevents exception 1320 // propagation to a caller of any non-inline function in this library. 1321 1322 IndexedIdentifier::IndexedIdentifier(unsigned int index) 1323 : m_index(index) 1324 { 1325 ItemRepositoryReferenceCounting::inc(this); 1326 } 1327 1328 IndexedIdentifier::IndexedIdentifier() 1329 : IndexedIdentifier(emptyConstantIdentifierPrivateIndex()) 1330 { 1331 } 1332 1333 IndexedIdentifier::IndexedIdentifier(const Identifier& id) 1334 : IndexedIdentifier(id.index()) 1335 { 1336 } 1337 1338 IndexedIdentifier::IndexedIdentifier(const IndexedIdentifier& rhs) noexcept 1339 : IndexedIdentifier(rhs.m_index) 1340 { 1341 } 1342 1343 IndexedIdentifier::~IndexedIdentifier() 1344 { 1345 ItemRepositoryReferenceCounting::dec(this); 1346 } 1347 1348 IndexedIdentifier& IndexedIdentifier::operator=(unsigned int index) 1349 { 1350 ItemRepositoryReferenceCounting::setIndex(this, m_index, index); 1351 return *this; 1352 } 1353 1354 IndexedIdentifier& IndexedIdentifier::operator=(const Identifier& id) 1355 { 1356 return operator=(id.index()); 1357 } 1358 1359 IndexedIdentifier& IndexedIdentifier::operator=(const IndexedIdentifier& id) noexcept 1360 { 1361 return operator=(id.m_index); 1362 } 1363 1364 bool IndexedIdentifier::operator==(const IndexedIdentifier& rhs) const 1365 { 1366 return m_index == rhs.m_index; 1367 } 1368 1369 bool IndexedIdentifier::operator!=(const IndexedIdentifier& rhs) const 1370 { 1371 return m_index != rhs.m_index; 1372 } 1373 1374 bool IndexedIdentifier::operator==(const Identifier& id) const 1375 { 1376 return m_index == id.index(); 1377 } 1378 1379 Identifier IndexedIdentifier::identifier() const 1380 { 1381 return Identifier(m_index); 1382 } 1383 1384 IndexedIdentifier::operator Identifier() const 1385 { 1386 return Identifier(m_index); 1387 } 1388 1389 bool IndexedQualifiedIdentifier::isValid() const 1390 { 1391 return m_index != emptyConstantQualifiedIdentifierPrivateIndex(); 1392 } 1393 1394 bool IndexedQualifiedIdentifier::isEmpty() const 1395 { 1396 return m_index == emptyConstantQualifiedIdentifierPrivateIndex(); 1397 } 1398 1399 int cnt = 0; 1400 1401 IndexedQualifiedIdentifier IndexedTypeIdentifier::identifier() const 1402 { 1403 return m_identifier; 1404 } 1405 1406 void IndexedTypeIdentifier::setIdentifier(const IndexedQualifiedIdentifier& id) 1407 { 1408 m_identifier = id; 1409 } 1410 1411 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(unsigned int index) 1412 : m_index(index) 1413 { 1414 ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ") Creating" << identifier().toString() << m_index); 1415 1416 ItemRepositoryReferenceCounting::inc(this); 1417 } 1418 1419 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier() 1420 : IndexedQualifiedIdentifier(emptyConstantQualifiedIdentifierPrivateIndex()) 1421 { 1422 } 1423 1424 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(const QualifiedIdentifier& id) 1425 : IndexedQualifiedIdentifier(id.index()) 1426 { 1427 } 1428 1429 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(const IndexedQualifiedIdentifier& id) noexcept 1430 : IndexedQualifiedIdentifier(id.m_index) 1431 { 1432 } 1433 1434 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(unsigned int index) 1435 { 1436 ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ") Assigning to" << identifier().toString() << m_index); 1437 1438 ItemRepositoryReferenceCounting::setIndex(this, m_index, index); 1439 return *this; 1440 } 1441 1442 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(const QualifiedIdentifier& id) 1443 { 1444 return operator=(id.index()); 1445 } 1446 1447 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(const IndexedQualifiedIdentifier& rhs) noexcept 1448 { 1449 return operator=(rhs.m_index); 1450 } 1451 1452 IndexedQualifiedIdentifier::~IndexedQualifiedIdentifier() 1453 { 1454 ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ") Destroying" << identifier().toString() << m_index); 1455 ItemRepositoryReferenceCounting::dec(this); 1456 } 1457 1458 bool IndexedQualifiedIdentifier::operator==(const IndexedQualifiedIdentifier& rhs) const 1459 { 1460 return m_index == rhs.m_index; 1461 } 1462 1463 bool IndexedQualifiedIdentifier::operator==(const QualifiedIdentifier& id) const 1464 { 1465 return m_index == id.index(); 1466 } 1467 1468 QualifiedIdentifier IndexedQualifiedIdentifier::identifier() const 1469 { 1470 return QualifiedIdentifier(m_index); 1471 } 1472 1473 IndexedQualifiedIdentifier::operator QualifiedIdentifier() const 1474 { 1475 return QualifiedIdentifier(m_index); 1476 } 1477 1478 void initIdentifierRepository() 1479 { 1480 emptyConstantIdentifierPrivateIndex(); 1481 emptyConstantIdentifierPrivate(); 1482 emptyConstantQualifiedIdentifierPrivateIndex(); 1483 emptyConstantQualifiedIdentifierPrivate(); 1484 } 1485 } 1486 1487 QDebug operator<<(QDebug s, const KDevelop::Identifier& identifier) 1488 { 1489 s.nospace() << identifier.toString(); 1490 return s.space(); 1491 } 1492 1493 QDebug operator<<(QDebug s, const KDevelop::QualifiedIdentifier& identifier) 1494 { 1495 s.nospace() << identifier.toString(); 1496 return s.space(); 1497 }