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
49QT_BEGIN_NAMESPACE
50
51QString CodeMarker::defaultLang;
52QList<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 */
61CodeMarker::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 */
70CodeMarker::~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 */
79void CodeMarker::initializeMarker(const Config& ) // config
80{
81}
82
83/*!
84 Terminating a code marker is trivial.
85 */
86void 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 */
95void 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 */
108void CodeMarker::terminate()
109{
110 QList<CodeMarker *>::ConstIterator m = markers.begin();
111 while (m != markers.end()) {
112 (*m)->terminateMarker();
113 ++m;
114 }
115}
116
117CodeMarker *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
132CodeMarker *CodeMarker::markerForFileName(const QString& fileName)
133{
134 CodeMarker *defaultMarker = markerForLanguage(defaultLang);
135 int dot = -1;
136 while ((dot = fileName.lastIndexOf(QLatin1Char('.'), dot)) != -1) {
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
151CodeMarker *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
162const 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
172QString 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
182static const QString samp = QLatin1String("&amp;");
183static const QString slt = QLatin1String("&lt;");
184static const QString sgt = QLatin1String("&gt;");
185static const QString squot = QLatin1String("&quot;");
186
187QString 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 '&': marked += samp; break;
196 case '<': marked += slt; break;
197 case '>': marked += sgt; break;
198 case '"': marked += squot; break;
199 default : marked += data[i];
200 }
201 }
202 return marked;
203}
204
205QString 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('a') && lower <= QLatin1Char('z'))
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 '\0':
234 break;
235 case '&':
236 result += QLatin1String("&amp;");
237 break;
238 case '<':
239 result += QLatin1String("&lt;");
240 break;
241 case '>':
242 result += QLatin1String("&gt;");
243 break;
244 default:
245 result += ch;
246 }
247 }
248 }
249 return result;
250}
251
252QString 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('<') + tag + QLatin1Char('>') + protect(name)
290 + QLatin1String("</") + tag + QLatin1Char('>');
291}
292
293#ifdef QDOC_QML
294QString 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('<') + tag + QLatin1Char('>') + protect(node->name())
312 + QLatin1String("</") + tag + QLatin1Char('>');
313}
314#endif
315
316QString CodeMarker::linkTag(const Node *node, const QString& body)
317{
318 return QLatin1String("<@link node=\"") + stringForNode(node)
319 + QLatin1String("\">") + body + QLatin1String("</@link>");
320}
321
322QString 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('A') + nodeName;
361
362 if (node->type() == Node::Property || node->type() == Node::Variable)
363 return QLatin1Char('E') + nodeName;
364
365 return QLatin1Char('B') + nodeName;
366}
367
368void 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 */
439bool 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 */
462void 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
473static 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 - '0') >= 10 && (ch - 'a') >= 26 && (ch - 'A') >= 26
483 && ch != '/' && ch != '(' && ch != ')' && ch != ',' && ch != '*'
484 && ch != '&' && ch != '_' && ch != '<' && ch != '>' && 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
494QStringList 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> &params = 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
599QString 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('/') + protect(myName);
609 }
610 else {
611 return plainFullName(node) + QLatin1Char('/') + protect(myName);
612 }
613}
614
615#ifdef QDOC_QML
616/*!
617 Get the list of documentation sections for the children of
618 the specified QmlClassNode.
619 */
620QList<Section> CodeMarker::qmlSections(const QmlClassNode* ,
621 SynopsisStyle ,
622 const Tree* )
623{
624 return QList<Section>();
625}
626#endif
627
628const Node* CodeMarker::resolveTarget(const QString& ,
629 const Tree* ,
630 const Node* ,
631 const Node* )
632{
633 return 0;
634}
635
636QT_END_NAMESPACE
637

Warning: That file was not part of the compilation database. It may have many parsing errors.