Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / qdoc3 / cppcodemarker.cpp
blob2df71339809b927ca1882532840224bb70e679fb
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
43 cppcodemarker.cpp
46 #include <qdebug.h>
47 #include "atom.h"
48 #include "cppcodemarker.h"
49 #include "node.h"
50 #include "text.h"
51 #include "tree.h"
53 QT_BEGIN_NAMESPACE
55 static int insertTagAround(QString &result, int pos, int len, const QString &tagName,
56 const QString &attributes = QString())
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;
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;
78 /*!
79 The constructor does nothing.
81 CppCodeMarker::CppCodeMarker()
83 // nothing.
86 /*!
87 The destructor does nothing.
89 CppCodeMarker::~CppCodeMarker()
91 // nothing.
94 /*!
95 Returns true.
97 bool CppCodeMarker::recognizeCode(const QString & /* code */)
99 return true;
103 Returns true if \a ext is any of a list of file extensions
104 for the C++ language.
106 bool CppCodeMarker::recognizeExtension(const QString& ext)
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";
122 Returns true if \a lang is either "C" or "Cpp".
124 bool CppCodeMarker::recognizeLanguage(const QString &lang)
126 return lang == "C" || lang == "Cpp";
130 Returns the \a node name, or "()" if \a node is a
131 Node::Function node.
133 QString CppCodeMarker::plainName(const Node *node)
135 QString name = node->name();
136 if (node->type() == Node::Function)
137 name += "()";
138 return name;
141 QString CppCodeMarker::plainFullName(const Node *node, const Node *relative)
143 if (node->name().isEmpty()) {
144 return "global";
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();
155 return fullName;
159 QString CppCodeMarker::markedUpCode(const QString &code,
160 const Node *relative,
161 const QString &dirPath)
163 return addMarkUp(protect(code), relative, dirPath);
166 QString CppCodeMarker::markedUpSynopsis(const Node *node,
167 const Node * /* relative */,
168 SynopsisStyle style)
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;
180 name = taggedNode(node);
181 if (style != Detailed)
182 name = linkTag(node, name);
183 name = "<@name>" + name + "</@name>";
185 if (style == Detailed && !node->parent()->name().isEmpty() &&
186 node->type() != Node::Property)
187 name.prepend(taggedNode(node->parent()) + "::");
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;
220 synopsis += " ";
222 synopsis += ")";
224 if (func->isConst())
225 synopsis += " const";
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");
233 else if (style == SeparateList) {
234 if (!func->returnType().isEmpty() && func->returnType() != "void")
235 synopsis += " : " + typified(func->returnType());
237 else {
238 QStringList bracketed;
239 if (func->isStatic()) {
240 bracketed += "static";
242 else if (func->virtualness() != FunctionNode::NonVirtual) {
243 if (func->virtualness() == FunctionNode::PureVirtual)
244 bracketed += "pure";
245 bracketed += "virtual";
248 if (func->access() == Node::Protected) {
249 bracketed += "protected";
251 else if (func->access() == Node::Private) {
252 bracketed += "private";
255 if (func->metaness() == FunctionNode::Signal) {
256 bracketed += "signal";
258 else if (func->metaness() == FunctionNode::Slot) {
259 bracketed += "slot";
261 if (!bracketed.isEmpty())
262 extra += " [" + bracketed.join(" ") + "]";
264 break;
265 case Node::Enum:
266 enume = static_cast<const EnumNode *>(node);
267 synopsis = "enum " + name;
268 if (style == Summary) {
269 synopsis += " { ";
271 QStringList documentedItems = enume->doc().enumItemNames();
272 if (documentedItems.isEmpty()) {
273 foreach (const EnumItem &item, enume->items())
274 documentedItems << item.name();
276 QStringList omitItems = enume->doc().omitEnumItemNames();
277 foreach (const QString &item, omitItems)
278 documentedItems.removeAll(item);
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);
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);
294 else if (i == MaxEnumValues - 1) {
295 synopsis += ", ...";
299 if (!documentedItems.isEmpty())
300 synopsis += " ";
301 synopsis += "}";
303 break;
304 case Node::Typedef:
305 typedeff = static_cast<const TypedefNode *>(node);
306 if (typedeff->associatedEnum()) {
307 synopsis = "flags " + name;
309 else {
310 synopsis = "typedef " + name;
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());
322 else {
323 synopsis = typified(variable->leftType()) + " " +
324 name + protect(variable->rightType());
326 break;
327 default:
328 synopsis = name;
331 if (style == Summary) {
332 if (node->status() == Node::Preliminary) {
333 extra += " (preliminary)";
335 else if (node->status() == Node::Deprecated) {
336 extra += " (deprecated)";
338 else if (node->status() == Node::Obsolete) {
339 extra += " (obsolete)";
343 if (!extra.isEmpty()) {
344 extra.prepend("<@extra>");
345 extra.append("</@extra>");
347 return synopsis + extra;
350 #ifdef QDOC_QML
353 QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
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('.'));
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());
370 QString extra;
371 if (summary) {
372 if (node->status() == Node::Preliminary) {
373 extra += " (preliminary)";
375 else if (node->status() == Node::Deprecated) {
376 extra += " (deprecated)";
378 else if (node->status() == Node::Obsolete) {
379 extra += " (obsolete)";
383 if (!extra.isEmpty()) {
384 extra.prepend("<@extra>");
385 extra.append("</@extra>");
387 return synopsis + extra;
389 #endif
391 QString CppCodeMarker::markedUpName(const Node *node)
393 QString name = linkTag(node, taggedNode(node));
394 if (node->type() == Node::Function)
395 name += "()";
396 return name;
399 QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative)
401 if (node->name().isEmpty()) {
402 return "global";
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();
413 return fullName;
417 QString CppCodeMarker::markedUpEnumValue(const QString &enumValue,
418 const Node *relative)
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();
429 if (!fullName.isEmpty())
430 fullName.append("<@op>::</@op>");
431 fullName.append(enumValue);
432 return fullName;
435 QString CppCodeMarker::markedUpIncludes(const QStringList& includes)
437 QString code;
439 QStringList::ConstIterator inc = includes.begin();
440 while (inc != includes.end()) {
441 code += "#include &lt;<@headerfile>" + *inc + "</@headerfile>&gt;\n";
442 ++inc;
444 return addMarkUp(code, 0, "");
447 QString CppCodeMarker::functionBeginRegExp(const QString& funcName)
449 return "^" + QRegExp::escape(funcName) + "$";
453 QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */)
455 return "^\\}$";
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
473 QList<Section> CppCodeMarker::sections(const InnerNode *inner,
474 SynopsisStyle style,
475 Status status)
477 QList<Section> sections;
479 if (inner->type() == Node::Class) {
480 const ClassNode *classe = static_cast<const ClassNode *>(inner);
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");
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);
544 else {
545 insert(relatedNonMembers, *r, style, status);
547 ++r;
550 QStack<const ClassNode *> stack;
551 stack.push(classe);
553 while (!stack.isEmpty()) {
554 const ClassNode *ancestorClass = stack.pop();
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();
567 else if ((*c)->type() == Node::Variable) {
568 const VariableNode *var = static_cast<const VariableNode *>(*c);
569 isStatic = var->isStatic();
572 switch ((*c)->access()) {
573 case Node::Public:
574 if (isSlot) {
575 insert(publicSlots, *c, style, status);
577 else if (isSignal) {
578 insert(publicSignals, *c, style, status);
580 else if (isStatic) {
581 if ((*c)->type() != Node::Variable
582 || !(*c)->doc().isEmpty())
583 insert(staticPublicMembers,*c,style,status);
585 else if ((*c)->type() == Node::Property) {
586 insert(properties, *c, style, status);
588 else if ((*c)->type() == Node::Variable) {
589 if (!(*c)->doc().isEmpty())
590 insert(publicVariables, *c, style, status);
592 else if ((*c)->type() == Node::Function) {
593 if (!insertReimpFunc(publicFunctions,*c,status))
594 insert(publicFunctions, *c, style, status);
596 else {
597 insert(publicTypes, *c, style, status);
599 break;
600 case Node::Protected:
601 if (isSlot) {
602 insert(protectedSlots, *c, style, status);
604 else if (isStatic) {
605 if ((*c)->type() != Node::Variable
606 || !(*c)->doc().isEmpty())
607 insert(staticProtectedMembers,*c,style,status);
609 else if ((*c)->type() == Node::Variable) {
610 if (!(*c)->doc().isEmpty())
611 insert(protectedVariables,*c,style,status);
613 else if ((*c)->type() == Node::Function) {
614 if (!insertReimpFunc(protectedFunctions,*c,status))
615 insert(protectedFunctions, *c, style, status);
617 else {
618 insert(protectedTypes, *c, style, status);
620 break;
621 case Node::Private:
622 if (isSlot) {
623 insert(privateSlots, *c, style, status);
625 else if (isStatic) {
626 if ((*c)->type() != Node::Variable
627 || !(*c)->doc().isEmpty())
628 insert(staticPrivateMembers,*c,style,status);
630 else if ((*c)->type() == Node::Function) {
631 if (!insertReimpFunc(privateFunctions,*c,status))
632 insert(privateFunctions, *c, style, status);
634 else {
635 insert(privateTypes,*c,style,status);
638 ++c;
641 QList<RelatedClass>::ConstIterator r =
642 ancestorClass->baseClasses().begin();
643 while (r != ancestorClass->baseClasses().end()) {
644 stack.prepend((*r).node);
645 ++r;
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);
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");
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);
685 else {
686 insert(relatedNonMembers, *r, style, status);
688 ++r;
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);
697 else if ((*c)->type() == Node::Property) {
698 insert(properties, *c, style, status);
700 else if ((*c)->type() == Node::Variable) {
701 if (!(*c)->doc().isEmpty())
702 insert(memberVariables, *c, style, status);
704 else if ((*c)->type() == Node::Function) {
705 FunctionNode *function = static_cast<FunctionNode *>(*c);
706 if (!function->associatedProperty())
707 insert(memberFunctions, function, style, status);
709 ++c;
712 append(sections, memberTypes);
713 append(sections, properties);
714 append(sections, memberFunctions);
715 append(sections, memberVariables);
716 append(sections, relatedNonMembers);
717 append(sections, macros);
719 else {
720 FastSection all(classe);
722 QStack<const ClassNode *> stack;
723 stack.push(classe);
725 while (!stack.isEmpty()) {
726 const ClassNode *ancestorClass = stack.pop();
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;
736 QList<RelatedClass>::ConstIterator r =
737 ancestorClass->baseClasses().begin();
738 while (r != ancestorClass->baseClasses().end()) {
739 stack.prepend((*r).node);
740 ++r;
743 append(sections, all);
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");
772 NodeList nodeList = inner->childNodes();
773 nodeList += inner->relatedNodes();
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:
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);
796 break;
797 default:
800 ++n;
802 append(sections, namespaces);
803 append(sections, classes);
804 append(sections, types);
805 append(sections, functions);
806 append(sections, macros);
810 return sections;
813 const Node *CppCodeMarker::resolveTarget(const QString &target,
814 const Tree *tree,
815 const Node *relative)
817 if (target.endsWith("()")) {
818 const FunctionNode *func;
819 QString funcName = target;
820 funcName.chop(2);
822 QStringList path = funcName.split("::");
823 if ((func = tree->findFunctionNode(path,
824 relative,
825 Tree::SearchBaseClasses))
826 && func->metaness() != FunctionNode::MacroWithoutParams)
827 return func;
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;
838 else {
839 QStringList path(link);
840 node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses);
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);
850 atom = atom->next();
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;
864 return 0;
867 QString CppCodeMarker::addMarkUp(const QString& protectedCode,
868 const Node * /* relative */,
869 const QString& /* dirPath */)
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 singleLineCommentLine("(?:^|\n)(?:[^&]|&(?!quot;)|&quot;(?:[^&\\\\]|&(?!quot;)|\\\\&quot;|\\\\(?!&quot;))*&quot;)*//(?!!)[^!\n]*");
885 static QRegExp singleLineComment("//(?!!)[^!\n]*");
886 static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define"
887 "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)");
888 static QRegExp literals("&quot;(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*&quot;"
889 "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'");
891 QString result = protectedCode;
892 int pos;
894 if (!hurryUp()) {
896 Mark global includes. For example:
898 #include &lt;<@headerfile>QString</@headerfile>
900 pos = 0;
901 while ((pos = result.indexOf(globalInclude, pos)) != -1)
902 pos += globalInclude.matchedLength()
903 + insertTagAround(result,
904 globalInclude.pos(1),
905 globalInclude.cap(1).length(),
906 "@headerfile");
909 Look for variable definitions and similar constructs, mark
910 the data type, and remember the type of the variable.
912 QMap<QString, QSet<QString> > typesForVariable;
913 pos = 0;
914 while ((pos = yHasTypeX.indexIn(result, pos)) != -1) {
915 QString x = yHasTypeX.cap(1);
916 QString y = yHasTypeX.cap(2);
918 if (!y.isEmpty())
919 typesForVariable[y].insert(x);
922 Without the minus one at the end, 'void member(Class
923 var)' would give 'member' as a variable of type 'void',
924 but would ignore 'Class var'. (### Is that true?)
926 pos += yHasTypeX.matchedLength()
927 + insertTagAround(result,
928 yHasTypeX.pos(1),
929 x.length(),
930 "@type") - 1;
934 Do syntax highlighting of preprocessor directives.
936 pos = 0;
937 while ((pos = preprocessor.indexIn(result, pos)) != -1)
938 pos += preprocessor.matchedLength()
939 + insertTagAround(result,
940 preprocessor.pos(1),
941 preprocessor.cap(1).length(),
942 "@preprocessor");
945 Deal with string and character literals.
947 pos = 0;
948 while ((pos = literals.indexIn(result, pos)) != -1)
949 pos += literals.matchedLength()
950 + insertTagAround(result,
951 pos,
952 literals.matchedLength(),
953 result.at(pos) ==
954 QLatin1Char(' ') ? "@string" : "@char");
957 Look for 'var = new Class'.
959 pos = 0;
960 while ((pos = xNewY.indexIn(result, pos)) != -1) {
961 QString x = xNewY.cap(1);
962 QString y = xNewY.cap(2);
963 typesForVariable[x].insert(y);
965 pos += xNewY.matchedLength() + insertTagAround(result,
966 xNewY.pos(2),
967 y.length(),
968 "@type");
972 Insert some stuff that cannot harm.
974 typesForVariable["qApp"].insert("QApplication");
977 Add link to ': Class'.
979 pos = 0;
980 while ((pos = classX.indexIn(result, pos)) != -1)
981 pos += classX.matchedLength()
982 + insertTagAround(result,
983 classX.pos(1),
984 classX.cap(1).length(),
985 "@type") - 1;
988 Find use of any of
990 var.method()
991 var->method()
992 var, SIGNAL(method())
993 var, SLOT(method()).
995 pos = 0;
996 while ((pos = xDotY.indexIn(result, pos)) != -1) {
997 QString x = xDotY.cap(1);
998 QString y = xDotY.cap(2);
1000 QSet<QString> types = typesForVariable.value(x);
1001 pos += xDotY.matchedLength()
1002 + insertTagAround(result,
1003 xDotY.pos(2),
1004 xDotY.cap(2).length(),
1005 "@func",
1006 (types.count() == 1) ? "target=\""
1007 + protect(*types.begin() + "::" + y)
1008 + "()\"" : QString());
1012 Add link to 'Class::method()'.
1014 pos = 0;
1015 while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) {
1016 QString x = xIsStaticZOfY.cap(1);
1017 QString z = xIsStaticZOfY.cap(3);
1019 pos += insertTagAround(result,
1020 xIsStaticZOfY.pos(3),
1021 z.length(),
1022 "@func",
1023 "target=\"" + protect(x) + "()\"");
1024 pos += insertTagAround(result,
1025 xIsStaticZOfY.pos(2),
1026 xIsStaticZOfY.cap(2).length(),
1027 "@type");
1028 pos += xIsStaticZOfY.matchedLength() - 1;
1032 Add link to 'globalFunction()'.
1034 pos = 0;
1035 while ((pos = globalX.indexIn(result, pos)) != -1) {
1036 QString x = globalX.cap(1);
1037 if (x != "QT_FORWARD_DECLARE_CLASS") {
1038 pos += globalX.matchedLength()
1039 + insertTagAround(result,
1040 globalX.pos(1),
1041 x.length(),
1042 "@func",
1043 "target=\"" + protect(x) + "()\"") - 1;
1045 else
1046 pos += globalX.matchedLength();
1051 Do syntax highlighting of comments. Also alter the code in a
1052 minor way, so that we can include comments in documentation
1053 comments.
1055 pos = 0;
1056 while (pos != -1) {
1057 int mlpos;
1058 int slpos;
1059 int len;
1060 int sllpos = singleLineCommentLine.indexIn(result, pos);
1061 slpos = sllpos == -1 ? -1 : singleLineComment.indexIn(result, sllpos);
1062 mlpos = multiLineComment.indexIn(result, pos);
1064 if (slpos == -1 && mlpos == -1)
1065 break;
1067 if (slpos == -1) {
1068 pos = mlpos;
1069 len = multiLineComment.matchedLength();
1071 else if (mlpos == -1) {
1072 pos = slpos;
1073 len = singleLineComment.matchedLength();
1075 else {
1076 if (slpos < mlpos) {
1077 pos = slpos;
1078 len = singleLineComment.matchedLength();
1080 else {
1081 pos = mlpos;
1082 len = multiLineComment.matchedLength();
1086 if (result.at(pos + 1) == QLatin1Char(' ')) {
1087 result.remove(pos + len - 2, 1);
1088 result.remove(pos + 1, 1);
1089 len -= 2;
1091 forever {
1092 int endcodePos = result.indexOf("\\ endcode", pos);
1093 if (endcodePos == -1 || endcodePos >= pos + len)
1094 break;
1095 result.remove(endcodePos + 1, 1);
1096 len -= 1;
1099 pos += len + insertTagAround(result, pos, len, "@comment");
1102 return result;
1105 #ifdef QDOC_QML
1107 This function is for documenting QML properties. It returns
1108 the list of documentation sections for the children of the
1109 \a qmlClassNode.
1111 Currently, it only handles QML property groups.
1113 QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
1114 SynopsisStyle style)
1116 QList<Section> sections;
1117 if (qmlClassNode) {
1118 if (style == Summary) {
1119 FastSection qmlproperties(qmlClassNode,
1120 "Properties",
1121 "property",
1122 "properties");
1123 FastSection qmlattachedproperties(qmlClassNode,
1124 "Attached Properties",
1125 "property",
1126 "properties");
1127 FastSection qmlsignals(qmlClassNode,
1128 "Signals",
1129 "signal",
1130 "signals");
1131 FastSection qmlattachedsignals(qmlClassNode,
1132 "QML Attached Signals",
1133 "signal",
1134 "signals");
1135 FastSection qmlmethods(qmlClassNode,
1136 "Methods",
1137 "method",
1138 "methods");
1139 FastSection qmlattachedmethods(qmlClassNode,
1140 "QML Attached Methods",
1141 "method",
1142 "methods");
1144 NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
1145 while (c != qmlClassNode->childNodes().end()) {
1146 if ((*c)->subType() == Node::QmlPropertyGroup) {
1147 const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c);
1148 NodeList::ConstIterator p = qpgn->childNodes().begin();
1149 while (p != qpgn->childNodes().end()) {
1150 if ((*p)->type() == Node::QmlProperty) {
1151 const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p);
1152 if (pn->isAttached())
1153 insert(qmlattachedproperties,*p,style,Okay);
1154 else
1155 insert(qmlproperties,*p,style,Okay);
1157 ++p;
1160 else if ((*c)->type() == Node::QmlSignal) {
1161 const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
1162 if (sn->isAttached())
1163 insert(qmlattachedsignals,*c,style,Okay);
1164 else
1165 insert(qmlsignals,*c,style,Okay);
1167 else if ((*c)->type() == Node::QmlMethod) {
1168 const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
1169 if (mn->isAttached())
1170 insert(qmlattachedmethods,*c,style,Okay);
1171 else
1172 insert(qmlmethods,*c,style,Okay);
1174 ++c;
1176 append(sections,qmlproperties);
1177 append(sections,qmlattachedproperties);
1178 append(sections,qmlsignals);
1179 append(sections,qmlattachedsignals);
1180 append(sections,qmlmethods);
1181 append(sections,qmlattachedmethods);
1183 else if (style == Detailed) {
1184 FastSection qmlproperties(qmlClassNode, "Property Documentation");
1185 FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation");
1186 FastSection qmlsignals(qmlClassNode,"Signal Documentation");
1187 FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Documentation");
1188 FastSection qmlmethods(qmlClassNode,"Method Documentation");
1189 FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation");
1190 NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
1191 while (c != qmlClassNode->childNodes().end()) {
1192 if ((*c)->subType() == Node::QmlPropertyGroup) {
1193 const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c);
1194 if (pgn->isAttached())
1195 insert(qmlattachedproperties,*c,style,Okay);
1196 else
1197 insert(qmlproperties,*c,style,Okay);
1199 else if ((*c)->type() == Node::QmlSignal) {
1200 const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
1201 if (sn->isAttached())
1202 insert(qmlattachedsignals,*c,style,Okay);
1203 else
1204 insert(qmlsignals,*c,style,Okay);
1206 else if ((*c)->type() == Node::QmlMethod) {
1207 const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
1208 if (mn->isAttached())
1209 insert(qmlattachedmethods,*c,style,Okay);
1210 else
1211 insert(qmlmethods,*c,style,Okay);
1213 ++c;
1215 append(sections,qmlproperties);
1216 append(sections,qmlattachedproperties);
1217 append(sections,qmlsignals);
1218 append(sections,qmlattachedsignals);
1219 append(sections,qmlmethods);
1220 append(sections,qmlattachedmethods);
1224 return sections;
1226 #endif
1228 QT_END_NAMESPACE