source: trunk/tools/qdoc3/cppcodemarker.cpp@ 1028

Last change on this file since 1028 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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