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

Last change on this file since 814 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 42.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 for (;;) {
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 "private function",
486 "private functions");
487 FastSection privateSlots(classe, "Private Slots", "private slot", "private slots");
488 FastSection privateTypes(classe, "Private Types", "private type", "private types");
489 FastSection protectedFunctions(classe,
490 "Protected Functions",
491 "protected function",
492 "protected functions");
493 FastSection protectedSlots(classe,
494 "Protected Slots",
495 "protected slot",
496 "protected slots");
497 FastSection protectedTypes(classe,
498 "Protected Types",
499 "protected type",
500 "protected types");
501 FastSection protectedVariables(classe,
502 "Protected Variables",
503 "protected type",
504 "protected variables");
505 FastSection publicFunctions(classe,
506 "Public Functions",
507 "public function",
508 "public functions");
509 FastSection publicSignals(classe, "Signals", "signal", "signals");
510 FastSection publicSlots(classe, "Public Slots", "public slot", "public slots");
511 FastSection publicTypes(classe, "Public Types", "public type", "public types");
512 FastSection publicVariables(classe,
513 "Public Variables",
514 "public type",
515 "public variables");
516 FastSection properties(classe, "Properties", "property", "properties");
517 FastSection relatedNonMembers(classe,
518 "Related Non-Members",
519 "related non-member",
520 "related non-members");
521 FastSection staticPrivateMembers(classe,
522 "Static Private Members",
523 "static private member",
524 "static private members");
525 FastSection staticProtectedMembers(classe,
526 "Static Protected Members",
527 "static protected member",
528 "static protected members");
529 FastSection staticPublicMembers(classe,
530 "Static Public Members",
531 "static public member",
532 "static public members");
533 FastSection macros(inner, "Macros", "macro", "macros");
534
535 NodeList::ConstIterator r = classe->relatedNodes().begin();
536 while (r != classe->relatedNodes().end()) {
537 if ((*r)->type() == Node::Function) {
538 FunctionNode *func = static_cast<FunctionNode *>(*r);
539 if (func->isMacro())
540 insert(macros, *r, style, status);
541 else
542 insert(relatedNonMembers, *r, style, status);
543 }
544 else {
545 insert(relatedNonMembers, *r, style, status);
546 }
547 ++r;
548 }
549
550 QStack<const ClassNode *> stack;
551 stack.push(classe);
552
553 while (!stack.isEmpty()) {
554 const ClassNode *ancestorClass = stack.pop();
555
556 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
557 while (c != ancestorClass->childNodes().end()) {
558 bool isSlot = false;
559 bool isSignal = false;
560 bool isStatic = false;
561 if ((*c)->type() == Node::Function) {
562 const FunctionNode *func = (const FunctionNode *) *c;
563 isSlot = (func->metaness() == FunctionNode::Slot);
564 isSignal = (func->metaness() == FunctionNode::Signal);
565 isStatic = func->isStatic();
566 }
567 else if ((*c)->type() == Node::Variable) {
568 const VariableNode *var = static_cast<const VariableNode *>(*c);
569 isStatic = var->isStatic();
570 }
571
572 switch ((*c)->access()) {
573 case Node::Public:
574 if (isSlot) {
575 insert(publicSlots, *c, style, status);
576 }
577 else if (isSignal) {
578 insert(publicSignals, *c, style, status);
579 }
580 else if (isStatic) {
581 if ((*c)->type() != Node::Variable
582 || !(*c)->doc().isEmpty())
583 insert(staticPublicMembers,*c,style,status);
584 }
585 else if ((*c)->type() == Node::Property) {
586 insert(properties, *c, style, status);
587 }
588 else if ((*c)->type() == Node::Variable) {
589 if (!(*c)->doc().isEmpty())
590 insert(publicVariables, *c, style, status);
591 }
592 else if ((*c)->type() == Node::Function) {
593 if (!insertReimpFunc(publicFunctions,*c,status))
594 insert(publicFunctions, *c, style, status);
595 }
596 else {
597 insert(publicTypes, *c, style, status);
598 }
599 break;
600 case Node::Protected:
601 if (isSlot) {
602 insert(protectedSlots, *c, style, status);
603 }
604 else if (isStatic) {
605 if ((*c)->type() != Node::Variable
606 || !(*c)->doc().isEmpty())
607 insert(staticProtectedMembers,*c,style,status);
608 }
609 else if ((*c)->type() == Node::Variable) {
610 if (!(*c)->doc().isEmpty())
611 insert(protectedVariables,*c,style,status);
612 }
613 else if ((*c)->type() == Node::Function) {
614 if (!insertReimpFunc(protectedFunctions,*c,status))
615 insert(protectedFunctions, *c, style, status);
616 }
617 else {
618 insert(protectedTypes, *c, style, status);
619 }
620 break;
621 case Node::Private:
622 if (isSlot) {
623 insert(privateSlots, *c, style, status);
624 }
625 else if (isStatic) {
626 if ((*c)->type() != Node::Variable
627 || !(*c)->doc().isEmpty())
628 insert(staticPrivateMembers,*c,style,status);
629 }
630 else if ((*c)->type() == Node::Function) {
631 if (!insertReimpFunc(privateFunctions,*c,status))
632 insert(privateFunctions, *c, style, status);
633 }
634 else {
635 insert(privateTypes,*c,style,status);
636 }
637 }
638 ++c;
639 }
640
641 QList<RelatedClass>::ConstIterator r =
642 ancestorClass->baseClasses().begin();
643 while (r != ancestorClass->baseClasses().end()) {
644 stack.prepend((*r).node);
645 ++r;
646 }
647 }
648
649 append(sections, publicTypes);
650 append(sections, properties);
651 append(sections, publicFunctions);
652 append(sections, publicSlots);
653 append(sections, publicSignals);
654 append(sections, publicVariables);
655 append(sections, staticPublicMembers);
656 append(sections, protectedTypes);
657 append(sections, protectedFunctions);
658 append(sections, protectedSlots);
659 append(sections, protectedVariables);
660 append(sections, staticProtectedMembers);
661 append(sections, privateTypes);
662 append(sections, privateFunctions);
663 append(sections, privateSlots);
664 append(sections, staticPrivateMembers);
665 append(sections, relatedNonMembers);
666 append(sections, macros);
667 }
668 else if (style == Detailed) {
669 FastSection memberFunctions(classe,"Member Function Documentation");
670 FastSection memberTypes(classe,"Member Type Documentation");
671 FastSection memberVariables(classe,"Member Variable Documentation");
672 FastSection properties(classe,"Property Documentation");
673 FastSection relatedNonMembers(classe,"Related Non-Members");
674 FastSection macros(classe,"Macro Documentation");
675
676 NodeList::ConstIterator r = classe->relatedNodes().begin();
677 while (r != classe->relatedNodes().end()) {
678 if ((*r)->type() == Node::Function) {
679 FunctionNode *func = static_cast<FunctionNode *>(*r);
680 if (func->isMacro())
681 insert(macros, *r, style, status);
682 else
683 insert(relatedNonMembers, *r, style, status);
684 }
685 else {
686 insert(relatedNonMembers, *r, style, status);
687 }
688 ++r;
689 }
690
691 NodeList::ConstIterator c = classe->childNodes().begin();
692 while (c != classe->childNodes().end()) {
693 if ((*c)->type() == Node::Enum ||
694 (*c)->type() == Node::Typedef) {
695 insert(memberTypes, *c, style, status);
696 }
697 else if ((*c)->type() == Node::Property) {
698 insert(properties, *c, style, status);
699 }
700 else if ((*c)->type() == Node::Variable) {
701 if (!(*c)->doc().isEmpty())
702 insert(memberVariables, *c, style, status);
703 }
704 else if ((*c)->type() == Node::Function) {
705 FunctionNode *function = static_cast<FunctionNode *>(*c);
706 if (!function->associatedProperty())
707 insert(memberFunctions, function, style, status);
708 }
709 ++c;
710 }
711
712 append(sections, memberTypes);
713 append(sections, properties);
714 append(sections, memberFunctions);
715 append(sections, memberVariables);
716 append(sections, relatedNonMembers);
717 append(sections, macros);
718 }
719 else {
720 FastSection all(classe);
721
722 QStack<const ClassNode *> stack;
723 stack.push(classe);
724
725 while (!stack.isEmpty()) {
726 const ClassNode *ancestorClass = stack.pop();
727
728 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
729 while (c != ancestorClass->childNodes().end()) {
730 if ((*c)->access() != Node::Private &&
731 (*c)->type() != Node::Property)
732 insert(all, *c, style, status);
733 ++c;
734 }
735
736 QList<RelatedClass>::ConstIterator r =
737 ancestorClass->baseClasses().begin();
738 while (r != ancestorClass->baseClasses().end()) {
739 stack.prepend((*r).node);
740 ++r;
741 }
742 }
743 append(sections, all);
744 }
745 }
746 else {
747 if (style == Summary || style == Detailed) {
748 FastSection namespaces(inner,
749 "Namespaces",
750 "namespace",
751 "namespaces");
752 FastSection classes(inner,
753 "Classes",
754 "class",
755 "classes");
756 FastSection types(inner,
757 style == Summary ?
758 "Types" : "Type Documentation",
759 "type",
760 "types");
761 FastSection functions(inner,
762 style == Summary ?
763 "Functions" : "Function Documentation",
764 "function",
765 "functions");
766 FastSection macros(inner,
767 style == Summary ?
768 "Macros" : "Macro Documentation",
769 "macro",
770 "macros");
771
772 NodeList nodeList = inner->childNodes();
773 nodeList += inner->relatedNodes();
774
775 NodeList::ConstIterator n = nodeList.begin();
776 while (n != nodeList.end()) {
777 switch ((*n)->type()) {
778 case Node::Namespace:
779 insert(namespaces, *n, style, status);
780 break;
781 case Node::Class:
782 insert(classes, *n, style, status);
783 break;
784 case Node::Enum:
785 case Node::Typedef:
786 insert(types, *n, style, status);
787 break;
788 case Node::Function:
789 {
790 FunctionNode *func = static_cast<FunctionNode *>(*n);
791 if (func->isMacro())
792 insert(macros, *n, style, status);
793 else
794 insert(functions, *n, style, status);
795 }
796 break;
797 default:
798 ;
799 }
800 ++n;
801 }
802 append(sections, namespaces);
803 append(sections, classes);
804 append(sections, types);
805 append(sections, functions);
806 append(sections, macros);
807 }
808 }
809
810 return sections;
811}
812
813const Node *CppCodeMarker::resolveTarget(const QString &target,
814 const Tree *tree,
815 const Node *relative)
816{
817 if (target.endsWith("()")) {
818 const FunctionNode *func;
819 QString funcName = target;
820 funcName.chop(2);
821
822 QStringList path = funcName.split("::");
823 if ((func = tree->findFunctionNode(path,
824 relative,
825 Tree::SearchBaseClasses))
826 && func->metaness() != FunctionNode::MacroWithoutParams)
827 return func;
828 }
829 else if (target.contains("#")) {
830 // ### this doesn't belong here; get rid of TargetNode hack
831 int hashAt = target.indexOf("#");
832 QString link = target.left(hashAt);
833 QString ref = target.mid(hashAt + 1);
834 const Node *node;
835 if (link.isEmpty()) {
836 node = relative;
837 }
838 else {
839 QStringList path(link);
840 node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses);
841 }
842 if (node && node->isInnerNode()) {
843 const Atom *atom = node->doc().body().firstAtom();
844 while (atom) {
845 if (atom->type() == Atom::Target && atom->string() == ref) {
846 Node *parentNode = const_cast<Node *>(node);
847 return new TargetNode(static_cast<InnerNode*>(parentNode),
848 ref);
849 }
850 atom = atom->next();
851 }
852 }
853 }
854 else {
855 QStringList path = target.split("::");
856 const Node *node;
857 if ((node = tree->findNode(path,
858 relative,
859 Tree::SearchBaseClasses |
860 Tree::SearchEnumValues |
861 Tree::NonFunction)))
862 return node;
863 }
864 return 0;
865}
866
867QString CppCodeMarker::addMarkUp(const QString& protectedCode,
868 const Node * /* relative */,
869 const QString& /* dirPath */)
870{
871 static QRegExp globalInclude("#include +&lt;([^<>&]+)&gt;");
872 static QRegExp yHasTypeX("(?:^|\n *)([a-zA-Z_][a-zA-Z_0-9]*)"
873 "(?:&lt;[^;{}]+&gt;)?(?: *(?:\\*|&amp;) *| +)"
874 "([a-zA-Z_][a-zA-Z_0-9]*)? *[,;()=]");
875 static QRegExp xNewY("([a-zA-Z_][a-zA-Z_0-9]*) *= *new +([a-zA-Z_0-9]+)");
876 static QRegExp xDotY("\\b([a-zA-Z_][a-zA-Z_0-9]*) *(?:\\.|-&gt;|,[ \n]*S(?:IGNAL|LOT)\\() *"
877 "([a-zA-Z_][a-zA-Z_0-9]*)(?= *\\()");
878 static QRegExp xIsStaticZOfY("[\n:;{(=] *(([a-zA-Z_0-9]+)::([a-zA-Z_0-9]+))(?= *\\()");
879 static QRegExp classX("[:,][ \n]*(?:p(?:ublic|r(?:otected|ivate))[ \n]+)?"
880 "([a-zA-Z_][a-zA-Z_0-9]*)");
881 static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\(");
882 static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)");
883 multiLineComment.setMinimal(true);
884 static QRegExp singleLineComment("//(?!!)[^!\n]*");
885 static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define"
886 "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)");
887 static QRegExp literals("&quot;(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*&quot;"
888 "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'");
889
890 QString result = protectedCode;
891 int pos;
892
893 if (!hurryUp()) {
894 /*
895 Mark global includes. For example:
896
897 #include &lt;<@headerfile>QString</@headerfile>
898 */
899 pos = 0;
900 while ((pos = result.indexOf(globalInclude, pos)) != -1)
901 pos += globalInclude.matchedLength()
902 + insertTagAround(result,
903 globalInclude.pos(1),
904 globalInclude.cap(1).length(),
905 "@headerfile");
906
907 /*
908 Look for variable definitions and similar constructs, mark
909 the data type, and remember the type of the variable.
910 */
911 QMap<QString, QSet<QString> > typesForVariable;
912 pos = 0;
913 while ((pos = yHasTypeX.indexIn(result, pos)) != -1) {
914 QString x = yHasTypeX.cap(1);
915 QString y = yHasTypeX.cap(2);
916
917 if (!y.isEmpty())
918 typesForVariable[y].insert(x);
919
920 /*
921 Without the minus one at the end, 'void member(Class
922 var)' would give 'member' as a variable of type 'void',
923 but would ignore 'Class var'. (### Is that true?)
924 */
925 pos += yHasTypeX.matchedLength()
926 + insertTagAround(result,
927 yHasTypeX.pos(1),
928 x.length(),
929 "@type") - 1;
930 }
931
932 /*
933 Do syntax highlighting of preprocessor directives.
934 */
935 pos = 0;
936 while ((pos = preprocessor.indexIn(result, pos)) != -1)
937 pos += preprocessor.matchedLength()
938 + insertTagAround(result,
939 preprocessor.pos(1),
940 preprocessor.cap(1).length(),
941 "@preprocessor");
942
943 /*
944 Deal with string and character literals.
945 */
946 pos = 0;
947 while ((pos = literals.indexIn(result, pos)) != -1)
948 pos += literals.matchedLength()
949 + insertTagAround(result,
950 pos,
951 literals.matchedLength(),
952 result.at(pos) ==
953 QLatin1Char(' ') ? "@string" : "@char");
954
955 /*
956 Look for 'var = new Class'.
957 */
958 pos = 0;
959 while ((pos = xNewY.indexIn(result, pos)) != -1) {
960 QString x = xNewY.cap(1);
961 QString y = xNewY.cap(2);
962 typesForVariable[x].insert(y);
963
964 pos += xNewY.matchedLength() + insertTagAround(result,
965 xNewY.pos(2),
966 y.length(),
967 "@type");
968 }
969
970 /*
971 Insert some stuff that cannot harm.
972 */
973 typesForVariable["qApp"].insert("QApplication");
974
975 /*
976 Add link to ': Class'.
977 */
978 pos = 0;
979 while ((pos = classX.indexIn(result, pos)) != -1)
980 pos += classX.matchedLength()
981 + insertTagAround(result,
982 classX.pos(1),
983 classX.cap(1).length(),
984 "@type") - 1;
985
986 /*
987 Find use of any of
988
989 var.method()
990 var->method()
991 var, SIGNAL(method())
992 var, SLOT(method()).
993 */
994 pos = 0;
995 while ((pos = xDotY.indexIn(result, pos)) != -1) {
996 QString x = xDotY.cap(1);
997 QString y = xDotY.cap(2);
998
999 QSet<QString> types = typesForVariable.value(x);
1000 pos += xDotY.matchedLength()
1001 + insertTagAround(result,
1002 xDotY.pos(2),
1003 xDotY.cap(2).length(),
1004 "@func",
1005 (types.count() == 1) ? "target=\""
1006 + protect(*types.begin() + "::" + y)
1007 + "()\"" : QString());
1008 }
1009
1010 /*
1011 Add link to 'Class::method()'.
1012 */
1013 pos = 0;
1014 while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) {
1015 QString x = xIsStaticZOfY.cap(1);
1016 QString z = xIsStaticZOfY.cap(3);
1017
1018 pos += insertTagAround(result,
1019 xIsStaticZOfY.pos(3),
1020 z.length(),
1021 "@func",
1022 "target=\"" + protect(x) + "()\"");
1023 pos += insertTagAround(result,
1024 xIsStaticZOfY.pos(2),
1025 xIsStaticZOfY.cap(2).length(),
1026 "@type");
1027 pos += xIsStaticZOfY.matchedLength() - 1;
1028 }
1029
1030 /*
1031 Add link to 'globalFunction()'.
1032 */
1033 pos = 0;
1034 while ((pos = globalX.indexIn(result, pos)) != -1) {
1035 QString x = globalX.cap(1);
1036 if (x != "QT_FORWARD_DECLARE_CLASS") {
1037 pos += globalX.matchedLength()
1038 + insertTagAround(result,
1039 globalX.pos(1),
1040 x.length(),
1041 "@func",
1042 "target=\"" + protect(x) + "()\"") - 1;
1043 }
1044 else
1045 pos += globalX.matchedLength();
1046 }
1047 }
1048
1049 /*
1050 Do syntax highlighting of comments. Also alter the code in a
1051 minor way, so that we can include comments in documentation
1052 comments.
1053 */
1054 pos = 0;
1055 while (pos != -1) {
1056 int mlpos;
1057 int slpos;
1058 int len;
1059 slpos = singleLineComment.indexIn(result, pos);
1060 mlpos = multiLineComment.indexIn(result, pos);
1061
1062 if (slpos == -1 && mlpos == -1)
1063 break;
1064
1065 if (slpos == -1) {
1066 pos = mlpos;
1067 len = multiLineComment.matchedLength();
1068 }
1069 else if (mlpos == -1) {
1070 pos = slpos;
1071 len = singleLineComment.matchedLength();
1072 }
1073 else {
1074 if (slpos < mlpos) {
1075 pos = slpos;
1076 len = singleLineComment.matchedLength();
1077 }
1078 else {
1079 pos = mlpos;
1080 len = multiLineComment.matchedLength();
1081 }
1082 }
1083
1084 if (result.at(pos + 1) == QLatin1Char(' ')) {
1085 result.remove(pos + len - 2, 1);
1086 result.remove(pos + 1, 1);
1087 len -= 2;
1088
1089 forever {
1090 int endcodePos = result.indexOf("\\ endcode", pos);
1091 if (endcodePos == -1 || endcodePos >= pos + len)
1092 break;
1093 result.remove(endcodePos + 1, 1);
1094 len -= 1;
1095 }
1096 }
1097 pos += len + insertTagAround(result, pos, len, "@comment");
1098 }
1099
1100 return result;
1101}
1102
1103#ifdef QDOC_QML
1104/*!
1105 This function is for documenting QML properties. It returns
1106 the list of documentation sections for the children of the
1107 \a qmlClassNode.
1108
1109 Currently, it only handles QML property groups.
1110 */
1111QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
1112 SynopsisStyle style)
1113{
1114 QList<Section> sections;
1115 if (qmlClassNode) {
1116 if (style == Summary) {
1117 FastSection qmlproperties(qmlClassNode,
1118 "Properties",
1119 "property",
1120 "properties");
1121 FastSection qmlattachedproperties(qmlClassNode,
1122 "Attached Properties",
1123 "property",
1124 "properties");
1125 FastSection qmlsignals(qmlClassNode,
1126 "Signals",
1127 "signal",
1128 "signals");
1129 FastSection qmlattachedsignals(qmlClassNode,
1130 "QML Attached Signals",
1131 "signal",
1132 "signals");
1133 FastSection qmlmethods(qmlClassNode,
1134 "Methods",
1135 "method",
1136 "methods");
1137 FastSection qmlattachedmethods(qmlClassNode,
1138 "QML Attached Methods",
1139 "method",
1140 "methods");
1141
1142 NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
1143 while (c != qmlClassNode->childNodes().end()) {
1144 if ((*c)->subType() == Node::QmlPropertyGroup) {
1145 const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c);
1146 NodeList::ConstIterator p = qpgn->childNodes().begin();
1147 while (p != qpgn->childNodes().end()) {
1148 if ((*p)->type() == Node::QmlProperty) {
1149 const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p);
1150 if (pn->isAttached())
1151 insert(qmlattachedproperties,*p,style,Okay);
1152 else
1153 insert(qmlproperties,*p,style,Okay);
1154 }
1155 ++p;
1156 }
1157 }
1158 else if ((*c)->type() == Node::QmlSignal) {
1159 const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
1160 if (sn->isAttached())
1161 insert(qmlattachedsignals,*c,style,Okay);
1162 else
1163 insert(qmlsignals,*c,style,Okay);
1164 }
1165 else if ((*c)->type() == Node::QmlMethod) {
1166 const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
1167 if (mn->isAttached())
1168 insert(qmlattachedmethods,*c,style,Okay);
1169 else
1170 insert(qmlmethods,*c,style,Okay);
1171 }
1172 ++c;
1173 }
1174 append(sections,qmlproperties);
1175 append(sections,qmlattachedproperties);
1176 append(sections,qmlsignals);
1177 append(sections,qmlattachedsignals);
1178 append(sections,qmlmethods);
1179 append(sections,qmlattachedmethods);
1180 }
1181 else if (style == Detailed) {
1182 FastSection qmlproperties(qmlClassNode, "Property Documentation");
1183 FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation");
1184 FastSection qmlsignals(qmlClassNode,"Signal Documentation");
1185 FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Documentation");
1186 FastSection qmlmethods(qmlClassNode,"Method Documentation");
1187 FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation");
1188 NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
1189 while (c != qmlClassNode->childNodes().end()) {
1190 if ((*c)->subType() == Node::QmlPropertyGroup) {
1191 const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c);
1192 if (pgn->isAttached())
1193 insert(qmlattachedproperties,*c,style,Okay);
1194 else
1195 insert(qmlproperties,*c,style,Okay);
1196 }
1197 else if ((*c)->type() == Node::QmlSignal) {
1198 const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
1199 if (sn->isAttached())
1200 insert(qmlattachedsignals,*c,style,Okay);
1201 else
1202 insert(qmlsignals,*c,style,Okay);
1203 }
1204 else if ((*c)->type() == Node::QmlMethod) {
1205 const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
1206 if (mn->isAttached())
1207 insert(qmlattachedmethods,*c,style,Okay);
1208 else
1209 insert(qmlmethods,*c,style,Okay);
1210 }
1211 ++c;
1212 }
1213 append(sections,qmlproperties);
1214 append(sections,qmlattachedproperties);
1215 append(sections,qmlsignals);
1216 append(sections,qmlattachedsignals);
1217 append(sections,qmlmethods);
1218 append(sections,qmlattachedmethods);
1219 }
1220 }
1221
1222 return sections;
1223}
1224#endif
1225
1226QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.