Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
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 Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include <QMetaObject> |
43 | #include "codemarker.h" |
44 | #include "config.h" |
45 | #include "node.h" |
46 | |
47 | #include <stdio.h> |
48 | |
49 | QT_BEGIN_NAMESPACE |
50 | |
51 | QString CodeMarker::defaultLang; |
52 | QList<CodeMarker *> CodeMarker::markers; |
53 | |
54 | /*! |
55 | When a code marker constructs itself, it puts itself into |
56 | the static list of code markers. All the code markers in |
57 | the static list get initialized in initialize(), which is |
58 | not called until after the qdoc configuration file has |
59 | been read. |
60 | */ |
61 | CodeMarker::CodeMarker() |
62 | { |
63 | markers.prepend(this); |
64 | } |
65 | |
66 | /*! |
67 | When a code marker destroys itself, it removes itself from |
68 | the static list of code markers. |
69 | */ |
70 | CodeMarker::~CodeMarker() |
71 | { |
72 | markers.removeAll(this); |
73 | } |
74 | |
75 | /*! |
76 | A code market performs no initialization by default. Marker-specific |
77 | initialization is performed in subclasses. |
78 | */ |
79 | void CodeMarker::initializeMarker(const Config& ) // config |
80 | { |
81 | } |
82 | |
83 | /*! |
84 | Terminating a code marker is trivial. |
85 | */ |
86 | void CodeMarker::terminateMarker() |
87 | { |
88 | // nothing. |
89 | } |
90 | |
91 | /*! |
92 | All the code markers in the static list are initialized |
93 | here, after the qdoc configuration file has been loaded. |
94 | */ |
95 | void CodeMarker::initialize(const Config& config) |
96 | { |
97 | defaultLang = config.getString(QLatin1String(CONFIG_LANGUAGE)); |
98 | QList<CodeMarker *>::ConstIterator m = markers.begin(); |
99 | while (m != markers.end()) { |
100 | (*m)->initializeMarker(config); |
101 | ++m; |
102 | } |
103 | } |
104 | |
105 | /*! |
106 | All the code markers in the static list are terminated here. |
107 | */ |
108 | void CodeMarker::terminate() |
109 | { |
110 | QList<CodeMarker *>::ConstIterator m = markers.begin(); |
111 | while (m != markers.end()) { |
112 | (*m)->terminateMarker(); |
113 | ++m; |
114 | } |
115 | } |
116 | |
117 | CodeMarker *CodeMarker::markerForCode(const QString& code) |
118 | { |
119 | CodeMarker *defaultMarker = markerForLanguage(defaultLang); |
120 | if (defaultMarker != 0 && defaultMarker->recognizeCode(code)) |
121 | return defaultMarker; |
122 | |
123 | QList<CodeMarker *>::ConstIterator m = markers.begin(); |
124 | while (m != markers.end()) { |
125 | if ((*m)->recognizeCode(code)) |
126 | return *m; |
127 | ++m; |
128 | } |
129 | return defaultMarker; |
130 | } |
131 | |
132 | CodeMarker *CodeMarker::markerForFileName(const QString& fileName) |
133 | { |
134 | CodeMarker *defaultMarker = markerForLanguage(defaultLang); |
135 | int dot = -1; |
136 | while ((dot = fileName.lastIndexOf(QLatin1Char( |
137 | QString ext = fileName.mid(dot + 1); |
138 | if (defaultMarker != 0 && defaultMarker->recognizeExtension(ext)) |
139 | return defaultMarker; |
140 | QList<CodeMarker *>::ConstIterator m = markers.begin(); |
141 | while (m != markers.end()) { |
142 | if ((*m)->recognizeExtension(ext)) |
143 | return *m; |
144 | ++m; |
145 | } |
146 | --dot; |
147 | } |
148 | return defaultMarker; |
149 | } |
150 | |
151 | CodeMarker *CodeMarker::markerForLanguage(const QString& lang) |
152 | { |
153 | QList<CodeMarker *>::ConstIterator m = markers.begin(); |
154 | while (m != markers.end()) { |
155 | if ((*m)->recognizeLanguage(lang)) |
156 | return *m; |
157 | ++m; |
158 | } |
159 | return 0; |
160 | } |
161 | |
162 | const Node *CodeMarker::nodeForString(const QString& string) |
163 | { |
164 | if (sizeof(const Node *) == sizeof(uint)) { |
165 | return reinterpret_cast<const Node *>(string.toUInt()); |
166 | } |
167 | else { |
168 | return reinterpret_cast<const Node *>(string.toULongLong()); |
169 | } |
170 | } |
171 | |
172 | QString CodeMarker::stringForNode(const Node *node) |
173 | { |
174 | if (sizeof(const Node *) == sizeof(ulong)) { |
175 | return QString::number(reinterpret_cast<quintptr>(node)); |
176 | } |
177 | else { |
178 | return QString::number(reinterpret_cast<qulonglong>(node)); |
179 | } |
180 | } |
181 | |
182 | static const QString samp = QLatin1String("&"); |
183 | static const QString slt = QLatin1String("<"); |
184 | static const QString sgt = QLatin1String(">"); |
185 | static const QString squot = QLatin1String("""); |
186 | |
187 | QString CodeMarker::protect(const QString& str) |
188 | { |
189 | int n = str.length(); |
190 | QString marked; |
191 | marked.reserve(n * 2 + 30); |
192 | const QChar *data = str.constData(); |
193 | for (int i = 0; i != n; ++i) { |
194 | switch (data[i].unicode()) { |
195 | case |
196 | case |
197 | case |
198 | case |
199 | default : marked += data[i]; |
200 | } |
201 | } |
202 | return marked; |
203 | } |
204 | |
205 | QString CodeMarker::typified(const QString &string) |
206 | { |
207 | QString result; |
208 | QString pendingWord; |
209 | |
210 | for (int i = 0; i <= string.size(); ++i) { |
211 | QChar ch; |
212 | if (i != string.size()) |
213 | ch = string.at(i); |
214 | |
215 | QChar lower = ch.toLower(); |
216 | if ((lower >= QLatin1Char( |
217 | || ch.digitValue() >= 0 || ch == QLatin1Char( |
218 | || ch == QLatin1Char( |
219 | pendingWord += ch; |
220 | } |
221 | else { |
222 | if (!pendingWord.isEmpty()) { |
223 | bool isProbablyType = (pendingWord != QLatin1String("const")); |
224 | if (isProbablyType) |
225 | result += QLatin1String("<@type>"); |
226 | result += pendingWord; |
227 | if (isProbablyType) |
228 | result += QLatin1String("</@type>"); |
229 | } |
230 | pendingWord.clear(); |
231 | |
232 | switch (ch.unicode()) { |
233 | case |
234 | break; |
235 | case |
236 | result += QLatin1String("&"); |
237 | break; |
238 | case |
239 | result += QLatin1String("<"); |
240 | break; |
241 | case |
242 | result += QLatin1String(">"); |
243 | break; |
244 | default: |
245 | result += ch; |
246 | } |
247 | } |
248 | } |
249 | return result; |
250 | } |
251 | |
252 | QString CodeMarker::taggedNode(const Node* node) |
253 | { |
254 | QString tag; |
255 | QString name = node->name(); |
256 | |
257 | switch (node->type()) { |
258 | case Node::Namespace: |
259 | tag = QLatin1String("@namespace"); |
260 | break; |
261 | case Node::Class: |
262 | tag = QLatin1String("@class"); |
263 | break; |
264 | case Node::Enum: |
265 | tag = QLatin1String("@enum"); |
266 | break; |
267 | case Node::Typedef: |
268 | tag = QLatin1String("@typedef"); |
269 | break; |
270 | case Node::Function: |
271 | tag = QLatin1String("@function"); |
272 | break; |
273 | case Node::Property: |
274 | tag = QLatin1String("@property"); |
275 | break; |
276 | #ifdef QDOC_QML |
277 | case Node::Fake: |
278 | if (node->subType() == Node::QmlClass) { |
279 | if (node->name().startsWith(QLatin1String("QML:"))) |
280 | name = name.mid(4); // remove the "QML:" prefix |
281 | } |
282 | tag = QLatin1String("@property"); |
283 | break; |
284 | #endif |
285 | default: |
286 | tag = QLatin1String("@unknown"); |
287 | break; |
288 | } |
289 | return QLatin1Char( |
290 | + QLatin1String("</") + tag + QLatin1Char( |
291 | } |
292 | |
293 | #ifdef QDOC_QML |
294 | QString CodeMarker::taggedQmlNode(const Node* node) |
295 | { |
296 | QString tag; |
297 | switch (node->type()) { |
298 | case Node::QmlProperty: |
299 | tag = QLatin1String("@property"); |
300 | break; |
301 | case Node::QmlSignal: |
302 | tag = QLatin1String("@signal"); |
303 | break; |
304 | case Node::QmlMethod: |
305 | tag = QLatin1String("@method"); |
306 | break; |
307 | default: |
308 | tag = QLatin1String("@unknown"); |
309 | break; |
310 | } |
311 | return QLatin1Char( |
312 | + QLatin1String("</") + tag + QLatin1Char( |
313 | } |
314 | #endif |
315 | |
316 | QString CodeMarker::linkTag(const Node *node, const QString& body) |
317 | { |
318 | return QLatin1String("<@link node=\"") + stringForNode(node) |
319 | + QLatin1String("\">") + body + QLatin1String( "</@link>"); |
320 | } |
321 | |
322 | QString CodeMarker::sortName(const Node *node) |
323 | { |
324 | QString nodeName = node->name(); |
325 | int numDigits = 0; |
326 | for (int i = nodeName.size() - 1; i > 0; --i) { |
327 | if (nodeName.at(i).digitValue() == -1) |
328 | break; |
329 | ++numDigits; |
330 | } |
331 | |
332 | // we want 'qint8' to appear before 'qint16' |
333 | if (numDigits > 0) { |
334 | for (int i = 0; i < 4 - numDigits; ++i) |
335 | nodeName.insert(nodeName.size()-numDigits-1, QLatin1String("0")); |
336 | } |
337 | |
338 | if (node->type() == Node::Function) { |
339 | const FunctionNode *func = static_cast<const FunctionNode *>(node); |
340 | QString sortNo; |
341 | if (func->metaness() == FunctionNode::Ctor) { |
342 | sortNo = QLatin1String("C"); |
343 | } |
344 | else if (func->metaness() == FunctionNode::Dtor) { |
345 | sortNo = QLatin1String("D"); |
346 | } |
347 | else { |
348 | if (nodeName.startsWith(QLatin1String("operator")) |
349 | && nodeName.length() > 8 |
350 | && !nodeName[8].isLetterOrNumber()) |
351 | sortNo = QLatin1String("F"); |
352 | else |
353 | sortNo = QLatin1String("E"); |
354 | } |
355 | return sortNo + nodeName + QLatin1Char( |
356 | + QString::number(func->overloadNumber(), 36); |
357 | } |
358 | |
359 | if (node->type() == Node::Class) |
360 | return QLatin1Char( |
361 | |
362 | if (node->type() == Node::Property || node->type() == Node::Variable) |
363 | return QLatin1Char( |
364 | |
365 | return QLatin1Char( |
366 | } |
367 | |
368 | void CodeMarker::insert(FastSection &fastSection, |
369 | Node *node, |
370 | SynopsisStyle style, |
371 | Status status) |
372 | { |
373 | bool irrelevant = false; |
374 | bool inheritedMember = false; |
375 | if (!node->relates()) { |
376 | if (node->parent() != (const InnerNode*)fastSection.innerNode) { |
377 | if (node->type() != Node::QmlProperty) |
378 | inheritedMember = true; |
379 | } |
380 | } |
381 | |
382 | if (node->access() == Node::Private) { |
383 | irrelevant = true; |
384 | } |
385 | else if (node->type() == Node::Function) { |
386 | FunctionNode *func = (FunctionNode *) node; |
387 | irrelevant = (inheritedMember |
388 | && (func->metaness() == FunctionNode::Ctor || |
389 | func->metaness() == FunctionNode::Dtor)); |
390 | } |
391 | else if (node->type() == Node::Class || node->type() == Node::Enum |
392 | || node->type() == Node::Typedef) { |
393 | irrelevant = (inheritedMember && style != SeparateList); |
394 | if (!irrelevant && style == Detailed && node->type() == Node::Typedef) { |
395 | const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node); |
396 | if (typedeffe->associatedEnum()) |
397 | irrelevant = true; |
398 | } |
399 | } |
400 | |
401 | if (!irrelevant) { |
402 | if (status == Compat) { |
403 | irrelevant = (node->status() != Node::Compat); |
404 | } |
405 | else if (status == Obsolete) { |
406 | irrelevant = (node->status() != Node::Obsolete); |
407 | } |
408 | else { |
409 | irrelevant = (node->status() == Node::Compat || |
410 | node->status() == Node::Obsolete); |
411 | } |
412 | } |
413 | |
414 | if (!irrelevant) { |
415 | if (!inheritedMember || style == SeparateList) { |
416 | QString key = sortName(node); |
417 | if (!fastSection.memberMap.contains(key)) |
418 | fastSection.memberMap.insert(key, node); |
419 | } |
420 | else { |
421 | if (node->parent()->type() == Node::Class) { |
422 | if (fastSection.inherited.isEmpty() |
423 | || fastSection.inherited.last().first != node->parent()) { |
424 | QPair<ClassNode *, int> p((ClassNode *)node->parent(), 0); |
425 | fastSection.inherited.append(p); |
426 | } |
427 | fastSection.inherited.last().second++; |
428 | } |
429 | } |
430 | } |
431 | } |
432 | |
433 | /*! |
434 | Returns true if \a node represents a reimplemented member function. |
435 | If it is, then it is inserted in the reimplemented member map in the |
436 | section \a fs. And, the test is only performed if \a status is \e OK. |
437 | Otherwise, false is returned. |
438 | */ |
439 | bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status) |
440 | { |
441 | if (node->access() == Node::Private) |
442 | return false; |
443 | |
444 | const FunctionNode* fn = static_cast<const FunctionNode*>(node); |
445 | if ((fn->reimplementedFrom() != 0) && (status == Okay)) { |
446 | bool inherited = (!fn->relates() && (fn->parent() != (const InnerNode*)fs.innerNode)); |
447 | if (!inherited) { |
448 | QString key = sortName(fn); |
449 | if (!fs.reimpMemberMap.contains(key)) { |
450 | fs.reimpMemberMap.insert(key,node); |
451 | return true; |
452 | } |
453 | } |
454 | } |
455 | return false; |
456 | } |
457 | |
458 | /*! |
459 | If \a fs is not empty, convert it to a Section and append |
460 | the new Section to \a sectionList. |
461 | */ |
462 | void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs) |
463 | { |
464 | if (!fs.isEmpty()) { |
465 | Section section(fs.name,fs.divClass,fs.singularMember,fs.pluralMember); |
466 | section.members = fs.memberMap.values(); |
467 | section.reimpMembers = fs.reimpMemberMap.values(); |
468 | section.inherited = fs.inherited; |
469 | sectionList.append(section); |
470 | } |
471 | } |
472 | |
473 | static QString encode(const QString &string) |
474 | { |
475 | #if 0 |
476 | QString result = string; |
477 | |
478 | for (int i = string.size() - 1; i >= 0; --i) { |
479 | uint ch = string.at(i).unicode(); |
480 | if (ch > 0xFF) |
481 | ch = |
482 | if ((ch - |
483 | && ch != |
484 | && ch != |
485 | && ch != |
486 | result.replace(i, 1, QString("%") + QString( "%1").arg(ch, 2, 16)); |
487 | } |
488 | return result; |
489 | #else |
490 | return string; |
491 | #endif |
492 | } |
493 | |
494 | QStringList CodeMarker::macRefsForNode(Node *node) |
495 | { |
496 | QString result = QLatin1String("cpp/"); |
497 | switch (node->type()) { |
498 | case Node::Class: |
499 | { |
500 | const ClassNode *classe = static_cast<const ClassNode *>(node); |
501 | #if 0 |
502 | if (!classe->templateStuff().isEmpty()) { |
503 | result += QLatin1String("tmplt/"); |
504 | } |
505 | else |
506 | #endif |
507 | { |
508 | result += QLatin1String("cl/"); |
509 | } |
510 | result += macName(classe); // ### Maybe plainName? |
511 | } |
512 | break; |
513 | case Node::Enum: |
514 | { |
515 | QStringList stringList; |
516 | stringList << encode(result + QLatin1String("tag/") + |
517 | macName(node)); |
518 | foreach (const QString &enumName, node->doc().enumItemNames()) { |
519 | // ### Write a plainEnumValue() and use it here |
520 | stringList << encode(result + QLatin1String("econst/") + |
521 | macName(node->parent(), enumName)); |
522 | } |
523 | return stringList; |
524 | } |
525 | case Node::Typedef: |
526 | result += QLatin1String("tdef/") + macName(node); |
527 | break; |
528 | case Node::Function: |
529 | { |
530 | const FunctionNode *func = static_cast<const FunctionNode *>(node); |
531 | |
532 | // overloads are too clever for the Xcode documentation browser |
533 | if (func->isOverload()) |
534 | return QStringList(); |
535 | |
536 | if (func->metaness() == FunctionNode::MacroWithParams |
537 | || func->metaness() == FunctionNode::MacroWithoutParams) { |
538 | result += QLatin1String("macro/"); |
539 | #if 0 |
540 | } |
541 | else if (!func->templateStuff().isEmpty()) { |
542 | result += QLatin1String("ftmplt/"); |
543 | #endif |
544 | } |
545 | else if (func->isStatic()) { |
546 | result += QLatin1String("clm/"); |
547 | } |
548 | else if (!func->parent()->name().isEmpty()) { |
549 | result += QLatin1String("instm/"); |
550 | } |
551 | else { |
552 | result += QLatin1String("func/"); |
553 | } |
554 | |
555 | result += macName(func); |
556 | if (result.endsWith(QLatin1String("()"))) |
557 | result.chop(2); |
558 | #if 0 |
559 | // this code is too clever for the Xcode documentation |
560 | // browser and/or pbhelpindexer |
561 | if (!isMacro) { |
562 | result += "/"+ QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/("; |
563 | const QList<Parameter> ¶ms = func->parameters(); |
564 | for (int i = 0; i < params.count(); ++i) { |
565 | QString type = params.at(i).leftType() + |
566 | params.at(i).rightType(); |
567 | type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData())); |
568 | if (i != 0) |
569 | result += ","; |
570 | result += type; |
571 | } |
572 | result += ")"; |
573 | } |
574 | #endif |
575 | } |
576 | break; |
577 | case Node::Variable: |
578 | result += QLatin1String("data/") + macName(node); |
579 | break; |
580 | case Node::Property: |
581 | { |
582 | NodeList list = static_cast<const PropertyNode*>(node)->functions(); |
583 | QStringList stringList; |
584 | foreach (Node* node, list) { |
585 | stringList += macRefsForNode(node); |
586 | } |
587 | return stringList; |
588 | } |
589 | case Node::Namespace: |
590 | case Node::Fake: |
591 | case Node::Target: |
592 | default: |
593 | return QStringList(); |
594 | } |
595 | |
596 | return QStringList(encode(result)); |
597 | } |
598 | |
599 | QString CodeMarker::macName(const Node *node, const QString &name) |
600 | { |
601 | QString myName = name; |
602 | if (myName.isEmpty()) { |
603 | myName = node->name(); |
604 | node = node->parent(); |
605 | } |
606 | |
607 | if (node->name().isEmpty()) { |
608 | return QLatin1Char( |
609 | } |
610 | else { |
611 | return plainFullName(node) + QLatin1Char( |
612 | } |
613 | } |
614 | |
615 | #ifdef QDOC_QML |
616 | /*! |
617 | Get the list of documentation sections for the children of |
618 | the specified QmlClassNode. |
619 | */ |
620 | QList<Section> CodeMarker::qmlSections(const QmlClassNode* , |
621 | SynopsisStyle , |
622 | const Tree* ) |
623 | { |
624 | return QList<Section>(); |
625 | } |
626 | #endif |
627 | |
628 | const Node* CodeMarker::resolveTarget(const QString& , |
629 | const Tree* , |
630 | const Node* , |
631 | const Node* ) |
632 | { |
633 | return 0; |
634 | } |
635 | |
636 | QT_END_NAMESPACE |
637 |
Warning: That file was not part of the compilation database. It may have many parsing errors.