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 #ifndef KDEVPLATFORM_IDENTIFIER_H
9 #define KDEVPLATFORM_IDENTIFIER_H
10 
11 #include <QList>
12 #include <QMetaType>
13 #include <util/kdevvarlengtharray.h>
14 
15 #include <language/languageexport.h>
16 #include <serialization/referencecounting.h>
17 
18 //We use shared d-pointers, which is even better than a d-pointer, but krazy probably won't get it, so exclude the test.
19 //krazy:excludeall=dpointer
20 
21 class QStringList;
22 
23 namespace KDevelop {
24 class IndexedTypeIdentifier;
25 class Identifier;
26 class QualifiedIdentifier;
27 template <bool>
28 class QualifiedIdentifierPrivate;
29 template <bool>
30 class IdentifierPrivate;
31 class IndexedString;
32 
33 /**
34  * A helper-class to store an identifier by index in a type-safe way.
35  *
36  * The difference to Identifier is that this class only stores the index of an identifier that is in the repository, without any dynamic
37  * abilities or access to the contained data.
38  *
39  * This class does "disk reference counting"
40  *
41  * @warning Do not use this after QCoreApplication::aboutToQuit() has been emitted, items that are not disk-referenced will be invalid at that point.
42  */
43 class KDEVPLATFORMLANGUAGE_EXPORT IndexedIdentifier
44     : public ReferenceCountManager
45 {
46 public:
47     IndexedIdentifier();
48     explicit IndexedIdentifier(const Identifier& id);
49     IndexedIdentifier(const IndexedIdentifier& rhs);
50     IndexedIdentifier(IndexedIdentifier&& rhs) Q_DECL_NOEXCEPT;
51     IndexedIdentifier& operator=(const Identifier& id);
52     IndexedIdentifier& operator=(const IndexedIdentifier& rhs);
53     IndexedIdentifier& operator=(IndexedIdentifier&& rhs) Q_DECL_NOEXCEPT;
54     ~IndexedIdentifier();
55     bool operator==(const IndexedIdentifier& rhs) const;
56     bool operator!=(const IndexedIdentifier& rhs) const;
57     bool operator==(const Identifier& id) const;
58 
59     bool isEmpty() const;
60 
61     Identifier identifier() const;
62     operator Identifier() const;
63 
index()64     unsigned int index() const
65     {
66         return m_index;
67     }
68 
69 private:
70     unsigned int m_index;
71 };
72 
73 /**
74  * A helper-class to store an identifier by index in a type-safe way.
75  *
76  * The difference to QualifiedIdentifier is that this class only stores the index of an identifier that is in the repository, without any dynamic
77  * abilities or access to the contained data.
78  *
79  * This class does "disk reference counting"
80  *
81  * @warning Do not use this after QCoreApplication::aboutToQuit() has been emitted, items that are not disk-referenced will be invalid at that point.
82  */
83 class KDEVPLATFORMLANGUAGE_EXPORT IndexedQualifiedIdentifier
84     : public ReferenceCountManager
85 {
86 public:
87     IndexedQualifiedIdentifier();
88     IndexedQualifiedIdentifier(const QualifiedIdentifier& id);
89     IndexedQualifiedIdentifier(const IndexedQualifiedIdentifier& rhs);
90     IndexedQualifiedIdentifier(IndexedQualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT;
91     IndexedQualifiedIdentifier& operator=(const QualifiedIdentifier& id);
92     IndexedQualifiedIdentifier& operator=(const IndexedQualifiedIdentifier& id);
93     IndexedQualifiedIdentifier& operator=(IndexedQualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT;
94     ~IndexedQualifiedIdentifier();
95     bool operator==(const IndexedQualifiedIdentifier& rhs) const;
96     bool operator==(const QualifiedIdentifier& id) const;
97 
98     bool operator<(const IndexedQualifiedIdentifier& rhs) const
99     {
100         return m_index < rhs.m_index;
101     }
102 
103     bool isValid() const;
104     bool isEmpty() const;
105 
106     QualifiedIdentifier identifier() const;
107     operator QualifiedIdentifier() const;
108 
index()109     unsigned int index() const
110     {
111         return m_index;
112     }
113 
114 private:
115     unsigned int m_index;
116 };
117 
118 /**
119  * Flags to control the string representation of identifiers.
120  */
121 enum IdentifierStringFormattingOption {
122     NoOptions = 0x0,
123 
124     /// Removes explicit global prefix from the result.
125     /// When enabled, global identifiers will be formatted as "globalIdentifierFormattedString"
126     /// instead "::globalIdentifierFormattedString".
127     RemoveExplicitlyGlobalPrefix = 0x1,
128 
129     /// Removes template information from the result.
130     /// When enabled, TemplateClass< someDataType > will be formatted as plain "TemplateClass".
131     RemoveTemplateInformation = 0x2
132 };
Q_DECLARE_FLAGS(IdentifierStringFormattingOptions,IdentifierStringFormattingOption)133 Q_DECLARE_FLAGS(IdentifierStringFormattingOptions, IdentifierStringFormattingOption)
134 
135 /**
136  * Represents a single unqualified identifier
137  */
138 class KDEVPLATFORMLANGUAGE_EXPORT Identifier
139 {
140     friend class QualifiedIdentifier;
141 
142 public:
143     /**
144      * @param start The position in the given string where to start searching for the identifier. (optional)
145      * @param takenRange If this is nonzero, it will be filled with the length of the range from the beginning
146      *                   of the given string, that was used to construct this identifier. (optional)
147      *
148      * @warning The identifier is parsed in a C++-similar way, and the result may not be what you expect.
149      *          If you want to prevent that parsing, use the constructor that takes IndexedString.
150      */
151     explicit Identifier(const QString& str, uint start = 0, uint* takenRange = nullptr);
152     /**
153      * Preferred constructor, use this if you already have an IndexedString available. This does not decompose the given string.
154      */
155     explicit Identifier(const IndexedString& str);
156     Identifier(const Identifier& rhs);
157     explicit Identifier(uint index);
158     Identifier();
159     Identifier(Identifier&& rhs) Q_DECL_NOEXCEPT;
160     ~Identifier();
161     Identifier& operator=(const Identifier& rhs);
162     Identifier& operator=(Identifier&& rhs) Q_DECL_NOEXCEPT;
163 
164     static Identifier unique(int token);
165 
166     bool isUnique() const;
167     int uniqueToken() const;
168     /**
169      * If \a token is non-zero, turns this Identifier into the special per-document unique identifier.
170      *
171      * This is used e.g. for anonymous namespaces.
172      *
173      * Pass a token which is specific to the document to allow correct equality comparison.
174      */
175     void setUnique(int token);
176 
177     const IndexedString identifier() const;
178     void setIdentifier(const QString& identifier);
179     /**
180      * Should be preferred over the other version
181      */
182     void setIdentifier(const IndexedString& identifier);
183 
184     uint hash() const;
185 
186     /**
187      * Comparison ignoring the template-identifiers
188      */
189     bool nameEquals(const Identifier& rhs) const;
190 
191     /**
192      * @warning This is expensive.
193      */
194     IndexedTypeIdentifier templateIdentifier(int num) const;
195     uint templateIdentifiersCount() const;
196     void appendTemplateIdentifier(const IndexedTypeIdentifier& identifier);
197     void clearTemplateIdentifiers();
198     void setTemplateIdentifiers(const QList<IndexedTypeIdentifier>& templateIdentifiers);
199 
200     QString toString(IdentifierStringFormattingOptions options = NoOptions) const;
201 
202     bool operator==(const Identifier& rhs) const;
203     bool operator!=(const Identifier& rhs) const;
204 
205     bool isEmpty() const;
206 
207     /**
208      * @return a unique index within the global identifier repository for this identifier.
209      *
210      * If the identifier isn't in the repository yet, it is added to the repository.
211      */
212     uint index() const;
213 
214     bool inRepository() const;
215 
216 private:
217     void makeConstant() const;
218     void prepareWrite();
219 
220     //Only one of the following pointers is valid at a given time
221     mutable uint m_index; //Valid if cd is valid
222     union {
223         mutable IdentifierPrivate<true>* dd; //Dynamic, owned by this identifier
224         mutable const IdentifierPrivate<false>* cd; //Constant, owned by the repository
225     };
226 };
227 
228 /**
229  * Represents a qualified identifier
230  *
231  * QualifiedIdentifier has it's hash-values stored, so using the hash-values is very efficient.
232  */
233 class KDEVPLATFORMLANGUAGE_EXPORT QualifiedIdentifier
234 {
235 public:
236     explicit QualifiedIdentifier(const QString& id, bool isExpression = false);
237     explicit QualifiedIdentifier(const Identifier& id);
238     QualifiedIdentifier(const QualifiedIdentifier& id);
239     explicit QualifiedIdentifier(uint index);
240     QualifiedIdentifier();
241     QualifiedIdentifier(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT;
242     ~QualifiedIdentifier();
243     QualifiedIdentifier& operator=(const QualifiedIdentifier& rhs);
244     QualifiedIdentifier& operator=(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT;
245 
246     /**
247      * Append @p id to this qualified identifier.
248      */
249     void push(const IndexedIdentifier& id);
250     /**
251      * Append @p id to this qualified identifier.
252      *
253      * NOTE: If you have an indexed identifier available, use the above method instead.
254      */
255     void push(const Identifier& id);
256     /**
257      * Append all identifiers of @p id to this qualified identifier.
258      */
259     void push(const QualifiedIdentifier& id);
260 
261     /**
262      * Pops one identifier from back:
263      */
264     void pop();
265     void clear();
266     bool isEmpty() const;
267     int count() const;
268     Identifier first() const;
269     IndexedIdentifier indexedFirst() const;
270     Identifier last() const;
271     IndexedIdentifier indexedLast() const;
272     Identifier top() const;
273     Identifier at(int i) const;
274     IndexedIdentifier indexedAt(int i) const;
275     /**
276      * @param pos Position where to start the copy.
277      * @param len If this is -1, the whole following part will be returned.
278      */
279     QualifiedIdentifier mid(int pos, int len = -1) const;
280 
281     /**
282      * Copy the leftmost \a len number of identifiers.
283      *
284      * @param len The number of identifiers to copy, or if negative, the number of identifiers to omit from the right
285      */
left(int len)286     inline QualifiedIdentifier left(int len) const
287     {
288         return mid(0, len > 0 ? len : count() + len);
289     }
290 
291     ///@todo Remove this flag
292     bool explicitlyGlobal() const;
293     void setExplicitlyGlobal(bool eg);
294     bool isQualified() const;
295 
296     /**
297      * A flag that can be set by setIsExpression
298      */
299     bool isExpression() const;
300     /**
301      * Set the expression-flag, that can be retrieved by isExpression().
302      * This flag is not respected while creating the hash-value and while operator==() comparison.
303      * It is respected while isSame(..) comparison.
304      */
305     void setIsExpression(bool);
306 
307     QString toString(IdentifierStringFormattingOptions options = NoOptions) const;
308     QStringList toStringList(IdentifierStringFormattingOptions options = NoOptions) const;
309 
310     QualifiedIdentifier operator+(const QualifiedIdentifier& rhs) const;
311     QualifiedIdentifier& operator+=(const QualifiedIdentifier& rhs);
312 
313     /**
314      * Nicer interfaces to merge
315      */
316     QualifiedIdentifier operator+(const Identifier& rhs) const;
317     QualifiedIdentifier& operator+=(const Identifier& rhs);
318 
319     QualifiedIdentifier operator+(const IndexedIdentifier& rhs) const;
320     QualifiedIdentifier& operator+=(const IndexedIdentifier& rhs);
321 
322     /**
323      * @return a QualifiedIdentifier with this one appended to the other.
324      *
325      * It is explicitly global if either this or base is.
326      */
327     QualifiedIdentifier merge(const QualifiedIdentifier& base) const;
328 
329     /**
330      * The comparison-operators do not respect explicitlyGlobal and isExpression, they only respect the real scope.
331      * This is for convenient use in hash-tables etc.
332      */
333     bool operator==(const QualifiedIdentifier& rhs) const;
334     bool operator!=(const QualifiedIdentifier& rhs) const;
335 
336     bool beginsWith(const QualifiedIdentifier& other) const;
337 
338     uint index() const;
339 
340     /**
341      * @return true if this qualified identifier is already in the persistent identifier repository
342      */
343     bool inRepository() const;
344 
345     /**
346      * The hash does not respect explicitlyGlobal, only the real scope.
347      */
348     uint hash() const;
349 
350 protected:
351     bool sameIdentifiers(const QualifiedIdentifier& rhs) const;
352 
353     void makeConstant() const;
354     void prepareWrite();
355 
356     mutable uint m_index;
357     union {
358         mutable QualifiedIdentifierPrivate<true>* dd;
359         mutable const QualifiedIdentifierPrivate<false>* cd;
360     };
361 };
362 
363 /**
364  * Extends IndexedQualifiedIdentifier by:
365  * - Arbitrary count of pointer-poperators with cv-qualifiers
366  * - Reference operator
367  * All the properties set here are respected in the hash value.
368  */
369 class KDEVPLATFORMLANGUAGE_EXPORT IndexedTypeIdentifier
370 {
371 public:
372     /**
373      * Variables like pointerDepth, isReference, etc. are not parsed from the string, so this parsing is quite limited.
374      */
375     explicit IndexedTypeIdentifier(const IndexedQualifiedIdentifier& identifier = IndexedQualifiedIdentifier());
376     explicit IndexedTypeIdentifier(const QString& identifer, bool isExpression = false);
377 
378     bool isReference() const;
379     void setIsReference(bool);
380 
381     bool isRValue() const;
382     void setIsRValue(bool);
383 
384     bool isConstant() const;
385     void setIsConstant(bool);
386 
387     bool isVolatile() const;
388     void setIsVolatile(bool);
389 
390     IndexedQualifiedIdentifier identifier() const;
391 
392     void setIdentifier(const IndexedQualifiedIdentifier& id);
393 
394     /**
395      * @return the pointer depth. Example for C++: "char*" has pointer-depth 1, "char***" has pointer-depth 3
396      */
397     int pointerDepth() const;
398     /**
399      * Sets the pointer-depth to the specified count.
400      *
401      * When the pointer-depth is increased, the "isConstPointer" values for new depths will be initialized with false.
402      *
403      * For efficiency-reasons the maximum currently is 23.
404      */
405     void setPointerDepth(int);
406 
407     /**
408      * Whether the target of pointer 'depthNumber' is constant
409      */
410     bool isConstPointer(int depthNumber) const;
411     void setIsConstPointer(int depthNumber, bool constant);
412 
413     QString toString(IdentifierStringFormattingOptions options = NoOptions) const;
414 
415     uint hash() const;
416 
417     /**
418      * The comparison-operators do not respect explicitlyGlobal and isExpression, they only respect the real scope.
419      * This is for convenient use in hash-tables etc.
420      */
421     bool operator==(const IndexedTypeIdentifier& rhs) const;
422     bool operator!=(const IndexedTypeIdentifier& rhs) const;
423 
424 private:
425     IndexedQualifiedIdentifier m_identifier;
426     // The overall number of bits shared by these bit-fields should not exceed 32,
427     // so that we don't waste space. IndexedTypeIdentifer should be as compact as possible.
428     bool m_isConstant : 1;
429     bool m_isReference : 1;
430     bool m_isRValue : 1;
431     bool m_isVolatile : 1;
432     uint m_pointerDepth : 5;
433     uint m_pointerConstMask : 23;
434 };
435 
436 KDEVPLATFORMLANGUAGE_EXPORT uint qHash(const IndexedTypeIdentifier& id);
437 KDEVPLATFORMLANGUAGE_EXPORT uint qHash(const QualifiedIdentifier& id);
438 KDEVPLATFORMLANGUAGE_EXPORT uint qHash(const Identifier& id);
439 
qHash(const IndexedIdentifier & id)440 inline uint qHash(const IndexedIdentifier& id)
441 {
442     return id.index();
443 }
444 
qHash(const IndexedQualifiedIdentifier & id)445 inline uint qHash(const IndexedQualifiedIdentifier& id)
446 {
447     return id.index();
448 }
449 }
450 
451 Q_DECLARE_TYPEINFO(KDevelop::IndexedTypeIdentifier, Q_MOVABLE_TYPE);
452 Q_DECLARE_TYPEINFO(KDevelop::IndexedQualifiedIdentifier, Q_MOVABLE_TYPE);
453 Q_DECLARE_TYPEINFO(KDevelop::IndexedIdentifier, Q_MOVABLE_TYPE);
454 Q_DECLARE_METATYPE(KDevelop::IndexedQualifiedIdentifier)
455 Q_DECLARE_METATYPE(KDevelop::IndexedIdentifier)
456 
457 Q_DECLARE_TYPEINFO(KDevelop::QualifiedIdentifier, Q_MOVABLE_TYPE);
458 Q_DECLARE_TYPEINFO(KDevelop::Identifier, Q_MOVABLE_TYPE);
459 Q_DECLARE_METATYPE(KDevelop::QualifiedIdentifier)
460 Q_DECLARE_METATYPE(KDevelop::Identifier)
461 
462 /**
463  * {q,k}Debug() stream operator: Writes the Identifier to the debug output.
464  */
465 KDEVPLATFORMLANGUAGE_EXPORT QDebug operator<<(QDebug s, const KDevelop::Identifier& identifier);
466 
467 /**
468  * {q,k}Debug() stream operator: Writes the QualifiedIdentifier to the debug output.
469  */
470 KDEVPLATFORMLANGUAGE_EXPORT QDebug operator<<(QDebug s, const KDevelop::QualifiedIdentifier& identifier);
471 
472 #endif // KDEVPLATFORM_IDENTIFIER_H
473