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 #ifndef KDEVPLATFORM_IDENTIFIER_H
0009 #define KDEVPLATFORM_IDENTIFIER_H
0010 
0011 #include <QList>
0012 #include <QMetaType>
0013 #include <QStringView>
0014 
0015 #include <util/kdevvarlengtharray.h>
0016 
0017 #include <language/languageexport.h>
0018 #include <serialization/referencecounting.h>
0019 
0020 //We use shared d-pointers, which is even better than a d-pointer, but krazy probably won't get it, so exclude the test.
0021 //krazy:excludeall=dpointer
0022 
0023 class QStringList;
0024 
0025 namespace KDevelop {
0026 class IndexedTypeIdentifier;
0027 class Identifier;
0028 class QualifiedIdentifier;
0029 template <bool>
0030 class QualifiedIdentifierPrivate;
0031 template <bool>
0032 class IdentifierPrivate;
0033 class IndexedString;
0034 
0035 /**
0036  * @note Move constructor and move assignment operator are deliberately not implemented for
0037  * Indexed[Qualified]Identifier. The move operations are tricky to implement correctly and more
0038  * efficiently in practice than the copy operations. swap() could be specialized for these two
0039  * classes, but it would never be called in practice. See a similar note for class IndexedString.
0040  */
0041 
0042 /**
0043  * A helper-class to store an identifier by index in a type-safe way.
0044  *
0045  * The difference to Identifier is that this class only stores the index of an identifier that is in the repository, without any dynamic
0046  * abilities or access to the contained data.
0047  *
0048  * This class does "disk reference counting"
0049  *
0050  * @warning Do not use this after QCoreApplication::aboutToQuit() has been emitted, items that are not disk-referenced will be invalid at that point.
0051  */
0052 class KDEVPLATFORMLANGUAGE_EXPORT IndexedIdentifier
0053     : public ReferenceCountManager
0054 {
0055 public:
0056     IndexedIdentifier();
0057     explicit IndexedIdentifier(const Identifier& id);
0058     IndexedIdentifier(const IndexedIdentifier& rhs) noexcept;
0059     IndexedIdentifier& operator=(const Identifier& id);
0060     IndexedIdentifier& operator=(const IndexedIdentifier& rhs) noexcept;
0061     ~IndexedIdentifier();
0062     bool operator==(const IndexedIdentifier& rhs) const;
0063     bool operator!=(const IndexedIdentifier& rhs) const;
0064     bool operator==(const Identifier& id) const;
0065 
0066     bool isEmpty() const;
0067 
0068     Identifier identifier() const;
0069     operator Identifier() const;
0070 
0071     unsigned int index() const
0072     {
0073         return m_index;
0074     }
0075 
0076 private:
0077     explicit IndexedIdentifier(unsigned int index);
0078     IndexedIdentifier& operator=(unsigned int index);
0079 
0080     unsigned int m_index;
0081 };
0082 
0083 /**
0084  * A helper-class to store an identifier by index in a type-safe way.
0085  *
0086  * The difference to QualifiedIdentifier is that this class only stores the index of an identifier that is in the repository, without any dynamic
0087  * abilities or access to the contained data.
0088  *
0089  * This class does "disk reference counting"
0090  *
0091  * @warning Do not use this after QCoreApplication::aboutToQuit() has been emitted, items that are not disk-referenced will be invalid at that point.
0092  */
0093 class KDEVPLATFORMLANGUAGE_EXPORT IndexedQualifiedIdentifier
0094     : public ReferenceCountManager
0095 {
0096 public:
0097     IndexedQualifiedIdentifier();
0098     IndexedQualifiedIdentifier(const QualifiedIdentifier& id);
0099     IndexedQualifiedIdentifier(const IndexedQualifiedIdentifier& rhs) noexcept;
0100     IndexedQualifiedIdentifier& operator=(const QualifiedIdentifier& id);
0101     IndexedQualifiedIdentifier& operator=(const IndexedQualifiedIdentifier& id) noexcept;
0102     ~IndexedQualifiedIdentifier();
0103     bool operator==(const IndexedQualifiedIdentifier& rhs) const;
0104     bool operator==(const QualifiedIdentifier& id) const;
0105 
0106     bool operator<(const IndexedQualifiedIdentifier& rhs) const
0107     {
0108         return m_index < rhs.m_index;
0109     }
0110 
0111     bool isValid() const;
0112     bool isEmpty() const;
0113 
0114     QualifiedIdentifier identifier() const;
0115     operator QualifiedIdentifier() const;
0116 
0117     unsigned int index() const
0118     {
0119         return m_index;
0120     }
0121 
0122 private:
0123     explicit IndexedQualifiedIdentifier(unsigned int index);
0124     IndexedQualifiedIdentifier& operator=(unsigned int index);
0125     unsigned int m_index;
0126 };
0127 
0128 /**
0129  * Flags to control the string representation of identifiers.
0130  */
0131 enum IdentifierStringFormattingOption {
0132     NoOptions = 0x0,
0133 
0134     /// Removes explicit global prefix from the result.
0135     /// When enabled, global identifiers will be formatted as "globalIdentifierFormattedString"
0136     /// instead "::globalIdentifierFormattedString".
0137     RemoveExplicitlyGlobalPrefix = 0x1,
0138 
0139     /// Removes template information from the result.
0140     /// When enabled, TemplateClass< someDataType > will be formatted as plain "TemplateClass".
0141     RemoveTemplateInformation = 0x2
0142 };
0143 Q_DECLARE_FLAGS(IdentifierStringFormattingOptions, IdentifierStringFormattingOption)
0144 
0145 /**
0146  * Represents a single unqualified identifier
0147  */
0148 class KDEVPLATFORMLANGUAGE_EXPORT Identifier
0149 {
0150     friend class QualifiedIdentifier;
0151 
0152 public:
0153     /**
0154      * @param start The position in the given string where to start searching for the identifier. (optional)
0155      * @param takenRange If this is nonzero, it will be filled with the length of the range from the beginning
0156      *                   of the given string, that was used to construct this identifier. (optional)
0157      *
0158      * @warning The identifier is parsed in a C++-similar way, and the result may not be what you expect.
0159      *          If you want to prevent that parsing, use the constructor that takes IndexedString.
0160      */
0161     explicit Identifier(QStringView str, uint start = 0, uint* takenRange = nullptr);
0162     explicit Identifier(const QString& str, uint start = 0, uint* takenRange = nullptr)
0163         : Identifier(QStringView{str}, start, takenRange)
0164     {
0165     }
0166 
0167     /**
0168      * Preferred constructor, use this if you already have an IndexedString available. This does not decompose the given string.
0169      */
0170     explicit Identifier(const IndexedString& str);
0171     Identifier(const Identifier& rhs);
0172     explicit Identifier(uint index);
0173     Identifier();
0174     Identifier(Identifier&& rhs) Q_DECL_NOEXCEPT;
0175     ~Identifier();
0176     Identifier& operator=(const Identifier& rhs);
0177     Identifier& operator=(Identifier&& rhs) Q_DECL_NOEXCEPT;
0178 
0179     static Identifier unique(int token);
0180 
0181     bool isUnique() const;
0182     int uniqueToken() const;
0183     /**
0184      * If \a token is non-zero, turns this Identifier into the special per-document unique identifier.
0185      *
0186      * This is used e.g. for anonymous namespaces.
0187      *
0188      * Pass a token which is specific to the document to allow correct equality comparison.
0189      */
0190     void setUnique(int token);
0191 
0192     const IndexedString identifier() const;
0193     void setIdentifier(QStringView identifier);
0194     /**
0195      * Should be preferred over the other version
0196      */
0197     void setIdentifier(const IndexedString& identifier);
0198 
0199     uint hash() const;
0200 
0201     /**
0202      * Comparison ignoring the template-identifiers
0203      */
0204     bool nameEquals(const Identifier& rhs) const;
0205 
0206     /**
0207      * @warning This is expensive.
0208      */
0209     IndexedTypeIdentifier templateIdentifier(int num) const;
0210     uint templateIdentifiersCount() const;
0211     void appendTemplateIdentifier(const IndexedTypeIdentifier& identifier);
0212     void clearTemplateIdentifiers();
0213     void setTemplateIdentifiers(const QList<IndexedTypeIdentifier>& templateIdentifiers);
0214 
0215     QString toString(IdentifierStringFormattingOptions options = NoOptions) const;
0216 
0217     /**
0218      * Whether this identifier begins with an underscore followed by a capital letter or by another underscore.
0219      */
0220     bool isReserved() const;
0221 
0222     bool operator==(const Identifier& rhs) const;
0223     bool operator!=(const Identifier& rhs) const;
0224 
0225     bool isEmpty() const;
0226 
0227     /**
0228      * @return a unique index within the global identifier repository for this identifier.
0229      *
0230      * If the identifier isn't in the repository yet, it is added to the repository.
0231      */
0232     uint index() const;
0233 
0234     bool inRepository() const;
0235 
0236 private:
0237     void makeConstant() const;
0238     void prepareWrite();
0239 
0240     //Only one of the following pointers is valid at a given time
0241     mutable uint m_index; //Valid if cd is valid
0242     union {
0243         mutable IdentifierPrivate<true>* dd; //Dynamic, owned by this identifier
0244         mutable const IdentifierPrivate<false>* cd; //Constant, owned by the repository
0245     };
0246 };
0247 
0248 /**
0249  * Represents a qualified identifier
0250  *
0251  * QualifiedIdentifier has it's hash-values stored, so using the hash-values is very efficient.
0252  */
0253 class KDEVPLATFORMLANGUAGE_EXPORT QualifiedIdentifier
0254 {
0255 public:
0256     explicit QualifiedIdentifier(QStringView id, bool isExpression = false);
0257     explicit QualifiedIdentifier(const QString& id, bool isExpression = false)
0258         : QualifiedIdentifier(QStringView{id}, isExpression)
0259     {
0260     }
0261 
0262     explicit QualifiedIdentifier(const Identifier& id);
0263     QualifiedIdentifier(const QualifiedIdentifier& id);
0264     explicit QualifiedIdentifier(uint index);
0265     QualifiedIdentifier();
0266     QualifiedIdentifier(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT;
0267     ~QualifiedIdentifier();
0268     QualifiedIdentifier& operator=(const QualifiedIdentifier& rhs);
0269     QualifiedIdentifier& operator=(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT;
0270 
0271     /**
0272      * Append @p id to this qualified identifier.
0273      */
0274     void push(const IndexedIdentifier& id);
0275     /**
0276      * Append @p id to this qualified identifier.
0277      *
0278      * NOTE: If you have an indexed identifier available, use the above method instead.
0279      */
0280     void push(const Identifier& id);
0281     /**
0282      * Append all identifiers of @p id to this qualified identifier.
0283      */
0284     void push(const QualifiedIdentifier& id);
0285 
0286     /**
0287      * Pops one identifier from back:
0288      */
0289     void pop();
0290     void clear();
0291     bool isEmpty() const;
0292     int count() const;
0293     Identifier first() const;
0294     IndexedIdentifier indexedFirst() const;
0295     Identifier last() const;
0296     IndexedIdentifier indexedLast() const;
0297     Identifier top() const;
0298     Identifier at(int i) const;
0299     IndexedIdentifier indexedAt(int i) const;
0300     /**
0301      * @param pos Position where to start the copy.
0302      * @param len If this is -1, the whole following part will be returned.
0303      */
0304     QualifiedIdentifier mid(int pos, int len = -1) const;
0305 
0306     /**
0307      * Copy the leftmost \a len number of identifiers.
0308      *
0309      * @param len The number of identifiers to copy, or if negative, the number of identifiers to omit from the right
0310      */
0311     inline QualifiedIdentifier left(int len) const
0312     {
0313         return mid(0, len > 0 ? len : count() + len);
0314     }
0315 
0316     ///@todo Remove this flag
0317     bool explicitlyGlobal() const;
0318     void setExplicitlyGlobal(bool eg);
0319     bool isQualified() const;
0320 
0321     /**
0322      * A flag that can be set by setIsExpression
0323      */
0324     bool isExpression() const;
0325     /**
0326      * Set the expression-flag, that can be retrieved by isExpression().
0327      * This flag is not respected while creating the hash-value and while operator==() comparison.
0328      * It is respected while isSame(..) comparison.
0329      */
0330     void setIsExpression(bool);
0331 
0332     QString toString(IdentifierStringFormattingOptions options = NoOptions) const;
0333     QStringList toStringList(IdentifierStringFormattingOptions options = NoOptions) const;
0334 
0335     QualifiedIdentifier operator+(const QualifiedIdentifier& rhs) const;
0336     QualifiedIdentifier& operator+=(const QualifiedIdentifier& rhs);
0337 
0338     /**
0339      * Nicer interfaces to merge
0340      */
0341     QualifiedIdentifier operator+(const Identifier& rhs) const;
0342     QualifiedIdentifier& operator+=(const Identifier& rhs);
0343 
0344     QualifiedIdentifier operator+(const IndexedIdentifier& rhs) const;
0345     QualifiedIdentifier& operator+=(const IndexedIdentifier& rhs);
0346 
0347     /**
0348      * @return a QualifiedIdentifier with this one appended to the other.
0349      *
0350      * It is explicitly global if either this or base is.
0351      */
0352     QualifiedIdentifier merge(const QualifiedIdentifier& base) const;
0353 
0354     /**
0355      * The comparison-operators do not respect explicitlyGlobal and isExpression, they only respect the real scope.
0356      * This is for convenient use in hash-tables etc.
0357      */
0358     bool operator==(const QualifiedIdentifier& rhs) const;
0359     bool operator!=(const QualifiedIdentifier& rhs) const;
0360 
0361     bool beginsWith(const QualifiedIdentifier& other) const;
0362 
0363     uint index() const;
0364 
0365     /**
0366      * @return true if this qualified identifier is already in the persistent identifier repository
0367      */
0368     bool inRepository() const;
0369 
0370     /**
0371      * The hash does not respect explicitlyGlobal, only the real scope.
0372      */
0373     uint hash() const;
0374 
0375 protected:
0376     bool sameIdentifiers(const QualifiedIdentifier& rhs) const;
0377 
0378     void makeConstant() const;
0379     void prepareWrite();
0380 
0381     mutable uint m_index;
0382     union {
0383         mutable QualifiedIdentifierPrivate<true>* dd;
0384         mutable const QualifiedIdentifierPrivate<false>* cd;
0385     };
0386 };
0387 
0388 /**
0389  * Extends IndexedQualifiedIdentifier by:
0390  * - Arbitrary count of pointer-poperators with cv-qualifiers
0391  * - Reference operator
0392  * All the properties set here are respected in the hash value.
0393  */
0394 class KDEVPLATFORMLANGUAGE_EXPORT IndexedTypeIdentifier
0395 {
0396 public:
0397     /**
0398      * Variables like pointerDepth, isReference, etc. are not parsed from the string, so this parsing is quite limited.
0399      */
0400     explicit IndexedTypeIdentifier(const IndexedQualifiedIdentifier& identifier = IndexedQualifiedIdentifier());
0401     explicit IndexedTypeIdentifier(QStringView identifer, bool isExpression = false);
0402 
0403     bool isReference() const;
0404     void setIsReference(bool);
0405 
0406     bool isRValue() const;
0407     void setIsRValue(bool);
0408 
0409     bool isConstant() const;
0410     void setIsConstant(bool);
0411 
0412     bool isVolatile() const;
0413     void setIsVolatile(bool);
0414 
0415     IndexedQualifiedIdentifier identifier() const;
0416 
0417     void setIdentifier(const IndexedQualifiedIdentifier& id);
0418 
0419     /**
0420      * @return the pointer depth. Example for C++: "char*" has pointer-depth 1, "char***" has pointer-depth 3
0421      */
0422     int pointerDepth() const;
0423     /**
0424      * Sets the pointer-depth to the specified count.
0425      *
0426      * When the pointer-depth is increased, the "isConstPointer" values for new depths will be initialized with false.
0427      *
0428      * For efficiency-reasons the maximum currently is 23.
0429      */
0430     void setPointerDepth(int);
0431 
0432     /**
0433      * Whether the target of pointer 'depthNumber' is constant
0434      */
0435     bool isConstPointer(int depthNumber) const;
0436     void setIsConstPointer(int depthNumber, bool constant);
0437 
0438     QString toString(IdentifierStringFormattingOptions options = NoOptions) const;
0439 
0440     uint hash() const;
0441 
0442     /**
0443      * The comparison-operators do not respect explicitlyGlobal and isExpression, they only respect the real scope.
0444      * This is for convenient use in hash-tables etc.
0445      */
0446     bool operator==(const IndexedTypeIdentifier& rhs) const;
0447     bool operator!=(const IndexedTypeIdentifier& rhs) const;
0448 
0449 private:
0450     IndexedQualifiedIdentifier m_identifier;
0451     // The overall number of bits shared by these bit-fields should not exceed 32,
0452     // so that we don't waste space. IndexedTypeIdentifer should be as compact as possible.
0453     bool m_isConstant : 1;
0454     bool m_isReference : 1;
0455     bool m_isRValue : 1;
0456     bool m_isVolatile : 1;
0457     uint m_pointerDepth : 5;
0458     uint m_pointerConstMask : 23;
0459 };
0460 
0461 KDEVPLATFORMLANGUAGE_EXPORT uint qHash(const IndexedTypeIdentifier& id);
0462 KDEVPLATFORMLANGUAGE_EXPORT uint qHash(const QualifiedIdentifier& id);
0463 KDEVPLATFORMLANGUAGE_EXPORT uint qHash(const Identifier& id);
0464 
0465 inline uint qHash(const IndexedIdentifier& id)
0466 {
0467     return id.index();
0468 }
0469 
0470 inline uint qHash(const IndexedQualifiedIdentifier& id)
0471 {
0472     return id.index();
0473 }
0474 }
0475 
0476 Q_DECLARE_TYPEINFO(KDevelop::IndexedTypeIdentifier, Q_MOVABLE_TYPE);
0477 Q_DECLARE_TYPEINFO(KDevelop::IndexedQualifiedIdentifier, Q_MOVABLE_TYPE);
0478 Q_DECLARE_TYPEINFO(KDevelop::IndexedIdentifier, Q_MOVABLE_TYPE);
0479 Q_DECLARE_METATYPE(KDevelop::IndexedQualifiedIdentifier)
0480 Q_DECLARE_METATYPE(KDevelop::IndexedIdentifier)
0481 
0482 Q_DECLARE_TYPEINFO(KDevelop::QualifiedIdentifier, Q_MOVABLE_TYPE);
0483 Q_DECLARE_TYPEINFO(KDevelop::Identifier, Q_MOVABLE_TYPE);
0484 Q_DECLARE_METATYPE(KDevelop::QualifiedIdentifier)
0485 Q_DECLARE_METATYPE(KDevelop::Identifier)
0486 
0487 /**
0488  * {q,k}Debug() stream operator: Writes the Identifier to the debug output.
0489  */
0490 KDEVPLATFORMLANGUAGE_EXPORT QDebug operator<<(QDebug s, const KDevelop::Identifier& identifier);
0491 
0492 /**
0493  * {q,k}Debug() stream operator: Writes the QualifiedIdentifier to the debug output.
0494  */
0495 KDEVPLATFORMLANGUAGE_EXPORT QDebug operator<<(QDebug s, const KDevelop::QualifiedIdentifier& identifier);
0496 
0497 #endif // KDEVPLATFORM_IDENTIFIER_H