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

Last change on this file since 348 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 33.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*
43 cppcodemarker.cpp
44*/
45
46#include "atom.h"
47#include "cppcodemarker.h"
48#include "node.h"
49#include "text.h"
50#include "tree.h"
51
52QT_BEGIN_NAMESPACE
53
54static int insertTagAround(QString &result, int pos, int len, const QString &tagName,
55 const QString &attributes = QString())
56{
57 QString s;
58 //s.reserve(result.size() + tagName.size() * 2 + attributes.size() + 20);
59 s += result.midRef(0, pos);
60 s += QLatin1Char('<');
61 s += tagName;
62 if (!attributes.isEmpty()) {
63 s += QLatin1Char(' ');
64 s += attributes;
65 }
66 s += QLatin1Char('>');
67 s += result.midRef(pos, len);
68 s += QLatin1String("</");
69 s += tagName;
70 s += QLatin1Char('>');
71 s += result.midRef(pos + len);
72 int diff = s.length() - result.length();
73 result = s;
74 return diff;
75}
76
77/*!
78 The constructor does nothing.
79 */
80CppCodeMarker::CppCodeMarker()
81{
82 // nothing.
83}
84
85/*!
86 The destructor does nothing.
87 */
88CppCodeMarker::~CppCodeMarker()
89{
90 // nothing.
91}
92
93/*!
94 Returns true.
95 */
96bool CppCodeMarker::recognizeCode(const QString & /* code */)
97{
98 return true;
99}
100
101/*!
102 Returns true if \a ext is any of a list of file extensions
103 for the C++ language.
104 */
105bool CppCodeMarker::recognizeExtension(const QString& ext)
106{
107 return ext == "c" ||
108 ext == "c++" ||
109 ext == "cc" ||
110 ext == "cpp" ||
111 ext == "cxx" ||
112 ext == "ch" ||
113 ext == "h" ||
114 ext == "h++" ||
115 ext == "hh" ||
116 ext == "hpp" ||
117 ext == "hxx";
118}
119
120/*!
121 Returns true if \a lang is either "C" or "Cpp".
122 */
123bool CppCodeMarker::recognizeLanguage(const QString &lang)
124{
125 return lang == "C" || lang == "Cpp";
126}
127
128/*!
129 Returns the \a node name, or "()" if \a node is a
130 Node::Function node.
131 */
132QString CppCodeMarker::plainName(const Node *node)
133{
134 QString name = node->name();
135 if (node->type() == Node::Function)
136 name += "()";
137 return name;
138}
139
140QString CppCodeMarker::plainFullName(const Node *node, const Node *relative)
141{
142 if (node->name().isEmpty()) {
143 return "global";
144 }
145 else {
146 QString fullName;
147 for (;;) {
148 fullName.prepend(plainName(node));
149 if (node->parent() == relative || node->parent()->name().isEmpty())
150 break;
151 fullName.prepend("::");
152 node = node->parent();
153 }
154 return fullName;
155 }
156}
157
158QString CppCodeMarker::markedUpCode(const QString &code,
159 const Node *relative,
160 const QString &dirPath)
161{
162 return addMarkUp(protect(code), relative, dirPath);
163}
164
165QString CppCodeMarker::markedUpSynopsis(const Node *node,
166 const Node * /* relative */,
167 SynopsisStyle style)
168{
169 const int MaxEnumValues = 6;
170 const FunctionNode *func;
171 const PropertyNode *property;
172 const VariableNode *variable;
173 const EnumNode *enume;
174 const TypedefNode *typedeff;
175 QString synopsis;
176 QString extra;
177 QString name;
178
179 name = taggedNode(node);
180 if (style != Detailed)
181 name = linkTag(node, name);
182 name = "<@name>" + name + "</@name>";
183
184 if (style == Detailed && !node->parent()->name().isEmpty() &&
185 node->type() != Node::Property)
186 name.prepend(taggedNode(node->parent()) + "::");
187
188 switch (node->type()) {
189 case Node::Namespace:
190 synopsis = "namespace " + name;
191 break;
192 case Node::Class:
193 synopsis = "class " + name;
194 break;
195 case Node::Function:
196 func = (const FunctionNode *) node;
197 if (style != SeparateList && !func->returnType().isEmpty())
198 synopsis = typified(func->returnType()) + " ";
199 synopsis += name;
200 if (func->metaness() != FunctionNode::MacroWithoutParams) {
201 synopsis += " (";
202 if (!func->parameters().isEmpty()) {
203 synopsis += " ";
204 QList<Parameter>::ConstIterator p = func->parameters().begin();
205 while (p != func->parameters().end()) {
206 if (p != func->parameters().begin())
207 synopsis += ", ";
208 synopsis += typified((*p).leftType());
209 if (style != SeparateList && !(*p).name().isEmpty())
210 synopsis +=
211 " <@param>" + protect((*p).name()) + "</@param>";
212 synopsis += protect((*p).rightType());
213 if (style != SeparateList && !(*p).defaultValue().isEmpty())
214 synopsis += " = " + protect((*p).defaultValue());
215 ++p;
216 }
217 synopsis += " ";
218 }
219 synopsis += ")";
220 }
221 if (func->isConst())
222 synopsis += " const";
223
224 if (style == Summary || style == Accessors) {
225 if (func->virtualness() != FunctionNode::NonVirtual)
226 synopsis.prepend("virtual ");
227 if (func->virtualness() == FunctionNode::PureVirtual)
228 synopsis.append(" = 0");
229 }
230 else if (style == SeparateList) {
231 if (!func->returnType().isEmpty() && func->returnType() != "void")
232 synopsis += " : " + typified(func->returnType());
233 }
234 else {
235 QStringList bracketed;
236 if (func->isStatic()) {
237 bracketed += "static";
238 }
239 else if (func->virtualness() != FunctionNode::NonVirtual) {
240 if (func->virtualness() == FunctionNode::PureVirtual)
241 bracketed += "pure";
242 bracketed += "virtual";
243 }
244
245 if (func->access() == Node::Protected) {
246 bracketed += "protected";
247 }
248 else if (func->access() == Node::Private) {
249 bracketed += "private";
250 }
251
252 if (func->metaness() == FunctionNode::Signal) {
253 bracketed += "signal";
254 }
255 else if (func->metaness() == FunctionNode::Slot) {
256 bracketed += "slot";
257 }
258 if (!bracketed.isEmpty())
259 extra += " [" + bracketed.join(" ") + "]";
260 }
261 break;
262 case Node::Enum:
263 enume = static_cast<const EnumNode *>(node);
264 synopsis = "enum " + name;
265 if (style == Summary) {
266 synopsis += " { ";
267
268 QStringList documentedItems = enume->doc().enumItemNames();
269 if (documentedItems.isEmpty()) {
270 foreach (const EnumItem &item, enume->items())
271 documentedItems << item.name();
272 }
273 QStringList omitItems = enume->doc().omitEnumItemNames();
274 foreach (const QString &item, omitItems)
275 documentedItems.removeAll(item);
276
277 if (documentedItems.size() <= MaxEnumValues) {
278 for (int i = 0; i < documentedItems.size(); ++i) {
279 if (i != 0)
280 synopsis += ", ";
281 synopsis += documentedItems.at(i);
282 }
283 }
284 else {
285 for (int i = 0; i < documentedItems.size(); ++i) {
286 if (i < MaxEnumValues - 2 || i == documentedItems.size() - 1) {
287 if (i != 0)
288 synopsis += ", ";
289 synopsis += documentedItems.at(i);
290 }
291 else if (i == MaxEnumValues - 1) {
292 synopsis += ", ...";
293 }
294 }
295 }
296 if (!documentedItems.isEmpty())
297 synopsis += " ";
298 synopsis += "}";
299 }
300 break;
301 case Node::Typedef:
302 typedeff = static_cast<const TypedefNode *>(node);
303 if (typedeff->associatedEnum()) {
304 synopsis = "flags " + name;
305 }
306 else {
307 synopsis = "typedef " + name;
308 }
309 break;
310 case Node::Property:
311 property = static_cast<const PropertyNode *>(node);
312 synopsis = name + " : " + typified(property->qualifiedDataType());
313 break;
314 case Node::Variable:
315 variable = static_cast<const VariableNode *>(node);
316 if (style == SeparateList) {
317 synopsis = name + " : " + typified(variable->dataType());
318 }
319 else {
320 synopsis = typified(variable->leftType()) + " " +
321 name + protect(variable->rightType());
322 }
323 break;
324 default:
325 synopsis = name;
326 }
327
328 if (style == Summary) {
329 if (node->status() == Node::Preliminary) {
330 extra += " (preliminary)";
331 }
332 else if (node->status() == Node::Deprecated) {
333 extra += " (deprecated)";
334 }
335 else if (node->status() == Node::Obsolete) {
336 extra += " (obsolete)";
337 }
338 }
339
340 if (!extra.isEmpty()) {
341 extra.prepend("<@extra>");
342 extra.append("</@extra>");
343 }
344 return synopsis + extra;
345}
346
347QString CppCodeMarker::markedUpName(const Node *node)
348{
349 QString name = linkTag(node, taggedNode(node));
350 if (node->type() == Node::Function)
351 name += "()";
352 return name;
353}
354
355QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative)
356{
357 if (node->name().isEmpty()) {
358 return "global";
359 }
360 else {
361 QString fullName;
362 for (;;) {
363 fullName.prepend(markedUpName(node));
364 if (node->parent() == relative || node->parent()->name().isEmpty())
365 break;
366 fullName.prepend("<@op>::</@op>");
367 node = node->parent();
368 }
369 return fullName;
370 }
371}
372
373QString CppCodeMarker::markedUpEnumValue(const QString &enumValue,
374 const Node *relative)
375{
376 const Node *node = relative->parent();
377 QString fullName;
378 while (node->parent()) {
379 fullName.prepend(markedUpName(node));
380 if (node->parent() == relative || node->parent()->name().isEmpty())
381 break;
382 fullName.prepend("<@op>::</@op>");
383 node = node->parent();
384 }
385 if (!fullName.isEmpty())
386 fullName.append("<@op>::</@op>");
387 fullName.append(enumValue);
388 return fullName;
389}
390
391QString CppCodeMarker::markedUpIncludes(const QStringList& includes)
392{
393 QString code;
394
395 QStringList::ConstIterator inc = includes.begin();
396 while (inc != includes.end()) {
397 code += "#include &lt;<@headerfile>" + *inc + "</@headerfile>&gt;\n";
398 ++inc;
399 }
400 return addMarkUp(code, 0, "");
401}
402
403QString CppCodeMarker::functionBeginRegExp(const QString& funcName)
404{
405 return "^" + QRegExp::escape(funcName) + "$";
406
407}
408
409QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */)
410{
411 return "^\\}$";
412}
413
414QList<Section> CppCodeMarker::sections(const InnerNode *inner,
415 SynopsisStyle style,
416 Status status)
417{
418 QList<Section> sections;
419
420 if (inner->type() == Node::Class) {
421 const ClassNode *classe = static_cast<const ClassNode *>(inner);
422
423 if (style == Summary) {
424 FastSection privateFunctions(classe, "Private Functions", "private function",
425 "private functions");
426 FastSection privateSlots(classe, "Private Slots", "private slot", "private slots");
427 FastSection privateTypes(classe, "Private Types", "private type", "private types");
428 FastSection protectedFunctions(classe, "Protected Functions", "protected function",
429 "protected functions");
430 FastSection protectedSlots(classe, "Protected Slots", "protected slot", "protected slots");
431 FastSection protectedTypes(classe, "Protected Types", "protected type", "protected types");
432 FastSection protectedVariables(classe, "Protected Variables", "protected type", "protected variables");
433 FastSection publicFunctions(classe, "Public Functions", "public function",
434 "public functions");
435 FastSection publicSignals(classe, "Signals", "signal", "signals");
436 FastSection publicSlots(classe, "Public Slots", "public slot", "public slots");
437 FastSection publicTypes(classe, "Public Types", "public type", "public types");
438 FastSection publicVariables(classe, "Public Variables", "public type", "public variables");
439 FastSection properties(classe, "Properties", "property", "properties");
440 FastSection relatedNonMembers(classe, "Related Non-Members", "related non-member",
441 "related non-members");
442 FastSection staticPrivateMembers(classe, "Static Private Members", "static private member",
443 "static private members");
444 FastSection staticProtectedMembers(classe, "Static Protected Members",
445 "static protected member", "static protected members");
446 FastSection staticPublicMembers(classe, "Static Public Members", "static public member",
447 "static public members");
448 FastSection macros(inner, "Macros", "macro", "macros");
449
450 NodeList::ConstIterator r = classe->relatedNodes().begin();
451 while (r != classe->relatedNodes().end()) {
452 if ((*r)->type() == Node::Function) {
453 FunctionNode *func = static_cast<FunctionNode *>(*r);
454 if (func->isMacro())
455 insert(macros, *r, style, status);
456 else
457 insert(relatedNonMembers, *r, style, status);
458 }
459 else {
460 insert(relatedNonMembers, *r, style, status);
461 }
462 ++r;
463 }
464
465 QStack<const ClassNode *> stack;
466 stack.push(classe);
467
468 while (!stack.isEmpty()) {
469 const ClassNode *ancestorClass = stack.pop();
470
471 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
472 while (c != ancestorClass->childNodes().end()) {
473 bool isSlot = false;
474 bool isSignal = false;
475 bool isStatic = false;
476 if ((*c)->type() == Node::Function) {
477 const FunctionNode *func = (const FunctionNode *) *c;
478 isSlot = (func->metaness() == FunctionNode::Slot);
479 isSignal = (func->metaness() == FunctionNode::Signal);
480 isStatic = func->isStatic();
481 }
482 else if ((*c)->type() == Node::Variable) {
483 const VariableNode *var = static_cast<const VariableNode *>(*c);
484 isStatic = var->isStatic();
485 }
486
487 switch ((*c)->access()) {
488 case Node::Public:
489 if (isSlot) {
490 insert(publicSlots, *c, style, status);
491 }
492 else if (isSignal) {
493 insert(publicSignals, *c, style, status);
494 }
495 else if (isStatic) {
496 if ((*c)->type() != Node::Variable
497 || !(*c)->doc().isEmpty())
498 insert(staticPublicMembers, *c, style, status);
499 }
500 else if ((*c)->type() == Node::Property) {
501 insert(properties, *c, style, status);
502 }
503 else if ((*c)->type() == Node::Variable) {
504 if (!(*c)->doc().isEmpty())
505 insert(publicVariables, *c, style, status);
506 }
507 else if ((*c)->type() == Node::Function) {
508 insert(publicFunctions, *c, style, status);
509 }
510 else {
511 insert(publicTypes, *c, style, status);
512 }
513 break;
514 case Node::Protected:
515 if (isSlot) {
516 insert(protectedSlots, *c, style, status);
517 }
518 else if (isStatic) {
519 if ((*c)->type() != Node::Variable
520 || !(*c)->doc().isEmpty())
521 insert(staticProtectedMembers, *c, style, status);
522 }
523 else if ((*c)->type() == Node::Variable) {
524 if (!(*c)->doc().isEmpty())
525 insert(protectedVariables, *c, style, status);
526 }
527 else if ((*c)->type() == Node::Function) {
528 insert(protectedFunctions, *c, style, status);
529 }
530 else {
531 insert(protectedTypes, *c, style, status);
532 }
533 break;
534 case Node::Private:
535 if (isSlot) {
536 insert(privateSlots, *c, style, status);
537 }
538 else if (isStatic) {
539 if ((*c)->type() != Node::Variable
540 || !(*c)->doc().isEmpty())
541 insert(staticPrivateMembers, *c, style, status);
542 }
543 else if ((*c)->type() == Node::Function) {
544 insert(privateFunctions, *c, style, status);
545 }
546 else {
547 insert(privateTypes, *c, style, status);
548 }
549 }
550 ++c;
551 }
552
553 QList<RelatedClass>::ConstIterator r =
554 ancestorClass->baseClasses().begin();
555 while (r != ancestorClass->baseClasses().end()) {
556 stack.prepend((*r).node);
557 ++r;
558 }
559 }
560
561 append(sections, publicTypes);
562 append(sections, properties);
563 append(sections, publicFunctions);
564 append(sections, publicSlots);
565 append(sections, publicSignals);
566 append(sections, publicVariables);
567 append(sections, staticPublicMembers);
568 append(sections, protectedTypes);
569 append(sections, protectedFunctions);
570 append(sections, protectedSlots);
571 append(sections, protectedVariables);
572 append(sections, staticProtectedMembers);
573 append(sections, privateTypes);
574 append(sections, privateFunctions);
575 append(sections, privateSlots);
576 append(sections, staticPrivateMembers);
577 append(sections, relatedNonMembers);
578 append(sections, macros);
579 }
580 else if (style == Detailed) {
581 FastSection memberFunctions(classe,"Member Function Documentation");
582 FastSection memberTypes(classe,"Member Type Documentation");
583 FastSection memberVariables(classe,"Member Variable Documentation");
584 FastSection properties(classe,"Property Documentation");
585 FastSection relatedNonMembers(classe,"Related Non-Members");
586 FastSection macros(classe,"Macro Documentation");
587
588 NodeList::ConstIterator r = classe->relatedNodes().begin();
589 while (r != classe->relatedNodes().end()) {
590 if ((*r)->type() == Node::Function) {
591 FunctionNode *func = static_cast<FunctionNode *>(*r);
592 if (func->isMacro())
593 insert(macros, *r, style, status);
594 else
595 insert(relatedNonMembers, *r, style, status);
596 }
597 else {
598 insert(relatedNonMembers, *r, style, status);
599 }
600 ++r;
601 }
602
603 NodeList::ConstIterator c = classe->childNodes().begin();
604 while (c != classe->childNodes().end()) {
605 if ((*c)->type() == Node::Enum ||
606 (*c)->type() == Node::Typedef) {
607 insert(memberTypes, *c, style, status);
608 }
609 else if ((*c)->type() == Node::Property) {
610 insert(properties, *c, style, status);
611 }
612 else if ((*c)->type() == Node::Variable) {
613 if (!(*c)->doc().isEmpty())
614 insert(memberVariables, *c, style, status);
615 }
616 else if ((*c)->type() == Node::Function) {
617 FunctionNode *function = static_cast<FunctionNode *>(*c);
618 if (!function->associatedProperty())
619 insert(memberFunctions, function, style, status);
620 }
621 ++c;
622 }
623
624 append(sections, memberTypes);
625 append(sections, properties);
626 append(sections, memberFunctions);
627 append(sections, memberVariables);
628 append(sections, relatedNonMembers);
629 append(sections, macros);
630 }
631 else {
632 FastSection all(classe);
633
634 QStack<const ClassNode *> stack;
635 stack.push(classe);
636
637 while (!stack.isEmpty()) {
638 const ClassNode *ancestorClass = stack.pop();
639
640 NodeList::ConstIterator c = ancestorClass->childNodes().begin();
641 while (c != ancestorClass->childNodes().end()) {
642 if ((*c)->access() != Node::Private &&
643 (*c)->type() != Node::Property)
644 insert(all, *c, style, status);
645 ++c;
646 }
647
648 QList<RelatedClass>::ConstIterator r =
649 ancestorClass->baseClasses().begin();
650 while (r != ancestorClass->baseClasses().end()) {
651 stack.prepend((*r).node);
652 ++r;
653 }
654 }
655 append(sections, all);
656 }
657 }
658 else {
659 if (style == Summary || style == Detailed) {
660 FastSection namespaces(inner,
661 "Namespaces",
662 "namespace",
663 "namespaces");
664 FastSection classes(inner, "Classes", "class", "classes");
665 FastSection types(inner,
666 style == Summary ? "Types" : "Type Documentation",
667 "type",
668 "types");
669 FastSection functions(inner,
670 style == Summary ? "Functions" : "Function Documentation",
671 "function",
672 "functions");
673 FastSection macros(inner,
674 style == Summary ? "Macros" : "Macro Documentation",
675 "macro",
676 "macros");
677
678 NodeList nodeList = inner->childNodes();
679 nodeList += inner->relatedNodes();
680
681 NodeList::ConstIterator n = nodeList.begin();
682 while (n != nodeList.end()) {
683 switch ((*n)->type()) {
684 case Node::Namespace:
685 insert(namespaces, *n, style, status);
686 break;
687 case Node::Class:
688 insert(classes, *n, style, status);
689 break;
690 case Node::Enum:
691 case Node::Typedef:
692 insert(types, *n, style, status);
693 break;
694 case Node::Function:
695 {
696 FunctionNode *func = static_cast<FunctionNode *>(*n);
697 if (func->isMacro())
698 insert(macros, *n, style, status);
699 else
700 insert(functions, *n, style, status);
701 }
702 break;
703 default:
704 ;
705 }
706 ++n;
707 }
708 append(sections, namespaces);
709 append(sections, classes);
710 append(sections, types);
711 append(sections, functions);
712 append(sections, macros);
713 }
714 }
715
716 return sections;
717}
718
719const Node *CppCodeMarker::resolveTarget(const QString &target,
720 const Tree *tree,
721 const Node *relative)
722{
723 if (target.endsWith("()")) {
724 const FunctionNode *func;
725 QString funcName = target;
726 funcName.chop(2);
727
728 QStringList path = funcName.split("::");
729 if ((func = tree->findFunctionNode(path,
730 relative,
731 Tree::SearchBaseClasses))
732 && func->metaness() != FunctionNode::MacroWithoutParams)
733 return func;
734 }
735 else if (target.contains("#")) {
736 // ### this doesn't belong here; get rid of TargetNode hack
737 int hashAt = target.indexOf("#");
738 QString link = target.left(hashAt);
739 QString ref = target.mid(hashAt + 1);
740 const Node *node;
741 if (link.isEmpty()) {
742 node = relative;
743 }
744 else {
745 QStringList path(link);
746 node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses);
747 }
748 if (node && node->isInnerNode()) {
749 const Atom *atom = node->doc().body().firstAtom();
750 while (atom) {
751 if (atom->type() == Atom::Target && atom->string() == ref) {
752 Node *parentNode = const_cast<Node *>(node);
753 return new TargetNode(static_cast<InnerNode*>(parentNode),
754 ref);
755 }
756 atom = atom->next();
757 }
758 }
759 }
760 else {
761 QStringList path = target.split("::");
762 const Node *node;
763 if ((node = tree->findNode(path,
764 relative,
765 Tree::SearchBaseClasses |
766 Tree::SearchEnumValues |
767 Tree::NonFunction)))
768 return node;
769 }
770 return 0;
771}
772
773QString CppCodeMarker::addMarkUp(const QString& protectedCode,
774 const Node * /* relative */,
775 const QString& /* dirPath */)
776{
777 static QRegExp globalInclude("#include +&lt;([^<>&]+)&gt;");
778 static QRegExp yHasTypeX("(?:^|\n *)([a-zA-Z_][a-zA-Z_0-9]*)"
779 "(?:&lt;[^;{}]+&gt;)?(?: *(?:\\*|&amp;) *| +)"
780 "([a-zA-Z_][a-zA-Z_0-9]*)? *[,;()=]");
781 static QRegExp xNewY("([a-zA-Z_][a-zA-Z_0-9]*) *= *new +([a-zA-Z_0-9]+)");
782 static QRegExp xDotY("\\b([a-zA-Z_][a-zA-Z_0-9]*) *(?:\\.|-&gt;|,[ \n]*S(?:IGNAL|LOT)\\() *"
783 "([a-zA-Z_][a-zA-Z_0-9]*)(?= *\\()");
784 static QRegExp xIsStaticZOfY("[\n:;{(=] *(([a-zA-Z_0-9]+)::([a-zA-Z_0-9]+))(?= *\\()");
785 static QRegExp classX("[:,][ \n]*(?:p(?:ublic|r(?:otected|ivate))[ \n]+)?"
786 "([a-zA-Z_][a-zA-Z_0-9]*)");
787 static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\(");
788 static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)");
789 multiLineComment.setMinimal(true);
790 static QRegExp singleLineComment("//(?!!)[^!\n]*");
791 static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define"
792 "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)");
793 static QRegExp literals("&quot;(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*&quot;"
794 "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'");
795
796 QString result = protectedCode;
797 int pos;
798
799 if (!hurryUp()) {
800 /*
801 Mark global includes. For example:
802
803 #include &lt;<@headerfile>QString</@headerfile>
804 */
805 pos = 0;
806 while ((pos = result.indexOf(globalInclude, pos)) != -1)
807 pos += globalInclude.matchedLength()
808 + insertTagAround(result,
809 globalInclude.pos(1),
810 globalInclude.cap(1).length(),
811 "@headerfile");
812
813 /*
814 Look for variable definitions and similar constructs, mark
815 the data type, and remember the type of the variable.
816 */
817 QMap<QString, QSet<QString> > typesForVariable;
818 pos = 0;
819 while ((pos = yHasTypeX.indexIn(result, pos)) != -1) {
820 QString x = yHasTypeX.cap(1);
821 QString y = yHasTypeX.cap(2);
822
823 if (!y.isEmpty())
824 typesForVariable[y].insert(x);
825
826 /*
827 Without the minus one at the end, 'void member(Class
828 var)' would give 'member' as a variable of type 'void',
829 but would ignore 'Class var'. (### Is that true?)
830 */
831 pos += yHasTypeX.matchedLength()
832 + insertTagAround(result,
833 yHasTypeX.pos(1),
834 x.length(),
835 "@type") - 1;
836 }
837
838 /*
839 Do syntax highlighting of preprocessor directives.
840 */
841 pos = 0;
842 while ((pos = preprocessor.indexIn(result, pos)) != -1)
843 pos += preprocessor.matchedLength()
844 + insertTagAround(result,
845 preprocessor.pos(1),
846 preprocessor.cap(1).length(),
847 "@preprocessor");
848
849 /*
850 Deal with string and character literals.
851 */
852 pos = 0;
853 while ((pos = literals.indexIn(result, pos)) != -1)
854 pos += literals.matchedLength()
855 + insertTagAround(result,
856 pos,
857 literals.matchedLength(),
858 result.at(pos) ==
859 QLatin1Char(' ') ? "@string" : "@char");
860
861 /*
862 Look for 'var = new Class'.
863 */
864 pos = 0;
865 while ((pos = xNewY.indexIn(result, pos)) != -1) {
866 QString x = xNewY.cap(1);
867 QString y = xNewY.cap(2);
868 typesForVariable[x].insert(y);
869
870 pos += xNewY.matchedLength() + insertTagAround(result,
871 xNewY.pos(2),
872 y.length(),
873 "@type");
874 }
875
876 /*
877 Insert some stuff that cannot harm.
878 */
879 typesForVariable["qApp"].insert("QApplication");
880
881 /*
882 Add link to ': Class'.
883 */
884 pos = 0;
885 while ((pos = classX.indexIn(result, pos)) != -1)
886 pos += classX.matchedLength()
887 + insertTagAround(result,
888 classX.pos(1),
889 classX.cap(1).length(),
890 "@type") - 1;
891
892 /*
893 Find use of any of
894
895 var.method()
896 var->method()
897 var, SIGNAL(method())
898 var, SLOT(method()).
899 */
900 pos = 0;
901 while ((pos = xDotY.indexIn(result, pos)) != -1) {
902 QString x = xDotY.cap(1);
903 QString y = xDotY.cap(2);
904
905 QSet<QString> types = typesForVariable.value(x);
906 pos += xDotY.matchedLength()
907 + insertTagAround(result,
908 xDotY.pos(2),
909 xDotY.cap(2).length(),
910 "@func",
911 (types.count() == 1) ? "target=\""
912 + protect(*types.begin() + "::" + y)
913 + "()\"" : QString());
914 }
915
916 /*
917 Add link to 'Class::method()'.
918 */
919 pos = 0;
920 while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) {
921 QString x = xIsStaticZOfY.cap(1);
922 QString z = xIsStaticZOfY.cap(3);
923
924 pos += insertTagAround(result,
925 xIsStaticZOfY.pos(3),
926 z.length(),
927 "@func",
928 "target=\"" + protect(x) + "()\"");
929 pos += insertTagAround(result,
930 xIsStaticZOfY.pos(2),
931 xIsStaticZOfY.cap(2).length(),
932 "@type");
933 pos += xIsStaticZOfY.matchedLength() - 1;
934 }
935
936 /*
937 Add link to 'globalFunction()'.
938 */
939 pos = 0;
940 while ((pos = globalX.indexIn(result, pos)) != -1) {
941 QString x = globalX.cap(1);
942 if (x != "QT_FORWARD_DECLARE_CLASS") {
943 pos += globalX.matchedLength()
944 + insertTagAround(result,
945 globalX.pos(1),
946 x.length(),
947 "@func",
948 "target=\"" + protect(x) + "()\"") - 1;
949 }
950 else
951 pos += globalX.matchedLength();
952 }
953 }
954
955 /*
956 Do syntax highlighting of comments. Also alter the code in a
957 minor way, so that we can include comments in documentation
958 comments.
959 */
960 pos = 0;
961 while (pos != -1) {
962 int mlpos;
963 int slpos;
964 int len;
965 slpos = singleLineComment.indexIn(result, pos);
966 mlpos = multiLineComment.indexIn(result, pos);
967
968 if (slpos == -1 && mlpos == -1)
969 break;
970
971 if (slpos == -1) {
972 pos = mlpos;
973 len = multiLineComment.matchedLength();
974 }
975 else if (mlpos == -1) {
976 pos = slpos;
977 len = singleLineComment.matchedLength();
978 }
979 else {
980 if (slpos < mlpos) {
981 pos = slpos;
982 len = singleLineComment.matchedLength();
983 }
984 else {
985 pos = mlpos;
986 len = multiLineComment.matchedLength();
987 }
988 }
989
990 if (result.at(pos + 1) == QLatin1Char(' ')) {
991 result.remove(pos + len - 2, 1);
992 result.remove(pos + 1, 1);
993 len -= 2;
994
995 forever {
996 int endcodePos = result.indexOf("\\ endcode", pos);
997 if (endcodePos == -1 || endcodePos >= pos + len)
998 break;
999 result.remove(endcodePos + 1, 1);
1000 len -= 1;
1001 }
1002 }
1003 pos += len + insertTagAround(result, pos, len, "@comment");
1004 }
1005
1006 return result;
1007}
1008
1009QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.