1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the qmake application of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #ifndef PROITEMS_H |
30 | #define PROITEMS_H |
31 | |
32 | #include "qmake_global.h" |
33 | |
34 | #include <qdebug.h> |
35 | #include <qstring.h> |
36 | #include <qvector.h> |
37 | #include <qhash.h> |
38 | |
39 | QT_BEGIN_NAMESPACE |
40 | |
41 | class QTextStream; |
42 | |
43 | #ifdef PROPARSER_THREAD_SAFE |
44 | typedef QAtomicInt ProItemRefCount; |
45 | #else |
46 | class ProItemRefCount { |
47 | public: |
48 | ProItemRefCount(int cnt = 0) : m_cnt(cnt) {} |
49 | bool ref() { return ++m_cnt != 0; } |
50 | bool deref() { return --m_cnt != 0; } |
51 | ProItemRefCount &operator=(int value) { m_cnt = value; return *this; } |
52 | private: |
53 | int m_cnt; |
54 | }; |
55 | #endif |
56 | |
57 | #ifndef QT_BUILD_QMAKE |
58 | # define PROITEM_EXPLICIT explicit |
59 | #else |
60 | # define PROITEM_EXPLICIT |
61 | #endif |
62 | |
63 | class ProKey; |
64 | class ProStringList; |
65 | class ProFile; |
66 | |
67 | class ProString { |
68 | public: |
69 | ProString(); |
70 | ProString(const ProString &other); |
71 | ProString &operator=(const ProString &) = default; |
72 | PROITEM_EXPLICIT ProString(const QString &str); |
73 | PROITEM_EXPLICIT ProString(const QStringRef &str); |
74 | PROITEM_EXPLICIT ProString(const char *str); |
75 | ProString(const QString &str, int offset, int length); |
76 | void setValue(const QString &str); |
77 | void clear() { m_string.clear(); m_length = 0; } |
78 | ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; } |
79 | ProString &setSource(int id) { m_file = id; return *this; } |
80 | int sourceFile() const { return m_file; } |
81 | |
82 | ProString &prepend(const ProString &other); |
83 | ProString &append(const ProString &other, bool *pending = nullptr); |
84 | ProString &append(const QString &other) { return append(other: ProString(other)); } |
85 | ProString &append(const QLatin1String other); |
86 | ProString &append(const char *other) { return append(other: QLatin1String(other)); } |
87 | ProString &append(QChar other); |
88 | ProString &append(const ProStringList &other, bool *pending = nullptr, bool skipEmpty1st = false); |
89 | ProString &operator+=(const ProString &other) { return append(other); } |
90 | ProString &operator+=(const QString &other) { return append(other); } |
91 | ProString &operator+=(const QLatin1String other) { return append(other); } |
92 | ProString &operator+=(const char *other) { return append(other); } |
93 | ProString &operator+=(QChar other) { return append(other); } |
94 | |
95 | void chop(int n) { Q_ASSERT(n <= m_length); m_length -= n; } |
96 | void chopFront(int n) { Q_ASSERT(n <= m_length); m_offset += n; m_length -= n; } |
97 | |
98 | bool operator==(const ProString &other) const { return toQStringRef() == other.toQStringRef(); } |
99 | bool operator==(const QString &other) const { return toQStringRef() == other; } |
100 | bool operator==(const QStringRef &other) const { return toQStringRef() == other; } |
101 | bool operator==(QLatin1String other) const { return toQStringRef() == other; } |
102 | bool operator==(const char *other) const { return toQStringRef() == QLatin1String(other); } |
103 | bool operator!=(const ProString &other) const { return !(*this == other); } |
104 | bool operator!=(const QString &other) const { return !(*this == other); } |
105 | bool operator!=(QLatin1String other) const { return !(*this == other); } |
106 | bool operator!=(const char *other) const { return !(*this == other); } |
107 | bool operator<(const ProString &other) const { return toQStringRef() < other.toQStringRef(); } |
108 | bool isNull() const { return m_string.isNull(); } |
109 | bool isEmpty() const { return !m_length; } |
110 | int length() const { return m_length; } |
111 | int size() const { return m_length; } |
112 | QChar at(int i) const { Q_ASSERT((uint)i < (uint)m_length); return constData()[i]; } |
113 | const QChar *constData() const { return m_string.constData() + m_offset; } |
114 | ProString mid(int off, int len = -1) const; |
115 | ProString left(int len) const { return mid(off: 0, len); } |
116 | ProString right(int len) const { return mid(off: qMax(a: 0, b: size() - len)); } |
117 | ProString trimmed() const; |
118 | int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(s: sub.toQStringRef(), cs); } |
119 | int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(s: sub, cs); } |
120 | int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(s: QLatin1String(sub), cs); } |
121 | bool startsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(c: sub.toQStringRef(), cs); } |
122 | bool startsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(s: sub, cs); } |
123 | bool startsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(s: QLatin1String(sub), cs); } |
124 | bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(c, cs); } |
125 | bool endsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(c: sub.toQStringRef(), cs); } |
126 | bool endsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(s: sub, cs); } |
127 | bool endsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(s: QLatin1String(sub), cs); } |
128 | bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(c, cs); } |
129 | int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(str: s, from, cs); } |
130 | int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(str: QLatin1String(s), from, cs); } |
131 | int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(ch: c, from, cs); } |
132 | int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(str: s, from, cs); } |
133 | int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(str: QLatin1String(s), from, cs); } |
134 | int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(ch: c, from, cs); } |
135 | bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, from: 0, cs) >= 0; } |
136 | bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s: QLatin1String(s), from: 0, cs) >= 0; } |
137 | bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, from: 0, cs) >= 0; } |
138 | qlonglong toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringRef().toLongLong(ok, base); } |
139 | int toInt(bool *ok = nullptr, int base = 10) const { return toQStringRef().toInt(ok, base); } |
140 | short toShort(bool *ok = nullptr, int base = 10) const { return toQStringRef().toShort(ok, base); } |
141 | |
142 | uint hash() const { return m_hash; } |
143 | static uint hash(const QChar *p, int n); |
144 | |
145 | ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); } |
146 | ALWAYS_INLINE QStringView toQStringView() const { return QStringView(m_string).mid(pos: m_offset, n: m_length); } |
147 | |
148 | ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; } |
149 | ALWAYS_INLINE const ProKey &toKey() const { return *(const ProKey *)this; } |
150 | |
151 | QString toQString() const; |
152 | QString &toQString(QString &tmp) const; |
153 | |
154 | QByteArray toLatin1() const { return toQStringRef().toLatin1(); } |
155 | |
156 | private: |
157 | ProString(const ProKey &other); |
158 | ProString &operator=(const ProKey &other); |
159 | |
160 | enum OmitPreHashing { NoHash }; |
161 | ProString(const ProString &other, OmitPreHashing); |
162 | |
163 | enum DoPreHashing { DoHash }; |
164 | ALWAYS_INLINE ProString(const QString &str, DoPreHashing); |
165 | ALWAYS_INLINE ProString(const char *str, DoPreHashing); |
166 | ALWAYS_INLINE ProString(const QString &str, int offset, int length, DoPreHashing); |
167 | ALWAYS_INLINE ProString(const QString &str, int offset, int length, uint hash); |
168 | |
169 | QString m_string; |
170 | int m_offset, m_length; |
171 | int m_file; |
172 | mutable uint m_hash; |
173 | QChar *prepareExtend(int , int thisTarget, int ); |
174 | uint updatedHash() const; |
175 | friend uint qHash(const ProString &str); |
176 | friend QString operator+(const ProString &one, const ProString &two); |
177 | friend class ProKey; |
178 | }; |
179 | Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE); |
180 | |
181 | class ProKey : public ProString { |
182 | public: |
183 | ALWAYS_INLINE ProKey() : ProString() {} |
184 | explicit ProKey(const QString &str); |
185 | PROITEM_EXPLICIT ProKey(const char *str); |
186 | ProKey(const QString &str, int off, int len); |
187 | ProKey(const QString &str, int off, int len, uint hash); |
188 | void setValue(const QString &str); |
189 | |
190 | #ifdef Q_CC_MSVC |
191 | // Workaround strange MSVC behaviour when exporting classes with ProKey members. |
192 | ALWAYS_INLINE ProKey(const ProKey &other) : ProString(other.toString()) {} |
193 | ALWAYS_INLINE ProKey &operator=(const ProKey &other) |
194 | { |
195 | toString() = other.toString(); |
196 | return *this; |
197 | } |
198 | #endif |
199 | |
200 | ALWAYS_INLINE ProString &toString() { return *(ProString *)this; } |
201 | ALWAYS_INLINE const ProString &toString() const { return *(const ProString *)this; } |
202 | |
203 | private: |
204 | ProKey(const ProString &other); |
205 | }; |
206 | Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE); |
207 | |
208 | uint qHash(const ProString &str); |
209 | QString operator+(const ProString &one, const ProString &two); |
210 | inline QString operator+(const ProString &one, const QString &two) |
211 | { return one.toQStringRef() + two; } |
212 | inline QString operator+(const QString &one, const ProString &two) |
213 | { return one + two.toQStringRef(); } |
214 | |
215 | inline QString operator+(const ProString &one, const char *two) |
216 | { return one.toQStringRef() + QLatin1String(two); } |
217 | inline QString operator+(const char *one, const ProString &two) |
218 | { return QLatin1String(one) + two.toQStringRef(); } |
219 | inline QString operator+(const ProString &one, QChar two) |
220 | { return one.toQStringRef() + two; } |
221 | inline QString operator+(QChar one, const ProString &two) |
222 | { return one + two.toQStringRef(); } |
223 | |
224 | inline QString &operator+=(QString &that, const ProString &other) |
225 | { return that += other.toQStringRef(); } |
226 | |
227 | inline bool operator==(const QString &that, const ProString &other) |
228 | { return other == that; } |
229 | inline bool operator!=(const QString &that, const ProString &other) |
230 | { return !(other == that); } |
231 | |
232 | QTextStream &operator<<(QTextStream &t, const ProString &str); |
233 | |
234 | // This class manages read-only access to a ProString via a raw data QString |
235 | // temporary, ensuring that the latter is accessed exclusively. |
236 | class ProStringRoUser |
237 | { |
238 | public: |
239 | ProStringRoUser(QString &rs) |
240 | { |
241 | Q_ASSERT(rs.isDetached() || rs.isEmpty()); |
242 | m_rs = &rs; |
243 | } |
244 | ProStringRoUser(const ProString &ps, QString &rs) |
245 | : ProStringRoUser(rs) |
246 | { |
247 | ps.toQString(tmp&: rs); |
248 | } |
249 | // No destructor, as a RAII pattern cannot be used: references to the |
250 | // temporary string can legitimately outlive instances of this class |
251 | // (if they are held by Qt, e.g. in QRegExp). |
252 | QString &set(const ProString &ps) { return ps.toQString(tmp&: *m_rs); } |
253 | QString &str() { return *m_rs; } |
254 | |
255 | protected: |
256 | QString *m_rs; |
257 | }; |
258 | |
259 | // This class manages read-write access to a ProString via a raw data QString |
260 | // temporary, ensuring that the latter is accessed exclusively, and that raw |
261 | // data does not leak outside its source's refcounting. |
262 | class ProStringRwUser : public ProStringRoUser |
263 | { |
264 | public: |
265 | ProStringRwUser(QString &rs) |
266 | : ProStringRoUser(rs), m_ps(nullptr) {} |
267 | ProStringRwUser(const ProString &ps, QString &rs) |
268 | : ProStringRoUser(ps, rs), m_ps(&ps) {} |
269 | QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); } |
270 | ProString (const QString &s) const |
271 | { return s.isSharedWith(other: *m_rs) ? *m_ps : ProString(s).setSource(*m_ps); } |
272 | ProString (const QString &s, const ProStringRwUser &other) const |
273 | { |
274 | if (other.m_ps && s.isSharedWith(other: *other.m_rs)) |
275 | return *other.m_ps; |
276 | return extract(s); |
277 | } |
278 | |
279 | private: |
280 | const ProString *m_ps; |
281 | }; |
282 | |
283 | class ProStringList : public QVector<ProString> { |
284 | public: |
285 | ProStringList() {} |
286 | ProStringList(const ProString &str) { *this << str; } |
287 | explicit ProStringList(const QStringList &list); |
288 | QStringList toQStringList() const; |
289 | |
290 | ProStringList &operator<<(const ProString &str) |
291 | { QVector<ProString>::operator<<(t: str); return *this; } |
292 | |
293 | int length() const { return size(); } |
294 | |
295 | QString join(const ProString &sep) const; |
296 | QString join(const QString &sep) const; |
297 | QString join(QChar sep) const; |
298 | |
299 | void insertUnique(const ProStringList &value); |
300 | |
301 | void removeAll(const ProString &str); |
302 | void removeAll(const char *str); |
303 | void removeEach(const ProStringList &value); |
304 | void removeAt(int idx) { remove(i: idx); } |
305 | void removeEmpty(); |
306 | void removeDuplicates(); |
307 | |
308 | bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; |
309 | bool contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; |
310 | bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const |
311 | { return contains(str: ProString(str), cs); } |
312 | bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; |
313 | }; |
314 | Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE); |
315 | |
316 | inline ProStringList operator+(const ProStringList &one, const ProStringList &two) |
317 | { ProStringList ret = one; ret += two; return ret; } |
318 | |
319 | typedef QHash<ProKey, ProStringList> ProValueMap; |
320 | |
321 | // These token definitions affect both ProFileEvaluator and ProWriter |
322 | enum ProToken { |
323 | TokTerminator = 0, // end of stream (possibly not included in length; must be zero) |
324 | TokLine, // line marker: |
325 | // - line (1) |
326 | TokAssign, // variable = |
327 | TokAppend, // variable += |
328 | TokAppendUnique, // variable *= |
329 | TokRemove, // variable -= |
330 | TokReplace, // variable ~= |
331 | // previous literal/expansion is a variable manipulation |
332 | // - lower bound for expected output length (1) |
333 | // - value expression + TokValueTerminator |
334 | TokValueTerminator, // assignment value terminator |
335 | TokLiteral, // literal string (fully dequoted) |
336 | // - length (1) |
337 | // - string data (length; unterminated) |
338 | TokHashLiteral, // literal string with hash (fully dequoted) |
339 | // - hash (2) |
340 | // - length (1) |
341 | // - string data (length; unterminated) |
342 | TokVariable, // qmake variable expansion |
343 | // - hash (2) |
344 | // - name length (1) |
345 | // - name (name length; unterminated) |
346 | TokProperty, // qmake property expansion |
347 | // - hash (2) |
348 | // - name length (1) |
349 | // - name (name length; unterminated) |
350 | TokEnvVar, // environment variable expansion |
351 | // - name length (1) |
352 | // - name (name length; unterminated) |
353 | TokFuncName, // replace function expansion |
354 | // - hash (2) |
355 | // - name length (1) |
356 | // - name (name length; unterminated) |
357 | // - ((nested expansion + TokArgSeparator)* + nested expansion)? |
358 | // - TokFuncTerminator |
359 | TokArgSeparator, // function argument separator |
360 | TokFuncTerminator, // function argument list terminator |
361 | TokCondition, // previous literal/expansion is a conditional |
362 | TokTestCall, // previous literal/expansion is a test function call |
363 | // - ((nested expansion + TokArgSeparator)* + nested expansion)? |
364 | // - TokFuncTerminator |
365 | TokReturn, // previous literal/expansion is a return value |
366 | TokBreak, // break loop |
367 | TokNext, // shortcut to next loop iteration |
368 | TokNot, // '!' operator |
369 | TokAnd, // ':' operator |
370 | TokOr, // '|' operator |
371 | TokBranch, // branch point: |
372 | // - then block length (2) |
373 | // - then block + TokTerminator (then block length) |
374 | // - else block length (2) |
375 | // - else block + TokTerminator (else block length) |
376 | TokForLoop, // for loop: |
377 | // - variable name: hash (2), length (1), chars (length) |
378 | // - expression: length (2), bytes + TokValueTerminator (length) |
379 | // - body length (2) |
380 | // - body + TokTerminator (body length) |
381 | TokTestDef, // test function definition: |
382 | TokReplaceDef, // replace function definition: |
383 | // - function name: hash (2), length (1), chars (length) |
384 | // - body length (2) |
385 | // - body + TokTerminator (body length) |
386 | TokBypassNesting, // escape from function local variable scopes: |
387 | // - block length (2) |
388 | // - block + TokTerminator (block length) |
389 | TokMask = 0xff, |
390 | TokQuoted = 0x100, // The expression is quoted => join expanded stringlist |
391 | TokNewStr = 0x200 // Next stringlist element |
392 | }; |
393 | |
394 | class QMAKE_EXPORT ProFile |
395 | { |
396 | public: |
397 | ProFile(int id, const QString &fileName); |
398 | ~ProFile(); |
399 | |
400 | int id() const { return m_id; } |
401 | QString fileName() const { return m_fileName; } |
402 | QString directoryName() const { return m_directoryName; } |
403 | const QString &items() const { return m_proitems; } |
404 | QString *itemsRef() { return &m_proitems; } |
405 | const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); } |
406 | const ushort *tokPtrEnd() const { return (const ushort *)m_proitems.constData() + m_proitems.size(); } |
407 | |
408 | void ref() { m_refCount.ref(); } |
409 | void deref() { if (!m_refCount.deref()) delete this; } |
410 | |
411 | bool isOk() const { return m_ok; } |
412 | void setOk(bool ok) { m_ok = ok; } |
413 | |
414 | bool isHostBuild() const { return m_hostBuild; } |
415 | void setHostBuild(bool host_build) { m_hostBuild = host_build; } |
416 | |
417 | ProString getStr(const ushort *&tPtr); |
418 | ProKey getHashStr(const ushort *&tPtr); |
419 | |
420 | private: |
421 | ProItemRefCount m_refCount; |
422 | QString m_proitems; |
423 | QString m_fileName; |
424 | QString m_directoryName; |
425 | int m_id; |
426 | bool m_ok; |
427 | bool m_hostBuild; |
428 | }; |
429 | |
430 | class ProFunctionDef { |
431 | public: |
432 | ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); } |
433 | ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); } |
434 | ProFunctionDef(ProFunctionDef &&other) noexcept |
435 | : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; } |
436 | ~ProFunctionDef() { if (m_pro) m_pro->deref(); } |
437 | ProFunctionDef &operator=(const ProFunctionDef &o) |
438 | { |
439 | if (this != &o) { |
440 | if (m_pro) |
441 | m_pro->deref(); |
442 | m_pro = o.m_pro; |
443 | m_pro->ref(); |
444 | m_offset = o.m_offset; |
445 | } |
446 | return *this; |
447 | } |
448 | ProFunctionDef &operator=(ProFunctionDef &&other) noexcept |
449 | { |
450 | ProFunctionDef moved(std::move(other)); |
451 | swap(other&: moved); |
452 | return *this; |
453 | } |
454 | void swap(ProFunctionDef &other) noexcept |
455 | { |
456 | qSwap(value1&: m_pro, value2&: other.m_pro); |
457 | qSwap(value1&: m_offset, value2&: other.m_offset); |
458 | } |
459 | |
460 | ProFile *pro() const { return m_pro; } |
461 | const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; } |
462 | private: |
463 | ProFile *m_pro; |
464 | int m_offset; |
465 | }; |
466 | |
467 | Q_DECLARE_TYPEINFO(ProFunctionDef, Q_MOVABLE_TYPE); |
468 | |
469 | struct ProFunctionDefs { |
470 | QHash<ProKey, ProFunctionDef> testFunctions; |
471 | QHash<ProKey, ProFunctionDef> replaceFunctions; |
472 | }; |
473 | |
474 | QDebug operator<<(QDebug debug, const ProString &str); |
475 | |
476 | QT_END_NAMESPACE |
477 | |
478 | #endif // PROITEMS_H |
479 | |