Merge remote branch 'origin/4.8' into 4.8-from-4.7
[qt:qt.git] / tools / qdoc3 / cppcodemarker.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the tools applications of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 /*
43   cppcodemarker.cpp
44 */
45
46 #include "atom.h"
47 #include "cppcodemarker.h"
48 #include "node.h"
49 #include "text.h"
50 #include "tree.h"
51
52 #include <ctype.h>
53
54 QT_BEGIN_NAMESPACE
55
56 /*!
57   The constructor does nothing.
58  */
59 CppCodeMarker::CppCodeMarker()
60 {
61     // nothing.
62 }
63
64 /*!
65   The destructor does nothing.
66  */
67 CppCodeMarker::~CppCodeMarker()
68 {
69     // nothing.
70 }
71
72 /*!
73   Returns true.
74  */
75 bool CppCodeMarker::recognizeCode(const QString & /* code */)
76 {
77     return true;
78 }
79
80 /*!
81   Returns true if \a ext is any of a list of file extensions
82   for the C++ language.
83  */
84 bool CppCodeMarker::recognizeExtension(const QString& ext)
85 {
86     return ext == "c" ||
87         ext == "c++" ||
88         ext == "cc" ||
89         ext == "cpp" ||
90         ext == "cxx" ||
91         ext == "ch" ||
92         ext == "h" ||
93         ext == "h++" ||
94         ext == "hh" ||
95         ext == "hpp" ||
96         ext == "hxx";
97 }
98
99 /*!
100   Returns true if \a lang is either "C" or "Cpp".
101  */
102 bool CppCodeMarker::recognizeLanguage(const QString &lang)
103 {
104     return lang == "C" || lang == "Cpp";
105 }
106
107 /*!
108   Returns the type of atom used to represent C++ code in the documentation.
109 */
110 Atom::Type CppCodeMarker::atomType() const
111 {
112     return Atom::Code;
113 }
114
115 /*!
116   Returns the \a node name, or "()" if \a node is a
117   Node::Function node.
118  */
119 QString CppCodeMarker::plainName(const Node *node)
120 {
121     QString name = node->name();
122     if (node->type() == Node::Function)
123         name += "()";
124     return name;
125 }
126
127 QString CppCodeMarker::plainFullName(const Node *node, const Node *relative)
128 {
129     if (node->name().isEmpty()) {
130         return "global";
131     }
132     else {
133         QString fullName;
134         while (node) {
135             fullName.prepend(plainName(node));
136             if (node->parent() == relative || node->parent()->name().isEmpty())
137                 break;
138             fullName.prepend("::");
139             node = node->parent();
140         }
141         return fullName;
142     }
143 }
144
145 QString CppCodeMarker::markedUpCode(const QString &code,
146                                     const Node *relative,
147                                     const Location &location)
148 {
149     return addMarkUp(code, relative, location);
150 }
151
152 QString CppCodeMarker::markedUpSynopsis(const Node *node,
153                                         const Node * /* relative */,
154                                         SynopsisStyle style)
155 {
156     const int MaxEnumValues = 6;
157     const FunctionNode *func;
158     const PropertyNode *property;
159     const VariableNode *variable;
160     const EnumNode *enume;
161     const TypedefNode *typedeff;
162     QString synopsis;
163     QString extra;
164     QString name;
165
166     name = taggedNode(node);
167     if (style != Detailed)
168         name = linkTag(node, name);
169     name = "<@name>" + name + "</@name>";
170
171     if (style == Detailed && !node->parent()->name().isEmpty() &&
172         node->type() != Node::Property)
173         name.prepend(taggedNode(node->parent()) + "::");
174
175     switch (node->type()) {
176     case Node::Namespace:
177         synopsis = "namespace " + name;
178         break;
179     case Node::Class:
180         synopsis = "class " + name;
181         break;
182     case Node::Function:
183     case Node::QmlSignal:
184     case Node::QmlMethod:
185         func = (const FunctionNode *) node;
186         if (style != SeparateList && !func->returnType().isEmpty())
187             synopsis = typified(func->returnType()) + " ";
188         synopsis += name;
189         if (func->metaness() != FunctionNode::MacroWithoutParams) {
190             synopsis += " (";
191             if (!func->parameters().isEmpty()) {
192                 synopsis += " ";
193                 QList<Parameter>::ConstIterator p = func->parameters().begin();
194                 while (p != func->parameters().end()) {
195                     if (p != func->parameters().begin())
196                         synopsis += ", ";
197                     synopsis += typified((*p).leftType());
198                     if (style != SeparateList && !(*p).name().isEmpty())
199                         synopsis +=
200                             " <@param>" + protect((*p).name()) + "</@param>";
201                     synopsis += protect((*p).rightType());
202                     if (style != SeparateList && !(*p).defaultValue().isEmpty())
203                         synopsis += " = " + protect((*p).defaultValue());
204                     ++p;
205                 }
206                 synopsis += " ";
207             }
208             synopsis += ")";
209         }
210         if (func->isConst())
211             synopsis += " const";
212
213         if (style == Summary || style == Accessors) {
214             if (func->virtualness() != FunctionNode::NonVirtual)
215                 synopsis.prepend("virtual ");
216             if (func->virtualness() == FunctionNode::PureVirtual)
217                 synopsis.append(" = 0");
218         }
219         else if (style == SeparateList) {
220             if (!func->returnType().isEmpty() && func->returnType() != "void")
221                 synopsis += " : " + typified(func->returnType());
222         }
223         else {
224             QStringList bracketed;
225             if (func->isStatic()) {
226                 bracketed += "static";
227             }
228             else if (func->virtualness() != FunctionNode::NonVirtual) {
229                 if (func->virtualness() == FunctionNode::PureVirtual)
230                     bracketed += "pure";
231                 bracketed += "virtual";
232             }
233
234             if (func->access() == Node::Protected) {
235                 bracketed += "protected";
236             }
237             else if (func->access() == Node::Private) {
238                 bracketed += "private";
239             }
240
241             if (func->metaness() == FunctionNode::Signal) {
242                 bracketed += "signal";
243             }
244             else if (func->metaness() == FunctionNode::Slot) {
245                 bracketed += "slot";
246             }
247             if (!bracketed.isEmpty())
248                 extra += " [" + bracketed.join(" ") + "]";
249         }
250         break;
251     case Node::Enum:
252         enume = static_cast<const EnumNode *>(node);
253         synopsis = "enum " + name;
254         if (style == Summary) {
255             synopsis += " { ";
256
257             QStringList documentedItems = enume->doc().enumItemNames();
258             if (documentedItems.isEmpty()) {
259                 foreach (const EnumItem &item, enume->items())
260                     documentedItems << item.name();
261             }
262             QStringList omitItems = enume->doc().omitEnumItemNames();
263             foreach (const QString &item, omitItems)
264                 documentedItems.removeAll(item);
265
266             if (documentedItems.size() <= MaxEnumValues) {
267                 for (int i = 0; i < documentedItems.size(); ++i) {
268                     if (i != 0)
269                         synopsis += ", ";
270                     synopsis += documentedItems.at(i);
271                 }
272             }
273             else {
274                 for (int i = 0; i < documentedItems.size(); ++i) {
275                     if (i < MaxEnumValues-2 || i == documentedItems.size()-1) {
276                         if (i != 0)
277                             synopsis += ", ";
278                         synopsis += documentedItems.at(i);
279                     }
280                     else if (i == MaxEnumValues - 1) {
281                         synopsis += ", ...";
282                     }
283                 }
284             }
285             if (!documentedItems.isEmpty())
286                 synopsis += " ";
287             synopsis += "}";
288         }
289         break;
290     case Node::Typedef:
291         typedeff = static_cast<const TypedefNode *>(node);
292         if (typedeff->associatedEnum()) {
293             synopsis = "flags " + name;
294         }
295         else {
296             synopsis = "typedef " + name;
297         }
298         break;
299     case Node::Property:
300         property = static_cast<const PropertyNode *>(node);
301         synopsis = name + " : " + typified(property->qualifiedDataType());
302         break;
303     case Node::Variable:
304         variable = static_cast<const VariableNode *>(node);
305         if (style == SeparateList) {
306             synopsis = name + " : " + typified(variable->dataType());
307         }
308         else {
309             synopsis = typified(variable->leftType()) + " " +
310                 name + protect(variable->rightType());
311         }
312         break;
313     default:
314         synopsis = name;
315     }
316
317     if (style == Summary) {
318         if (node->status() == Node::Preliminary) {
319             extra += " (preliminary)";
320         }
321         else if (node->status() == Node::Deprecated) {
322             extra += " (deprecated)";
323         }
324         else if (node->status() == Node::Obsolete) {
325             extra += " (obsolete)";
326         }
327     }
328
329     if (!extra.isEmpty()) {
330         extra.prepend("<@extra>");
331         extra.append("</@extra>");
332     }
333     return synopsis + extra;
334 }
335
336 #ifdef QDOC_QML
337 /*!
338  */
339 QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
340 {
341     QString name = taggedQmlNode(node);
342     if (summary) {
343         name = linkTag(node,name);
344     } else if (node->type() == Node::QmlProperty) {
345         const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node);
346         if (pn->isAttached())
347             name.prepend(pn->element() + QLatin1Char('.'));
348     }
349     name = "<@name>" + name + "</@name>";
350     QString synopsis = name;
351     if (node->type() == Node::QmlProperty) {
352         const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node);
353         synopsis += " : " + typified(pn->dataType());
354     }
355
356     QString extra;
357     if (summary) {
358         if (node->status() == Node::Preliminary) {
359             extra += " (preliminary)";
360         }
361         else if (node->status() == Node::Deprecated) {
362             extra += " (deprecated)";
363         }
364         else if (node->status() == Node::Obsolete) {
365             extra += " (obsolete)";
366         }
367     }
368
369     if (!extra.isEmpty()) {
370         extra.prepend("<@extra>");
371         extra.append("</@extra>");
372     }
373     return synopsis + extra;
374 }
375 #endif
376
377 QString CppCodeMarker::markedUpName(const Node *node)
378 {
379     QString name = linkTag(node, taggedNode(node));
380     if (node->type() == Node::Function)
381         name += "()";
382     return name;
383 }
384
385 QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative)
386 {
387     if (node->name().isEmpty()) {
388         return "global";
389     }
390     else {
391         QString fullName;
392         for (;;) {
393             fullName.prepend(markedUpName(node));
394             if (node->parent() == relative || node->parent()->name().isEmpty())
395                 break;
396             fullName.prepend("<@op>::</@op>");
397             node = node->parent();
398         }
399         return fullName;
400     }
401 }
402
403 QString CppCodeMarker::markedUpEnumValue(const QString &enumValue,
404                                          const Node *relative)
405 {
406     const Node *node = relative->parent();
407     QString fullName;
408     while (node->parent()) {
409         fullName.prepend(markedUpName(node));
410         if (node->parent() == relative || node->parent()->name().isEmpty())
411             break;
412         fullName.prepend("<@op>::</@op>");
413         node = node->parent();
414     }
415     if (!fullName.isEmpty())
416         fullName.append("<@op>::</@op>");
417     fullName.append(enumValue);
418     return fullName;
419 }
420
421 QString CppCodeMarker::markedUpIncludes(const QStringList& includes)
422 {
423     QString code;
424
425     QStringList::ConstIterator inc = includes.begin();
426     while (inc != includes.end()) {
427         code += "<@preprocessor>#include &lt;<@headerfile>" + *inc + "</@headerfile>&gt;</@preprocessor>\n";
428         ++inc;
429     }
430     return code;
431 }
432
433 QString CppCodeMarker::functionBeginRegExp(const QString& funcName)
434 {
435     return "^" + QRegExp::escape(funcName) + "$";
436
437 }
438
439 QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */)
440 {
441     return "^\\}$";
442 }
443
444 QList<Section> CppCodeMarker::sections(const InnerNode *inner,
445                                        SynopsisStyle style,
446                                        Status status)
447 {
448     QList<Section> sections;
449
450     if (inner->type() == Node::Class) {
451         const ClassNode *classe = static_cast<const ClassNode *>(inner);
452
453         if (style == Summary) {
454             FastSection privateFunctions(classe,
455                                          "Private Functions",
456                                          "",
457                                          "private function",
458                                          "private functions");
459             FastSection privateSlots(classe, "Private Slots", "", "private slot", "private slots");
460             FastSection privateTypes(classe, "Private Types", "", "private type", "private types");
461             FastSection protectedFunctions(classe,
462                                            "Protected Functions",
463                                            "",
464                                            "protected function",
465                                            "protected functions");
466             FastSection protectedSlots(classe,
467                                        "Protected Slots",
468                                        "",
469                                        "protected slot",
470                                        "protected slots");
471             FastSection protectedTypes(classe,
472                                        "Protected Types",
473                                        "",
474                                        "protected type",
475                                        "protected types");
476             FastSection protectedVariables(classe,
477                                            "Protected Variables",
478                                            "",
479                                            "protected type",
480                                            "protected variables");
481             FastSection publicFunctions(classe,
482                                         "Public Functions",
483                                         "",
484                                         "public function",
485                                         "public functions");
486             FastSection publicSignals(classe, "Signals", "", "signal", "signals");
487             FastSection publicSlots(classe, "Public Slots", "", "public slot", "public slots");
488             FastSection publicTypes(classe, "Public Types", "", "public type", "public types");
489             FastSection publicVariables(classe,
490                                         "Public Variables",
491                                         "",
492                                         "public variable",
493                                         "public variables");
494             FastSection properties(classe, "Properties", "", "property", "properties");
495             FastSection relatedNonMembers(classe,
496                                           "Related Non-Members",
497                                           "",
498                                           "related non-member",
499                                           "related non-members");
500             FastSection staticPrivateMembers(classe,
501                                              "Static Private Members",
502                                              "",
503                                              "static private member",
504                                              "static private members");
505             FastSection staticProtectedMembers(classe,
506                                                "Static Protected Members",
507                                                "",
508                                                "static protected member",
509                                                "static protected members");
510             FastSection staticPublicMembers(classe,
511                                             "Static Public Members",
512                                             "",
513                                             "static public member",
514                                             "static public members");
515             FastSection macros(inner, "Macros", "", "macro", "macros");
516
517             NodeList::ConstIterator r = classe->relatedNodes().begin();
518             while (r != classe->relatedNodes().end()) {
519                 if ((*r)->type() == Node::Function) {
520                     FunctionNode *func = static_cast<FunctionNode *>(*r);
521                     if (func->isMacro())
522                         insert(macros, *r, style, status);
523                     else
524                         insert(relatedNonMembers, *r, style, status);
525                 }
526                 else {
527                     insert(relatedNonMembers, *r, style, status);
528                 }
529                 ++r;
530             }
531
532             QStack<const ClassNode *> stack;
533             stack.push(classe);
534
535             while (!stack.isEmpty()) {
536                 const ClassNode *ancestorClass = stack.pop();
537
538                 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
539                 while (c != ancestorClass->childNodes().end()) {
540                     bool isSlot = false;
541                     bool isSignal = false;
542                     bool isStatic = false;
543                     if ((*c)->type() == Node::Function) {
544                         const FunctionNode *func = (const FunctionNode *) *c;
545                         isSlot = (func->metaness() == FunctionNode::Slot);
546                         isSignal = (func->metaness() == FunctionNode::Signal);
547                         isStatic = func->isStatic();
548                     }
549                     else if ((*c)->type() == Node::Variable) {
550                         const VariableNode *var = static_cast<const VariableNode *>(*c);
551                         isStatic = var->isStatic();
552                     }
553
554                     switch ((*c)->access()) {
555                     case Node::Public:
556                         if (isSlot) {
557                             insert(publicSlots, *c, style, status);
558                         }
559                         else if (isSignal) {
560                             insert(publicSignals, *c, style, status);
561                         }
562                         else if (isStatic) {
563                             if ((*c)->type() != Node::Variable
564                                     || !(*c)->doc().isEmpty())
565                                 insert(staticPublicMembers,*c,style,status);
566                         }
567                         else if ((*c)->type() == Node::Property) {
568                             insert(properties, *c, style, status);
569                         }
570                         else if ((*c)->type() == Node::Variable) {
571                             if (!(*c)->doc().isEmpty())
572                                 insert(publicVariables, *c, style, status);
573                         }
574                         else if ((*c)->type() == Node::Function) {
575                             if (!insertReimpFunc(publicFunctions,*c,status))
576                                 insert(publicFunctions, *c, style, status);
577                         }
578                         else {
579                             insert(publicTypes, *c, style, status);
580                         }
581                         break;
582                     case Node::Protected:
583                         if (isSlot) {
584                             insert(protectedSlots, *c, style, status);
585                         }
586                         else if (isStatic) {
587                             if ((*c)->type() != Node::Variable
588                                     || !(*c)->doc().isEmpty())
589                                 insert(staticProtectedMembers,*c,style,status);
590                         }
591                         else if ((*c)->type() == Node::Variable) {
592                             if (!(*c)->doc().isEmpty())
593                                 insert(protectedVariables,*c,style,status);
594                         }
595                         else if ((*c)->type() == Node::Function) {
596                             if (!insertReimpFunc(protectedFunctions,*c,status))
597                                 insert(protectedFunctions, *c, style, status);
598                         }
599                         else {
600                             insert(protectedTypes, *c, style, status);
601                         }
602                         break;
603                     case Node::Private:
604                         if (isSlot) {
605                             insert(privateSlots, *c, style, status);
606                         }
607                         else if (isStatic) {
608                             if ((*c)->type() != Node::Variable
609                                     || !(*c)->doc().isEmpty())
610                                 insert(staticPrivateMembers,*c,style,status);
611                         }
612                         else if ((*c)->type() == Node::Function) {
613                             if (!insertReimpFunc(privateFunctions,*c,status))
614                                 insert(privateFunctions, *c, style, status);
615                         }
616                         else {
617                             insert(privateTypes,*c,style,status);
618                         }
619                     }
620                     ++c;
621                 }
622
623                 QList<RelatedClass>::ConstIterator r =
624                     ancestorClass->baseClasses().begin();
625                 while (r != ancestorClass->baseClasses().end()) {
626                     stack.prepend((*r).node);
627                     ++r;
628                 }
629             }
630
631             append(sections, publicTypes);
632             append(sections, properties);
633             append(sections, publicFunctions);
634             append(sections, publicSlots);
635             append(sections, publicSignals);
636             append(sections, publicVariables);
637             append(sections, staticPublicMembers);
638             append(sections, protectedTypes);
639             append(sections, protectedFunctions);
640             append(sections, protectedSlots);
641             append(sections, protectedVariables);
642             append(sections, staticProtectedMembers);
643             append(sections, privateTypes);
644             append(sections, privateFunctions);
645             append(sections, privateSlots);
646             append(sections, staticPrivateMembers);
647             append(sections, relatedNonMembers);
648             append(sections, macros);
649         }
650         else if (style == Detailed) {
651             FastSection memberFunctions(classe,"Member Function Documentation","func","member","members");
652             FastSection memberTypes(classe,"Member Type Documentation","types","member","members");
653             FastSection memberVariables(classe,"Member Variable Documentation","vars","member","members");
654             FastSection properties(classe,"Property Documentation","prop","member","members");
655             FastSection relatedNonMembers(classe,"Related Non-Members","relnonmem","member","members");
656             FastSection macros(classe,"Macro Documentation","macros","member","members");
657
658             NodeList::ConstIterator r = classe->relatedNodes().begin();
659             while (r != classe->relatedNodes().end()) {
660                 if ((*r)->type() == Node::Function) {
661                     FunctionNode *func = static_cast<FunctionNode *>(*r);
662                     if (func->isMacro())
663                         insert(macros, *r, style, status);
664                     else
665                         insert(relatedNonMembers, *r, style, status);
666                 }
667                 else {
668                     insert(relatedNonMembers, *r, style, status);
669                 }
670                 ++r;
671             }
672
673             NodeList::ConstIterator c = classe->childNodes().begin();
674             while (c != classe->childNodes().end()) {
675                 if ((*c)->type() == Node::Enum ||
676                     (*c)->type() == Node::Typedef) {
677                     insert(memberTypes, *c, style, status);
678                 }
679                 else if ((*c)->type() == Node::Property) {
680                     insert(properties, *c, style, status);
681                 }
682                 else if ((*c)->type() == Node::Variable) {
683                     if (!(*c)->doc().isEmpty())
684                         insert(memberVariables, *c, style, status);
685                 }
686                 else if ((*c)->type() == Node::Function) {
687                     FunctionNode *function = static_cast<FunctionNode *>(*c);
688                     if (!function->associatedProperty())
689                         insert(memberFunctions, function, style, status);
690                 }
691                 ++c;
692             }
693
694             append(sections, memberTypes);
695             append(sections, properties);
696             append(sections, memberFunctions);
697             append(sections, memberVariables);
698             append(sections, relatedNonMembers);
699             append(sections, macros);
700         }
701         else {
702             FastSection all(classe,"","","member","members");
703
704             QStack<const ClassNode *> stack;
705             stack.push(classe);
706
707             while (!stack.isEmpty()) {
708                 const ClassNode *ancestorClass = stack.pop();
709
710                 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
711                 while (c != ancestorClass->childNodes().end()) {
712                     if ((*c)->access() != Node::Private &&
713                         (*c)->type() != Node::Property)
714                         insert(all, *c, style, status);
715                     ++c;
716                 }
717
718                 QList<RelatedClass>::ConstIterator r =
719                     ancestorClass->baseClasses().begin();
720                 while (r != ancestorClass->baseClasses().end()) {
721                     stack.prepend((*r).node);
722                     ++r;
723                 }
724             }
725             append(sections, all);
726         }
727     }
728     else {
729         if (style == Summary || style == Detailed) {
730             FastSection namespaces(inner,
731                                    "Namespaces",
732                                    style == Detailed ? "nmspace" : "",
733                                    "namespace",
734                                    "namespaces");
735             FastSection classes(inner,
736                                 "Classes",
737                                 style == Detailed ? "classes" : "",
738                                 "class",
739                                 "classes");
740             FastSection types(inner,
741                               style == Summary ? "Types" : "Type Documentation",
742                               style == Detailed ? "types" : "",
743                               "type",
744                               "types");
745             FastSection functions(inner,
746                                   style == Summary ?
747                                   "Functions" : "Function Documentation",
748                                   style == Detailed ? "func" : "",
749                                   "function",
750                                   "functions");
751             FastSection macros(inner,
752                                style == Summary ?
753                                "Macros" : "Macro Documentation",
754                                style == Detailed ? "macros" : "",
755                                "macro",
756                                "macros");
757
758             NodeList nodeList = inner->childNodes();
759             nodeList += inner->relatedNodes();
760
761             NodeList::ConstIterator n = nodeList.begin();
762             while (n != nodeList.end()) {
763                 switch ((*n)->type()) {
764                 case Node::Namespace:
765                     insert(namespaces, *n, style, status);
766                     break;
767                 case Node::Class:
768                     insert(classes, *n, style, status);
769                     break;
770                 case Node::Enum:
771                 case Node::Typedef:
772                     insert(types, *n, style, status);
773                     break;
774                 case Node::Function:
775                     {
776                         FunctionNode *func = static_cast<FunctionNode *>(*n);
777                         if (func->isMacro())
778                             insert(macros, *n, style, status);
779                         else
780                             insert(functions, *n, style, status);
781                     }
782                     break;
783                 default:
784                     ;
785                 }
786                 ++n;
787             }
788             append(sections, namespaces);
789             append(sections, classes);
790             append(sections, types);
791             append(sections, functions);
792             append(sections, macros);
793         }
794     }
795
796     return sections;
797 }
798
799 const Node *CppCodeMarker::resolveTarget(const QString& target,
800                                          const Tree* tree,
801                                          const Node* relative,
802                                          const Node* self)
803 {
804     if (target.endsWith("()")) {
805         const FunctionNode *func;
806         QString funcName = target;
807         funcName.chop(2);
808
809         QStringList path = funcName.split("::");
810         if ((func = tree->findFunctionNode(path,
811                                            relative,
812                                            Tree::SearchBaseClasses))
813                 && func->metaness() != FunctionNode::MacroWithoutParams)
814             return func;
815     }
816     else if (target.contains("#")) {
817         // ### this doesn't belong here; get rid of TargetNode hack
818         int hashAt = target.indexOf("#");
819         QString link = target.left(hashAt);
820         QString ref = target.mid(hashAt + 1);
821         const Node *node;
822         if (link.isEmpty()) {
823             node = relative;
824         }
825         else {
826             QStringList path(link);
827             node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses);
828         }
829         if (node && node->isInnerNode()) {
830             const Atom *atom = node->doc().body().firstAtom();
831             while (atom) {
832                 if (atom->type() == Atom::Target && atom->string() == ref) {
833                     Node *parentNode = const_cast<Node *>(node);
834                     return new TargetNode(static_cast<InnerNode*>(parentNode),
835                                           ref);
836                 }
837                 atom = atom->next();
838             }
839         }
840     }
841     else {
842         QStringList path = target.split("::");
843         const Node *node;
844         int flags = Tree::SearchBaseClasses |
845             Tree::SearchEnumValues |
846             Tree::NonFunction;
847         if ((node = tree->findNode(path,
848                                    relative,
849                                    flags,
850                                    self)))
851             return node;
852     }
853     return 0;
854 }
855
856 static const char * const typeTable[] = {
857     "bool", "char", "double", "float", "int", "long", "short",
858     "signed", "unsigned", "uint", "ulong", "ushort", "uchar", "void",
859     "qlonglong", "qulonglong",
860     "qint", "qint8", "qint16", "qint32", "qint64",
861     "quint", "quint8", "quint16", "quint32", "quint64",
862     "qreal", "cond", 0
863 };
864
865 static const char * const keywordTable[] = {
866     "and", "and_eq", "asm", "auto", "bitand", "bitor", "break",
867     "case", "catch", "class", "compl", "const", "const_cast",
868     "continue", "default", "delete", "do", "dynamic_cast", "else",
869     "enum", "explicit", "export", "extern", "false", "for", "friend",
870     "goto", "if", "include", "inline", "monitor", "mutable", "namespace",
871     "new", "not", "not_eq", "operator", "or", "or_eq", "private", "protected",
872     "public", "register", "reinterpret_cast", "return", "sizeof",
873     "static", "static_cast", "struct", "switch", "template", "this",
874     "throw", "true", "try", "typedef", "typeid", "typename", "union",
875     "using", "virtual", "volatile", "wchar_t", "while", "xor",
876     "xor_eq", "synchronized",
877     // Qt specific
878     "signals", "slots", "emit", 0
879 };
880
881 /*
882     @char
883     @class
884     @comment
885     @function
886     @keyword
887     @number
888     @op
889     @preprocessor
890     @string
891     @type
892 */
893
894 QString CppCodeMarker::addMarkUp(const QString &in,
895                                  const Node * /* relative */,
896                                  const Location & /* location */)
897 {
898 #define readChar() \
899     ch = (i < (int)code.length()) ? code[i++].cell() : EOF
900
901     QString code = in;
902
903     QMap<QString, int> types;
904     QMap<QString, int> keywords;
905     int j = 0;
906     while (typeTable[j] != 0) {
907         types.insert(QString(typeTable[j]), 0);
908         j++;
909     }
910     j = 0;
911     while (keywordTable[j] != 0) {
912         keywords.insert(QString(keywordTable[j]), 0);
913         j++;
914     }
915
916     QString out("");
917     int braceDepth = 0;
918     int parenDepth = 0;
919     int i = 0;
920     int start = 0;
921     int finish = 0;
922     QChar ch;
923     QRegExp classRegExp("Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)");
924     QRegExp functionRegExp("q([A-Z][a-z]+)+");
925
926     readChar();
927
928     while (ch != EOF) {
929         QString tag;
930         bool target = false;
931
932         if (ch.isLetter() || ch == '_') {
933             QString ident;
934             do {
935             ident += ch;
936             finish = i;
937             readChar();
938         } while (ch.isLetterOrNumber() || ch == '_');
939
940             if (classRegExp.exactMatch(ident)) {
941                 tag = QLatin1String("type");
942             } else if (functionRegExp.exactMatch(ident)) {
943                 tag = QLatin1String("func");
944                 target = true;
945             } else if (types.contains(ident)) {
946                 tag = QLatin1String("type");
947             } else if (keywords.contains(ident)) {
948                 tag = QLatin1String("keyword");
949             } else if (braceDepth == 0 && parenDepth == 0) {
950                 if (QString(code.unicode() + i - 1, code.length() - (i - 1))
951                      .indexOf(QRegExp(QLatin1String("^\\s*\\("))) == 0)
952                     tag = QLatin1String("func");
953                     target = true;
954             }
955         } else if (ch.isDigit()) {
956             do {
957                 finish = i;
958                 readChar();
959             } while (ch.isLetterOrNumber() || ch == '.');
960             tag = QLatin1String("number");
961         } else {
962             switch (ch.unicode()) {
963             case '+':
964             case '-':
965             case '!':
966             case '%':
967             case '^':
968             case '&':
969             case '*':
970             case ',':
971             case '.':
972             case '<':
973             case '=':
974             case '>':
975             case '?':
976             case '[':
977             case ']':
978             case '|':
979             case '~':
980                 finish = i;
981                 readChar();
982                 tag = QLatin1String("op");
983                 break;
984             case '"':
985                 finish = i;
986                 readChar();
987
988                 while (ch != EOF && ch != '"') {
989                     if (ch == '\\')
990                         readChar();
991                     readChar();
992                 }
993                 finish = i;
994                 readChar();
995                 tag = QLatin1String("string");
996                 break;
997             case '#':
998                 finish = i;
999                 readChar();
1000                 while (ch != EOF && ch != '\n') {
1001                     if (ch == '\\')
1002                         readChar();
1003                     finish = i;
1004                     readChar();
1005                 }
1006                 tag = QLatin1String("preprocessor");
1007                 break;
1008             case '\'':
1009                 finish = i;
1010                 readChar();
1011
1012                 while (ch != EOF && ch != '\'') {
1013                     if (ch == '\\')
1014                         readChar();
1015                     readChar();
1016                 }
1017                 finish = i;
1018                 readChar();
1019                 tag = QLatin1String("char");
1020                 break;
1021             case '(':
1022                 finish = i;
1023                 readChar();
1024                 parenDepth++;
1025                 break;
1026             case ')':
1027                 finish = i;
1028                 readChar();
1029                 parenDepth--;
1030                 break;
1031             case ':':
1032                 finish = i;
1033                 readChar();
1034                 if (ch == ':') {
1035                     finish = i;
1036                     readChar();
1037                     tag = QLatin1String("op");
1038                 }
1039                 break;
1040             case '/':
1041                 finish = i;
1042                 readChar();
1043                 if (ch == '/') {
1044                     do {
1045                         finish = i;
1046                         readChar();
1047                     } while (ch != EOF && ch != '\n');
1048                     tag = QLatin1String("comment");
1049                 } else if (ch == '*') {
1050                     bool metAster = false;
1051                     bool metAsterSlash = false;
1052
1053                     finish = i;
1054                     readChar();
1055
1056                     while (!metAsterSlash) {
1057                         if (ch == EOF)
1058                             break;
1059
1060                         if (ch == '*')
1061                             metAster = true;
1062                         else if (metAster && ch == '/')
1063                             metAsterSlash = true;
1064                         else
1065                             metAster = false;
1066                         finish = i;
1067                         readChar();
1068                     }
1069                     tag = QLatin1String("comment");
1070                 } else {
1071                     tag = QLatin1String("op");
1072                 }
1073                 break;
1074             case '{':
1075                 finish = i;
1076                 readChar();
1077                 braceDepth++;
1078                 break;
1079             case '}':
1080                 finish = i;
1081                 readChar();
1082                 braceDepth--;
1083                 break;
1084             default:
1085                 finish = i;
1086                 readChar();
1087             }
1088         }
1089
1090         QString text;
1091         text = code.mid(start, finish - start);
1092         start = finish;
1093
1094         if (!tag.isEmpty()) {
1095             out += QLatin1String("<@") + tag;
1096             if (target)
1097                 out += QLatin1String(" target=\"") + text + QLatin1String("()\"");
1098             out += QLatin1String(">");
1099         }
1100
1101         out += protect(text);
1102
1103         if (!tag.isEmpty())
1104             out += QLatin1String("</@") + tag + QLatin1String(">");
1105     }
1106
1107     if (start < code.length()) {
1108         out += protect(code.mid(start));
1109     }
1110
1111     return out;
1112 }
1113
1114 #ifdef QDOC_QML
1115 /*!
1116   This function is for documenting QML properties. It returns
1117   the list of documentation sections for the children of the
1118   \a qmlClassNode.
1119
1120   Currently, it only handles QML property groups.
1121  */
1122 QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
1123                                           SynopsisStyle style,
1124                                           const Tree* tree)
1125 {
1126     QList<Section> sections;
1127     if (qmlClassNode) {
1128         if (style == Summary) {
1129             FastSection qmlproperties(qmlClassNode,
1130                                       "Properties",
1131                                       "",
1132                                       "property",
1133                                       "properties");
1134             FastSection qmlattachedproperties(qmlClassNode,
1135                                               "Attached Properties",
1136                                               "",
1137                                               "property",
1138                                               "properties");
1139             FastSection qmlsignals(qmlClassNode,
1140                                    "Signal Handlers",
1141                                    "",
1142                                    "signal handler",
1143                                    "signal handlers");
1144             FastSection qmlattachedsignals(qmlClassNode,
1145                                            "Attached Signal Handlers",
1146                                            "",
1147                                            "signal handler",
1148                                            "signal handlers");
1149             FastSection qmlmethods(qmlClassNode,
1150                                    "Methods",
1151                                    "",
1152                                    "method",
1153                                    "methods");
1154             FastSection qmlattachedmethods(qmlClassNode,
1155                                            "Attached Methods",
1156                                            "",
1157                                            "method",
1158                                            "methods");
1159
1160             NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
1161             while (c != qmlClassNode->childNodes().end()) {
1162                 if ((*c)->subType() == Node::QmlPropertyGroup) {
1163                     const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c);
1164                     NodeList::ConstIterator p = qpgn->childNodes().begin();
1165                     while (p != qpgn->childNodes().end()) {
1166                         if ((*p)->type() == Node::QmlProperty) {
1167                             const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p);
1168                             if (pn->isAttached())
1169                                 insert(qmlattachedproperties,*p,style,Okay);
1170                             else
1171                                 insert(qmlproperties,*p,style,Okay);
1172                         }
1173                         ++p;
1174                     }
1175                 }
1176                 else if ((*c)->type() == Node::QmlSignal) {
1177                     const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
1178                     if (sn->isAttached())
1179                         insert(qmlattachedsignals,*c,style,Okay);
1180                     else
1181                         insert(qmlsignals,*c,style,Okay);
1182                 }
1183                 else if ((*c)->type() == Node::QmlMethod) {
1184                     const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
1185                     if (mn->isAttached())
1186                         insert(qmlattachedmethods,*c,style,Okay);
1187                     else
1188                         insert(qmlmethods,*c,style,Okay);
1189                 }
1190                 ++c;
1191             }
1192             append(sections,qmlproperties);
1193             append(sections,qmlattachedproperties);
1194             append(sections,qmlsignals);
1195             append(sections,qmlattachedsignals);
1196             append(sections,qmlmethods);
1197             append(sections,qmlattachedmethods);
1198         }
1199         else if (style == Detailed) {
1200             FastSection qmlproperties(qmlClassNode, "Property Documentation","qmlprop","member","members");
1201             FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation","qmlattprop",
1202                                               "member","members");
1203             FastSection qmlsignals(qmlClassNode,"Signal Handler Documentation","qmlsig","handler","handlers");
1204             FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Handler Documentation","qmlattsig",
1205                                            "handler","handlers");
1206             FastSection qmlmethods(qmlClassNode,"Method Documentation","qmlmeth","member","members");
1207             FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation","qmlattmeth",
1208                                            "member","members");
1209             NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
1210             while (c != qmlClassNode->childNodes().end()) {
1211                 if ((*c)->subType() == Node::QmlPropertyGroup) {
1212                     const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c);
1213                     if (pgn->isAttached())
1214                         insert(qmlattachedproperties,*c,style,Okay);
1215                     else
1216                         insert(qmlproperties,*c,style,Okay);
1217                 }
1218                 else if ((*c)->type() == Node::QmlSignal) {
1219                     const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
1220                     if (sn->isAttached())
1221                         insert(qmlattachedsignals,*c,style,Okay);
1222                     else
1223                         insert(qmlsignals,*c,style,Okay);
1224                 }
1225                 else if ((*c)->type() == Node::QmlMethod) {
1226                     const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
1227                     if (mn->isAttached())
1228                         insert(qmlattachedmethods,*c,style,Okay);
1229                     else
1230                         insert(qmlmethods,*c,style,Okay);
1231                 }
1232                 ++c;
1233             }
1234             append(sections,qmlproperties);
1235             append(sections,qmlattachedproperties);
1236             append(sections,qmlsignals);
1237             append(sections,qmlattachedsignals);
1238             append(sections,qmlmethods);
1239             append(sections,qmlattachedmethods);
1240         }
1241         else {
1242             FastSection all(qmlClassNode,"","","member","members");
1243
1244             QStack<const QmlClassNode*> stack;
1245             stack.push(qmlClassNode);
1246
1247             while (!stack.isEmpty()) {
1248                 const QmlClassNode* ancestorClass = stack.pop();
1249
1250                 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
1251                 while (c != ancestorClass->childNodes().end()) {
1252                     //              if ((*c)->access() != Node::Private)
1253                     if ((*c)->subType() == Node::QmlPropertyGroup) {
1254                         const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c);
1255                         NodeList::ConstIterator p = qpgn->childNodes().begin();
1256                         while (p != qpgn->childNodes().end()) {
1257                             if ((*p)->type() == Node::QmlProperty) {
1258                                 insert(all,*p,style,Okay);
1259                             }
1260                             ++p;
1261                         }
1262                     }
1263                     else
1264                         insert(all,*c,style,Okay);
1265                     ++c;
1266                 }
1267
1268                 if (!ancestorClass->links().empty()) {
1269                     if (ancestorClass->links().contains(Node::InheritsLink)) {
1270                         QPair<QString,QString> linkPair;
1271                         linkPair = ancestorClass->links()[Node::InheritsLink];
1272                         QStringList strList(linkPair.first);
1273                         const Node* n = tree->findNode(strList,Node::Fake);
1274                         if (n && n->subType() == Node::QmlClass) {
1275                             const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n);
1276                             stack.prepend(qcn);
1277                         }
1278                     }
1279                 }
1280             }
1281             append(sections, all);
1282         }
1283     }
1284
1285     return sections;
1286 }
1287 #endif
1288
1289 QT_END_NAMESPACE