qdoc: Removed several #if 0 blocks.
[profile/ivi/qtbase.git] / src / tools / qdoc / codemarker.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
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 #include <qdebug.h>
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.constBegin();
99     while (m != markers.constEnd()) {
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.constBegin();
111     while (m != markers.constEnd()) {
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.constBegin();
124     while (m != markers.constEnd()) {
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('.'), 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.constBegin();
141         while (m != markers.constEnd()) {
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.constBegin();
154     while (m != markers.constEnd()) {
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("&amp;");
183 static const QString slt   = QLatin1String("&lt;");
184 static const QString sgt   = QLatin1String("&gt;");
185 static const QString squot = QLatin1String("&quot;");
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 '&': 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
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('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
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     case Node::Fake:
277         /*
278           Remove the "QML:" prefix, if present.
279           There shouldn't be any of these "QML:"
280           prefixes in the documentation sources
281           after the switch to using QML module
282           qualifiers, but this code is kept to
283           be backward compatible.
284         */
285         if (node->subType() == Node::QmlClass) {
286             if (node->name().startsWith(QLatin1String("QML:")))
287                 name = name.mid(4);
288         }
289         tag = QLatin1String("@property");
290         break;
291     case Node::QmlMethod:
292     case Node::QmlSignal:
293     case Node::QmlSignalHandler:
294         tag = QLatin1String("@function");
295         break;
296     default:
297         tag = QLatin1String("@unknown");
298         break;
299     }
300     return (QLatin1Char('<') + tag + QLatin1Char('>') + protect(name)
301             + QLatin1String("</") + tag + QLatin1Char('>'));
302 }
303
304 QString CodeMarker::taggedQmlNode(const Node* node)
305 {
306     QString tag;
307     switch (node->type()) {
308     case Node::QmlProperty:
309         tag = QLatin1String("@property");
310         break;
311     case Node::QmlSignal:
312         tag = QLatin1String("@signal");
313         break;
314     case Node::QmlSignalHandler:
315         tag = QLatin1String("@signalhandler");
316         break;
317     case Node::QmlMethod:
318         tag = QLatin1String("@method");
319         break;
320     default:
321         tag = QLatin1String("@unknown");
322         break;
323     }
324     return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
325             + QLatin1String("</") + tag + QLatin1Char('>');
326 }
327
328 QString CodeMarker::linkTag(const Node *node, const QString& body)
329 {
330     return QLatin1String("<@link node=\"") + stringForNode(node)
331             + QLatin1String("\">") + body + QLatin1String("</@link>");
332 }
333
334 QString CodeMarker::sortName(const Node *node, const QString* name)
335 {
336     QString nodeName;
337     if (name != 0)
338         nodeName = *name;
339     else
340         nodeName = node->name();
341     int numDigits = 0;
342     for (int i = nodeName.size() - 1; i > 0; --i) {
343         if (nodeName.at(i).digitValue() == -1)
344             break;
345         ++numDigits;
346     }
347
348     // we want 'qint8' to appear before 'qint16'
349     if (numDigits > 0) {
350         for (int i = 0; i < 4 - numDigits; ++i)
351             nodeName.insert(nodeName.size()-numDigits-1, QLatin1Char('0'));
352     }
353
354     if (node->type() == Node::Function) {
355         const FunctionNode *func = static_cast<const FunctionNode *>(node);
356         QString sortNo;
357         if (func->metaness() == FunctionNode::Ctor) {
358             sortNo = QLatin1String("C");
359         }
360         else if (func->metaness() == FunctionNode::Dtor) {
361             sortNo = QLatin1String("D");
362         }
363         else {
364             if (nodeName.startsWith(QLatin1String("operator"))
365                     && nodeName.length() > 8
366                     && !nodeName[8].isLetterOrNumber())
367                 sortNo = QLatin1String("F");
368             else
369                 sortNo = QLatin1String("E");
370         }
371         return sortNo + nodeName + QLatin1Char(' ')
372                 + QString::number(func->overloadNumber(), 36);
373     }
374
375     if (node->type() == Node::Class)
376         return QLatin1Char('A') + nodeName;
377
378     if (node->type() == Node::Property || node->type() == Node::Variable)
379         return QLatin1Char('E') + nodeName;
380
381     if ((node->type() == Node::QmlMethod) ||
382         (node->type() == Node::QmlSignal) ||
383         (node->type() == Node::QmlSignalHandler)) {
384         const FunctionNode* func = static_cast<const FunctionNode *>(node);
385         return QLatin1Char('E') + func->signature();
386     }
387
388     return QLatin1Char('B') + nodeName;
389 }
390
391 void CodeMarker::insert(FastSection &fastSection,
392                         Node *node,
393                         SynopsisStyle style,
394                         Status status)
395 {
396     bool irrelevant = false;
397     bool inheritedMember = false;
398     if (!node->relates()) {
399         if (node->parent() != (const InnerNode*)fastSection.innerNode && !node->parent()->isAbstract()) {
400             if (node->type() != Node::QmlProperty) {
401                 inheritedMember = true;
402             }
403         }
404     }
405
406     if (node->access() == Node::Private) {
407         irrelevant = true;
408     }
409     else if (node->type() == Node::Function) {
410         FunctionNode *func = (FunctionNode *) node;
411         irrelevant = (inheritedMember
412                       && (func->metaness() == FunctionNode::Ctor ||
413                           func->metaness() == FunctionNode::Dtor));
414     }
415     else if (node->type() == Node::Class || node->type() == Node::Enum
416              || node->type() == Node::Typedef) {
417         irrelevant = (inheritedMember && style != Subpage);
418         if (!irrelevant && style == Detailed && node->type() == Node::Typedef) {
419             const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node);
420             if (typedeffe->associatedEnum())
421                 irrelevant = true;
422         }
423     }
424
425     if (!irrelevant) {
426         if (status == Compat) {
427             irrelevant = (node->status() != Node::Compat);
428         }
429         else if (status == Obsolete) {
430             irrelevant = (node->status() != Node::Obsolete);
431         }
432         else {
433             irrelevant = (node->status() == Node::Compat ||
434                           node->status() == Node::Obsolete);
435         }
436     }
437
438     if (!irrelevant) {
439         if (!inheritedMember || style == Subpage) {
440             QString key = sortName(node);
441             if (!fastSection.memberMap.contains(key))
442                 fastSection.memberMap.insert(key, node);
443         }
444         else {
445             if (node->parent()->type() == Node::Class) {
446                 if (fastSection.inherited.isEmpty()
447                         || fastSection.inherited.last().first != node->parent()) {
448                     QPair<InnerNode *, int> p(node->parent(), 0);
449                     fastSection.inherited.append(p);
450                 }
451                 fastSection.inherited.last().second++;
452             }
453         }
454     }
455 }
456
457 void CodeMarker::insert(FastSection& fastSection,
458                         Node* node,
459                         SynopsisStyle style,
460                         bool /* includeClassName */)
461 {
462     if (node->status() == Node::Compat || node->status() == Node::Obsolete)
463         return;
464
465     bool inheritedMember = false;
466     InnerNode* parent = node->parent();
467     if (parent && (parent->type() == Node::Fake) &&
468             (parent->subType() == Node::QmlPropertyGroup)) {
469         parent = parent->parent();
470     }
471     inheritedMember = (parent != (const InnerNode*)fastSection.innerNode);
472
473     if (!inheritedMember || style == Subpage) {
474         QString key = sortName(node);
475         if (!fastSection.memberMap.contains(key))
476             fastSection.memberMap.insert(key, node);
477     }
478     else {
479         if ((parent->type() == Node::Fake) && (parent->subType() == Node::QmlClass)) {
480             if (fastSection.inherited.isEmpty()
481                     || fastSection.inherited.last().first != parent) {
482                 QPair<InnerNode*, int> p(parent, 0);
483                 fastSection.inherited.append(p);
484             }
485             fastSection.inherited.last().second++;
486         }
487     }
488 }
489
490 /*!
491   Returns true if \a node represents a reimplemented member function.
492   If it is, then it is inserted in the reimplemented member map in the
493   section \a fs. And, the test is only performed if \a status is \e OK.
494   Otherwise, false is returned.
495  */
496 bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status)
497 {
498     if (node->access() == Node::Private)
499         return false;
500
501     const FunctionNode* fn = static_cast<const FunctionNode*>(node);
502     if ((fn->reimplementedFrom() != 0) && (status == Okay)) {
503         bool inherited = (!fn->relates() && (fn->parent() != (const InnerNode*)fs.innerNode));
504         if (!inherited) {
505             QString key = sortName(fn);
506             if (!fs.reimpMemberMap.contains(key)) {
507                 fs.reimpMemberMap.insert(key,node);
508                 return true;
509             }
510         }
511     }
512     return false;
513 }
514
515 /*!
516   If \a fs is not empty, convert it to a Section and append
517   the new Section to \a sectionList.
518  */
519 void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs, bool includeKeys)
520 {
521     if (!fs.isEmpty()) {
522         Section section(fs.name,fs.divClass,fs.singularMember,fs.pluralMember);
523         if (includeKeys) {
524             section.keys = fs.memberMap.keys();
525         }
526         section.members = fs.memberMap.values();
527         section.reimpMembers = fs.reimpMemberMap.values();
528         section.inherited = fs.inherited;
529         sectionList.append(section);
530     }
531 }
532
533 static QString encode(const QString &string)
534 {
535     return string;
536 }
537
538 QStringList CodeMarker::macRefsForNode(Node *node)
539 {
540     QString result = QLatin1String("cpp/");
541     switch (node->type()) {
542     case Node::Class:
543     {
544         const ClassNode *classe = static_cast<const ClassNode *>(node);
545         {
546             result += QLatin1String("cl/");
547         }
548         result += macName(classe); // ### Maybe plainName?
549     }
550         break;
551     case Node::Enum:
552     {
553         QStringList stringList;
554         stringList << encode(result + QLatin1String("tag/") +
555                              macName(node));
556         foreach (const QString &enumName, node->doc().enumItemNames()) {
557             // ### Write a plainEnumValue() and use it here
558             stringList << encode(result + QLatin1String("econst/") +
559                                  macName(node->parent(), enumName));
560         }
561         return stringList;
562     }
563     case Node::Typedef:
564         result += QLatin1String("tdef/") + macName(node);
565         break;
566     case Node::Function:
567     {
568         bool isMacro = false;
569         Q_UNUSED(isMacro)
570         const FunctionNode *func = static_cast<const FunctionNode *>(node);
571
572         // overloads are too clever for the Xcode documentation browser
573         if (func->isOverload())
574             return QStringList();
575
576         if (func->metaness() == FunctionNode::MacroWithParams
577                 || func->metaness() == FunctionNode::MacroWithoutParams) {
578             result += QLatin1String("macro/");
579         }
580         else if (func->isStatic()) {
581             result += QLatin1String("clm/");
582         }
583         else if (!func->parent()->name().isEmpty()) {
584             result += QLatin1String("instm/");
585         }
586         else {
587             result += QLatin1String("func/");
588         }
589
590         result += macName(func);
591         if (result.endsWith(QLatin1String("()")))
592             result.chop(2);
593     }
594         break;
595     case Node::Variable:
596         result += QLatin1String("data/") + macName(node);
597         break;
598     case Node::Property:
599     {
600         NodeList list = static_cast<const PropertyNode*>(node)->functions();
601         QStringList stringList;
602         foreach (Node* node, list) {
603             stringList += macRefsForNode(node);
604         }
605         return stringList;
606     }
607     case Node::Namespace:
608     case Node::Fake:
609     default:
610         return QStringList();
611     }
612
613     return QStringList(encode(result));
614 }
615
616 QString CodeMarker::macName(const Node *node, const QString &name)
617 {
618     QString myName = name;
619     if (myName.isEmpty()) {
620         myName = node->name();
621         node = node->parent();
622     }
623
624     if (node->name().isEmpty()) {
625         return QLatin1Char('/') + protect(myName);
626     }
627     else {
628         return plainFullName(node) + QLatin1Char('/') + protect(myName);
629     }
630 }
631
632 /*!
633   Get the list of documentation sections for the children of
634   the specified QmlClassNode.
635  */
636 QList<Section> CodeMarker::qmlSections(const QmlClassNode* ,
637                                        SynopsisStyle )
638 {
639     return QList<Section>();
640 }
641
642 const Node* CodeMarker::resolveTarget(const QString& /* target */,
643                                       const Tree* ,
644                                       const Node* ,
645                                       const Node* )
646 {
647     return 0;
648 }
649
650 QT_END_NAMESPACE