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