|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |
|
53 QT_BEGIN_NAMESPACE |
|
54 |
|
55 static 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 */ |
|
81 CppCodeMarker::CppCodeMarker() |
|
82 { |
|
83 // nothing. |
|
84 } |
|
85 |
|
86 /*! |
|
87 The destructor does nothing. |
|
88 */ |
|
89 CppCodeMarker::~CppCodeMarker() |
|
90 { |
|
91 // nothing. |
|
92 } |
|
93 |
|
94 /*! |
|
95 Returns true. |
|
96 */ |
|
97 bool 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 */ |
|
106 bool 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 */ |
|
124 bool 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 */ |
|
133 QString CppCodeMarker::plainName(const Node *node) |
|
134 { |
|
135 QString name = node->name(); |
|
136 if (node->type() == Node::Function) |
|
137 name += "()"; |
|
138 return name; |
|
139 } |
|
140 |
|
141 QString 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 |
|
159 QString CppCodeMarker::markedUpCode(const QString &code, |
|
160 const Node *relative, |
|
161 const QString &dirPath) |
|
162 { |
|
163 return addMarkUp(protect(code), relative, dirPath); |
|
164 } |
|
165 |
|
166 QString 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 func = (const FunctionNode *) node; |
|
198 if (style != SeparateList && !func->returnType().isEmpty()) |
|
199 synopsis = typified(func->returnType()) + " "; |
|
200 synopsis += name; |
|
201 if (func->metaness() != FunctionNode::MacroWithoutParams) { |
|
202 synopsis += " ("; |
|
203 if (!func->parameters().isEmpty()) { |
|
204 synopsis += " "; |
|
205 QList<Parameter>::ConstIterator p = func->parameters().begin(); |
|
206 while (p != func->parameters().end()) { |
|
207 if (p != func->parameters().begin()) |
|
208 synopsis += ", "; |
|
209 synopsis += typified((*p).leftType()); |
|
210 if (style != SeparateList && !(*p).name().isEmpty()) |
|
211 synopsis += |
|
212 " <@param>" + protect((*p).name()) + "</@param>"; |
|
213 synopsis += protect((*p).rightType()); |
|
214 if (style != SeparateList && !(*p).defaultValue().isEmpty()) |
|
215 synopsis += " = " + protect((*p).defaultValue()); |
|
216 ++p; |
|
217 } |
|
218 synopsis += " "; |
|
219 } |
|
220 synopsis += ")"; |
|
221 } |
|
222 if (func->isConst()) |
|
223 synopsis += " const"; |
|
224 |
|
225 if (style == Summary || style == Accessors) { |
|
226 if (func->virtualness() != FunctionNode::NonVirtual) |
|
227 synopsis.prepend("virtual "); |
|
228 if (func->virtualness() == FunctionNode::PureVirtual) |
|
229 synopsis.append(" = 0"); |
|
230 } |
|
231 else if (style == SeparateList) { |
|
232 if (!func->returnType().isEmpty() && func->returnType() != "void") |
|
233 synopsis += " : " + typified(func->returnType()); |
|
234 } |
|
235 else { |
|
236 QStringList bracketed; |
|
237 if (func->isStatic()) { |
|
238 bracketed += "static"; |
|
239 } |
|
240 else if (func->virtualness() != FunctionNode::NonVirtual) { |
|
241 if (func->virtualness() == FunctionNode::PureVirtual) |
|
242 bracketed += "pure"; |
|
243 bracketed += "virtual"; |
|
244 } |
|
245 |
|
246 if (func->access() == Node::Protected) { |
|
247 bracketed += "protected"; |
|
248 } |
|
249 else if (func->access() == Node::Private) { |
|
250 bracketed += "private"; |
|
251 } |
|
252 |
|
253 if (func->metaness() == FunctionNode::Signal) { |
|
254 bracketed += "signal"; |
|
255 } |
|
256 else if (func->metaness() == FunctionNode::Slot) { |
|
257 bracketed += "slot"; |
|
258 } |
|
259 if (!bracketed.isEmpty()) |
|
260 extra += " [" + bracketed.join(" ") + "]"; |
|
261 } |
|
262 break; |
|
263 case Node::Enum: |
|
264 enume = static_cast<const EnumNode *>(node); |
|
265 synopsis = "enum " + name; |
|
266 if (style == Summary) { |
|
267 synopsis += " { "; |
|
268 |
|
269 QStringList documentedItems = enume->doc().enumItemNames(); |
|
270 if (documentedItems.isEmpty()) { |
|
271 foreach (const EnumItem &item, enume->items()) |
|
272 documentedItems << item.name(); |
|
273 } |
|
274 QStringList omitItems = enume->doc().omitEnumItemNames(); |
|
275 foreach (const QString &item, omitItems) |
|
276 documentedItems.removeAll(item); |
|
277 |
|
278 if (documentedItems.size() <= MaxEnumValues) { |
|
279 for (int i = 0; i < documentedItems.size(); ++i) { |
|
280 if (i != 0) |
|
281 synopsis += ", "; |
|
282 synopsis += documentedItems.at(i); |
|
283 } |
|
284 } |
|
285 else { |
|
286 for (int i = 0; i < documentedItems.size(); ++i) { |
|
287 if (i < MaxEnumValues-2 || i == documentedItems.size()-1) { |
|
288 if (i != 0) |
|
289 synopsis += ", "; |
|
290 synopsis += documentedItems.at(i); |
|
291 } |
|
292 else if (i == MaxEnumValues - 1) { |
|
293 synopsis += ", ..."; |
|
294 } |
|
295 } |
|
296 } |
|
297 if (!documentedItems.isEmpty()) |
|
298 synopsis += " "; |
|
299 synopsis += "}"; |
|
300 } |
|
301 break; |
|
302 case Node::Typedef: |
|
303 typedeff = static_cast<const TypedefNode *>(node); |
|
304 if (typedeff->associatedEnum()) { |
|
305 synopsis = "flags " + name; |
|
306 } |
|
307 else { |
|
308 synopsis = "typedef " + name; |
|
309 } |
|
310 break; |
|
311 case Node::Property: |
|
312 property = static_cast<const PropertyNode *>(node); |
|
313 synopsis = name + " : " + typified(property->qualifiedDataType()); |
|
314 break; |
|
315 case Node::Variable: |
|
316 variable = static_cast<const VariableNode *>(node); |
|
317 if (style == SeparateList) { |
|
318 synopsis = name + " : " + typified(variable->dataType()); |
|
319 } |
|
320 else { |
|
321 synopsis = typified(variable->leftType()) + " " + |
|
322 name + protect(variable->rightType()); |
|
323 } |
|
324 break; |
|
325 default: |
|
326 synopsis = name; |
|
327 } |
|
328 |
|
329 if (style == Summary) { |
|
330 if (node->status() == Node::Preliminary) { |
|
331 extra += " (preliminary)"; |
|
332 } |
|
333 else if (node->status() == Node::Deprecated) { |
|
334 extra += " (deprecated)"; |
|
335 } |
|
336 else if (node->status() == Node::Obsolete) { |
|
337 extra += " (obsolete)"; |
|
338 } |
|
339 } |
|
340 |
|
341 if (!extra.isEmpty()) { |
|
342 extra.prepend("<@extra>"); |
|
343 extra.append("</@extra>"); |
|
344 } |
|
345 return synopsis + extra; |
|
346 } |
|
347 |
|
348 #ifdef QDOC_QML |
|
349 /*! |
|
350 */ |
|
351 QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) |
|
352 { |
|
353 QString name = taggedQmlNode(node); |
|
354 if (summary) { |
|
355 name = linkTag(node,name); |
|
356 } |
|
357 name = "<@name>" + name + "</@name>"; |
|
358 QString synopsis = name; |
|
359 if (node->type() == Node::QmlProperty) { |
|
360 const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node); |
|
361 synopsis += " : " + typified(pn->dataType()); |
|
362 } |
|
363 |
|
364 QString extra; |
|
365 if (summary) { |
|
366 if (node->status() == Node::Preliminary) { |
|
367 extra += " (preliminary)"; |
|
368 } |
|
369 else if (node->status() == Node::Deprecated) { |
|
370 extra += " (deprecated)"; |
|
371 } |
|
372 else if (node->status() == Node::Obsolete) { |
|
373 extra += " (obsolete)"; |
|
374 } |
|
375 } |
|
376 |
|
377 if (!extra.isEmpty()) { |
|
378 extra.prepend("<@extra>"); |
|
379 extra.append("</@extra>"); |
|
380 } |
|
381 return synopsis + extra; |
|
382 } |
|
383 #endif |
|
384 |
|
385 QString CppCodeMarker::markedUpName(const Node *node) |
|
386 { |
|
387 QString name = linkTag(node, taggedNode(node)); |
|
388 if (node->type() == Node::Function) |
|
389 name += "()"; |
|
390 return name; |
|
391 } |
|
392 |
|
393 QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative) |
|
394 { |
|
395 if (node->name().isEmpty()) { |
|
396 return "global"; |
|
397 } |
|
398 else { |
|
399 QString fullName; |
|
400 for (;;) { |
|
401 fullName.prepend(markedUpName(node)); |
|
402 if (node->parent() == relative || node->parent()->name().isEmpty()) |
|
403 break; |
|
404 fullName.prepend("<@op>::</@op>"); |
|
405 node = node->parent(); |
|
406 } |
|
407 return fullName; |
|
408 } |
|
409 } |
|
410 |
|
411 QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, |
|
412 const Node *relative) |
|
413 { |
|
414 const Node *node = relative->parent(); |
|
415 QString fullName; |
|
416 while (node->parent()) { |
|
417 fullName.prepend(markedUpName(node)); |
|
418 if (node->parent() == relative || node->parent()->name().isEmpty()) |
|
419 break; |
|
420 fullName.prepend("<@op>::</@op>"); |
|
421 node = node->parent(); |
|
422 } |
|
423 if (!fullName.isEmpty()) |
|
424 fullName.append("<@op>::</@op>"); |
|
425 fullName.append(enumValue); |
|
426 return fullName; |
|
427 } |
|
428 |
|
429 QString CppCodeMarker::markedUpIncludes(const QStringList& includes) |
|
430 { |
|
431 QString code; |
|
432 |
|
433 QStringList::ConstIterator inc = includes.begin(); |
|
434 while (inc != includes.end()) { |
|
435 code += "#include <<@headerfile>" + *inc + "</@headerfile>>\n"; |
|
436 ++inc; |
|
437 } |
|
438 return addMarkUp(code, 0, ""); |
|
439 } |
|
440 |
|
441 QString CppCodeMarker::functionBeginRegExp(const QString& funcName) |
|
442 { |
|
443 return "^" + QRegExp::escape(funcName) + "$"; |
|
444 |
|
445 } |
|
446 |
|
447 QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) |
|
448 { |
|
449 return "^\\}$"; |
|
450 } |
|
451 |
|
452 #if 0 |
|
453 FastSection privateReimpFuncs(classe, |
|
454 "Private Reimplemented Functions", |
|
455 "private reimplemented function", |
|
456 "private reimplemented functions"); |
|
457 FastSection protectedReimpFuncs(classe, |
|
458 "Protected Reimplemented Functions", |
|
459 "protected reimplemented function", |
|
460 "protected reimplemented functions"); |
|
461 FastSection publicReimpFuncs(classe, |
|
462 "Public Reimplemented Functions", |
|
463 "public reimplemented function", |
|
464 "public reimplemented functions"); |
|
465 #endif |
|
466 |
|
467 QList<Section> CppCodeMarker::sections(const InnerNode *inner, |
|
468 SynopsisStyle style, |
|
469 Status status) |
|
470 { |
|
471 QList<Section> sections; |
|
472 |
|
473 if (inner->type() == Node::Class) { |
|
474 const ClassNode *classe = static_cast<const ClassNode *>(inner); |
|
475 |
|
476 if (style == Summary) { |
|
477 FastSection privateFunctions(classe, |
|
478 "Private Functions", |
|
479 "private function", |
|
480 "private functions"); |
|
481 FastSection privateSlots(classe, "Private Slots", "private slot", "private slots"); |
|
482 FastSection privateTypes(classe, "Private Types", "private type", "private types"); |
|
483 FastSection protectedFunctions(classe, |
|
484 "Protected Functions", |
|
485 "protected function", |
|
486 "protected functions"); |
|
487 FastSection protectedSlots(classe, |
|
488 "Protected Slots", |
|
489 "protected slot", |
|
490 "protected slots"); |
|
491 FastSection protectedTypes(classe, |
|
492 "Protected Types", |
|
493 "protected type", |
|
494 "protected types"); |
|
495 FastSection protectedVariables(classe, |
|
496 "Protected Variables", |
|
497 "protected type", |
|
498 "protected variables"); |
|
499 FastSection publicFunctions(classe, |
|
500 "Public Functions", |
|
501 "public function", |
|
502 "public functions"); |
|
503 FastSection publicSignals(classe, "Signals", "signal", "signals"); |
|
504 FastSection publicSlots(classe, "Public Slots", "public slot", "public slots"); |
|
505 FastSection publicTypes(classe, "Public Types", "public type", "public types"); |
|
506 FastSection publicVariables(classe, |
|
507 "Public Variables", |
|
508 "public type", |
|
509 "public variables"); |
|
510 FastSection properties(classe, "Properties", "property", "properties"); |
|
511 FastSection relatedNonMembers(classe, |
|
512 "Related Non-Members", |
|
513 "related non-member", |
|
514 "related non-members"); |
|
515 FastSection staticPrivateMembers(classe, |
|
516 "Static Private Members", |
|
517 "static private member", |
|
518 "static private members"); |
|
519 FastSection staticProtectedMembers(classe, |
|
520 "Static Protected Members", |
|
521 "static protected member", |
|
522 "static protected members"); |
|
523 FastSection staticPublicMembers(classe, |
|
524 "Static Public Members", |
|
525 "static public member", |
|
526 "static public members"); |
|
527 FastSection macros(inner, "Macros", "macro", "macros"); |
|
528 |
|
529 NodeList::ConstIterator r = classe->relatedNodes().begin(); |
|
530 while (r != classe->relatedNodes().end()) { |
|
531 if ((*r)->type() == Node::Function) { |
|
532 FunctionNode *func = static_cast<FunctionNode *>(*r); |
|
533 if (func->isMacro()) |
|
534 insert(macros, *r, style, status); |
|
535 else |
|
536 insert(relatedNonMembers, *r, style, status); |
|
537 } |
|
538 else { |
|
539 insert(relatedNonMembers, *r, style, status); |
|
540 } |
|
541 ++r; |
|
542 } |
|
543 |
|
544 QStack<const ClassNode *> stack; |
|
545 stack.push(classe); |
|
546 |
|
547 while (!stack.isEmpty()) { |
|
548 const ClassNode *ancestorClass = stack.pop(); |
|
549 |
|
550 NodeList::ConstIterator c = ancestorClass->childNodes().begin(); |
|
551 while (c != ancestorClass->childNodes().end()) { |
|
552 bool isSlot = false; |
|
553 bool isSignal = false; |
|
554 bool isStatic = false; |
|
555 if ((*c)->type() == Node::Function) { |
|
556 const FunctionNode *func = (const FunctionNode *) *c; |
|
557 isSlot = (func->metaness() == FunctionNode::Slot); |
|
558 isSignal = (func->metaness() == FunctionNode::Signal); |
|
559 isStatic = func->isStatic(); |
|
560 } |
|
561 else if ((*c)->type() == Node::Variable) { |
|
562 const VariableNode *var = static_cast<const VariableNode *>(*c); |
|
563 isStatic = var->isStatic(); |
|
564 } |
|
565 |
|
566 switch ((*c)->access()) { |
|
567 case Node::Public: |
|
568 if (isSlot) { |
|
569 insert(publicSlots, *c, style, status); |
|
570 } |
|
571 else if (isSignal) { |
|
572 insert(publicSignals, *c, style, status); |
|
573 } |
|
574 else if (isStatic) { |
|
575 if ((*c)->type() != Node::Variable |
|
576 || !(*c)->doc().isEmpty()) |
|
577 insert(staticPublicMembers,*c,style,status); |
|
578 } |
|
579 else if ((*c)->type() == Node::Property) { |
|
580 insert(properties, *c, style, status); |
|
581 } |
|
582 else if ((*c)->type() == Node::Variable) { |
|
583 if (!(*c)->doc().isEmpty()) |
|
584 insert(publicVariables, *c, style, status); |
|
585 } |
|
586 else if ((*c)->type() == Node::Function) { |
|
587 if (!insertReimpFunc(publicFunctions,*c,status)) |
|
588 insert(publicFunctions, *c, style, status); |
|
589 } |
|
590 else { |
|
591 insert(publicTypes, *c, style, status); |
|
592 } |
|
593 break; |
|
594 case Node::Protected: |
|
595 if (isSlot) { |
|
596 insert(protectedSlots, *c, style, status); |
|
597 } |
|
598 else if (isStatic) { |
|
599 if ((*c)->type() != Node::Variable |
|
600 || !(*c)->doc().isEmpty()) |
|
601 insert(staticProtectedMembers,*c,style,status); |
|
602 } |
|
603 else if ((*c)->type() == Node::Variable) { |
|
604 if (!(*c)->doc().isEmpty()) |
|
605 insert(protectedVariables,*c,style,status); |
|
606 } |
|
607 else if ((*c)->type() == Node::Function) { |
|
608 if (!insertReimpFunc(protectedFunctions,*c,status)) |
|
609 insert(protectedFunctions, *c, style, status); |
|
610 } |
|
611 else { |
|
612 insert(protectedTypes, *c, style, status); |
|
613 } |
|
614 break; |
|
615 case Node::Private: |
|
616 if (isSlot) { |
|
617 insert(privateSlots, *c, style, status); |
|
618 } |
|
619 else if (isStatic) { |
|
620 if ((*c)->type() != Node::Variable |
|
621 || !(*c)->doc().isEmpty()) |
|
622 insert(staticPrivateMembers,*c,style,status); |
|
623 } |
|
624 else if ((*c)->type() == Node::Function) { |
|
625 if (!insertReimpFunc(privateFunctions,*c,status)) |
|
626 insert(privateFunctions, *c, style, status); |
|
627 } |
|
628 else { |
|
629 insert(privateTypes,*c,style,status); |
|
630 } |
|
631 } |
|
632 ++c; |
|
633 } |
|
634 |
|
635 QList<RelatedClass>::ConstIterator r = |
|
636 ancestorClass->baseClasses().begin(); |
|
637 while (r != ancestorClass->baseClasses().end()) { |
|
638 stack.prepend((*r).node); |
|
639 ++r; |
|
640 } |
|
641 } |
|
642 |
|
643 append(sections, publicTypes); |
|
644 append(sections, properties); |
|
645 append(sections, publicFunctions); |
|
646 append(sections, publicSlots); |
|
647 append(sections, publicSignals); |
|
648 append(sections, publicVariables); |
|
649 append(sections, staticPublicMembers); |
|
650 append(sections, protectedTypes); |
|
651 append(sections, protectedFunctions); |
|
652 append(sections, protectedSlots); |
|
653 append(sections, protectedVariables); |
|
654 append(sections, staticProtectedMembers); |
|
655 append(sections, privateTypes); |
|
656 append(sections, privateFunctions); |
|
657 append(sections, privateSlots); |
|
658 append(sections, staticPrivateMembers); |
|
659 append(sections, relatedNonMembers); |
|
660 append(sections, macros); |
|
661 } |
|
662 else if (style == Detailed) { |
|
663 FastSection memberFunctions(classe,"Member Function Documentation"); |
|
664 FastSection memberTypes(classe,"Member Type Documentation"); |
|
665 FastSection memberVariables(classe,"Member Variable Documentation"); |
|
666 FastSection properties(classe,"Property Documentation"); |
|
667 FastSection relatedNonMembers(classe,"Related Non-Members"); |
|
668 FastSection macros(classe,"Macro Documentation"); |
|
669 |
|
670 NodeList::ConstIterator r = classe->relatedNodes().begin(); |
|
671 while (r != classe->relatedNodes().end()) { |
|
672 if ((*r)->type() == Node::Function) { |
|
673 FunctionNode *func = static_cast<FunctionNode *>(*r); |
|
674 if (func->isMacro()) |
|
675 insert(macros, *r, style, status); |
|
676 else |
|
677 insert(relatedNonMembers, *r, style, status); |
|
678 } |
|
679 else { |
|
680 insert(relatedNonMembers, *r, style, status); |
|
681 } |
|
682 ++r; |
|
683 } |
|
684 |
|
685 NodeList::ConstIterator c = classe->childNodes().begin(); |
|
686 while (c != classe->childNodes().end()) { |
|
687 if ((*c)->type() == Node::Enum || |
|
688 (*c)->type() == Node::Typedef) { |
|
689 insert(memberTypes, *c, style, status); |
|
690 } |
|
691 else if ((*c)->type() == Node::Property) { |
|
692 insert(properties, *c, style, status); |
|
693 } |
|
694 else if ((*c)->type() == Node::Variable) { |
|
695 if (!(*c)->doc().isEmpty()) |
|
696 insert(memberVariables, *c, style, status); |
|
697 } |
|
698 else if ((*c)->type() == Node::Function) { |
|
699 FunctionNode *function = static_cast<FunctionNode *>(*c); |
|
700 if (!function->associatedProperty()) |
|
701 insert(memberFunctions, function, style, status); |
|
702 } |
|
703 ++c; |
|
704 } |
|
705 |
|
706 append(sections, memberTypes); |
|
707 append(sections, properties); |
|
708 append(sections, memberFunctions); |
|
709 append(sections, memberVariables); |
|
710 append(sections, relatedNonMembers); |
|
711 append(sections, macros); |
|
712 } |
|
713 else { |
|
714 FastSection all(classe); |
|
715 |
|
716 QStack<const ClassNode *> stack; |
|
717 stack.push(classe); |
|
718 |
|
719 while (!stack.isEmpty()) { |
|
720 const ClassNode *ancestorClass = stack.pop(); |
|
721 |
|
722 NodeList::ConstIterator c = ancestorClass->childNodes().begin(); |
|
723 while (c != ancestorClass->childNodes().end()) { |
|
724 if ((*c)->access() != Node::Private && |
|
725 (*c)->type() != Node::Property) |
|
726 insert(all, *c, style, status); |
|
727 ++c; |
|
728 } |
|
729 |
|
730 QList<RelatedClass>::ConstIterator r = |
|
731 ancestorClass->baseClasses().begin(); |
|
732 while (r != ancestorClass->baseClasses().end()) { |
|
733 stack.prepend((*r).node); |
|
734 ++r; |
|
735 } |
|
736 } |
|
737 append(sections, all); |
|
738 } |
|
739 } |
|
740 else { |
|
741 if (style == Summary || style == Detailed) { |
|
742 FastSection namespaces(inner, |
|
743 "Namespaces", |
|
744 "namespace", |
|
745 "namespaces"); |
|
746 FastSection classes(inner, |
|
747 "Classes", |
|
748 "class", |
|
749 "classes"); |
|
750 FastSection types(inner, |
|
751 style == Summary ? |
|
752 "Types" : "Type Documentation", |
|
753 "type", |
|
754 "types"); |
|
755 FastSection functions(inner, |
|
756 style == Summary ? |
|
757 "Functions" : "Function Documentation", |
|
758 "function", |
|
759 "functions"); |
|
760 FastSection macros(inner, |
|
761 style == Summary ? |
|
762 "Macros" : "Macro Documentation", |
|
763 "macro", |
|
764 "macros"); |
|
765 |
|
766 NodeList nodeList = inner->childNodes(); |
|
767 nodeList += inner->relatedNodes(); |
|
768 |
|
769 NodeList::ConstIterator n = nodeList.begin(); |
|
770 while (n != nodeList.end()) { |
|
771 switch ((*n)->type()) { |
|
772 case Node::Namespace: |
|
773 insert(namespaces, *n, style, status); |
|
774 break; |
|
775 case Node::Class: |
|
776 insert(classes, *n, style, status); |
|
777 break; |
|
778 case Node::Enum: |
|
779 case Node::Typedef: |
|
780 insert(types, *n, style, status); |
|
781 break; |
|
782 case Node::Function: |
|
783 { |
|
784 FunctionNode *func = static_cast<FunctionNode *>(*n); |
|
785 if (func->isMacro()) |
|
786 insert(macros, *n, style, status); |
|
787 else |
|
788 insert(functions, *n, style, status); |
|
789 } |
|
790 break; |
|
791 default: |
|
792 ; |
|
793 } |
|
794 ++n; |
|
795 } |
|
796 append(sections, namespaces); |
|
797 append(sections, classes); |
|
798 append(sections, types); |
|
799 append(sections, functions); |
|
800 append(sections, macros); |
|
801 } |
|
802 } |
|
803 |
|
804 return sections; |
|
805 } |
|
806 |
|
807 const Node *CppCodeMarker::resolveTarget(const QString &target, |
|
808 const Tree *tree, |
|
809 const Node *relative) |
|
810 { |
|
811 if (target.endsWith("()")) { |
|
812 const FunctionNode *func; |
|
813 QString funcName = target; |
|
814 funcName.chop(2); |
|
815 |
|
816 QStringList path = funcName.split("::"); |
|
817 if ((func = tree->findFunctionNode(path, |
|
818 relative, |
|
819 Tree::SearchBaseClasses)) |
|
820 && func->metaness() != FunctionNode::MacroWithoutParams) |
|
821 return func; |
|
822 } |
|
823 else if (target.contains("#")) { |
|
824 // ### this doesn't belong here; get rid of TargetNode hack |
|
825 int hashAt = target.indexOf("#"); |
|
826 QString link = target.left(hashAt); |
|
827 QString ref = target.mid(hashAt + 1); |
|
828 const Node *node; |
|
829 if (link.isEmpty()) { |
|
830 node = relative; |
|
831 } |
|
832 else { |
|
833 QStringList path(link); |
|
834 node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses); |
|
835 } |
|
836 if (node && node->isInnerNode()) { |
|
837 const Atom *atom = node->doc().body().firstAtom(); |
|
838 while (atom) { |
|
839 if (atom->type() == Atom::Target && atom->string() == ref) { |
|
840 Node *parentNode = const_cast<Node *>(node); |
|
841 return new TargetNode(static_cast<InnerNode*>(parentNode), |
|
842 ref); |
|
843 } |
|
844 atom = atom->next(); |
|
845 } |
|
846 } |
|
847 } |
|
848 else { |
|
849 QStringList path = target.split("::"); |
|
850 const Node *node; |
|
851 if ((node = tree->findNode(path, |
|
852 relative, |
|
853 Tree::SearchBaseClasses | |
|
854 Tree::SearchEnumValues | |
|
855 Tree::NonFunction))) |
|
856 return node; |
|
857 } |
|
858 return 0; |
|
859 } |
|
860 |
|
861 QString CppCodeMarker::addMarkUp(const QString& protectedCode, |
|
862 const Node * /* relative */, |
|
863 const QString& /* dirPath */) |
|
864 { |
|
865 static QRegExp globalInclude("#include +<([^<>&]+)>"); |
|
866 static QRegExp yHasTypeX("(?:^|\n *)([a-zA-Z_][a-zA-Z_0-9]*)" |
|
867 "(?:<[^;{}]+>)?(?: *(?:\\*|&) *| +)" |
|
868 "([a-zA-Z_][a-zA-Z_0-9]*)? *[,;()=]"); |
|
869 static QRegExp xNewY("([a-zA-Z_][a-zA-Z_0-9]*) *= *new +([a-zA-Z_0-9]+)"); |
|
870 static QRegExp xDotY("\\b([a-zA-Z_][a-zA-Z_0-9]*) *(?:\\.|->|,[ \n]*S(?:IGNAL|LOT)\\() *" |
|
871 "([a-zA-Z_][a-zA-Z_0-9]*)(?= *\\()"); |
|
872 static QRegExp xIsStaticZOfY("[\n:;{(=] *(([a-zA-Z_0-9]+)::([a-zA-Z_0-9]+))(?= *\\()"); |
|
873 static QRegExp classX("[:,][ \n]*(?:p(?:ublic|r(?:otected|ivate))[ \n]+)?" |
|
874 "([a-zA-Z_][a-zA-Z_0-9]*)"); |
|
875 static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\("); |
|
876 static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)"); |
|
877 multiLineComment.setMinimal(true); |
|
878 static QRegExp singleLineComment("//(?!!)[^!\n]*"); |
|
879 static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define" |
|
880 "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)"); |
|
881 static QRegExp literals(""(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*"" |
|
882 "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'"); |
|
883 |
|
884 QString result = protectedCode; |
|
885 int pos; |
|
886 |
|
887 if (!hurryUp()) { |
|
888 /* |
|
889 Mark global includes. For example: |
|
890 |
|
891 #include <<@headerfile>QString</@headerfile> |
|
892 */ |
|
893 pos = 0; |
|
894 while ((pos = result.indexOf(globalInclude, pos)) != -1) |
|
895 pos += globalInclude.matchedLength() |
|
896 + insertTagAround(result, |
|
897 globalInclude.pos(1), |
|
898 globalInclude.cap(1).length(), |
|
899 "@headerfile"); |
|
900 |
|
901 /* |
|
902 Look for variable definitions and similar constructs, mark |
|
903 the data type, and remember the type of the variable. |
|
904 */ |
|
905 QMap<QString, QSet<QString> > typesForVariable; |
|
906 pos = 0; |
|
907 while ((pos = yHasTypeX.indexIn(result, pos)) != -1) { |
|
908 QString x = yHasTypeX.cap(1); |
|
909 QString y = yHasTypeX.cap(2); |
|
910 |
|
911 if (!y.isEmpty()) |
|
912 typesForVariable[y].insert(x); |
|
913 |
|
914 /* |
|
915 Without the minus one at the end, 'void member(Class |
|
916 var)' would give 'member' as a variable of type 'void', |
|
917 but would ignore 'Class var'. (### Is that true?) |
|
918 */ |
|
919 pos += yHasTypeX.matchedLength() |
|
920 + insertTagAround(result, |
|
921 yHasTypeX.pos(1), |
|
922 x.length(), |
|
923 "@type") - 1; |
|
924 } |
|
925 |
|
926 /* |
|
927 Do syntax highlighting of preprocessor directives. |
|
928 */ |
|
929 pos = 0; |
|
930 while ((pos = preprocessor.indexIn(result, pos)) != -1) |
|
931 pos += preprocessor.matchedLength() |
|
932 + insertTagAround(result, |
|
933 preprocessor.pos(1), |
|
934 preprocessor.cap(1).length(), |
|
935 "@preprocessor"); |
|
936 |
|
937 /* |
|
938 Deal with string and character literals. |
|
939 */ |
|
940 pos = 0; |
|
941 while ((pos = literals.indexIn(result, pos)) != -1) |
|
942 pos += literals.matchedLength() |
|
943 + insertTagAround(result, |
|
944 pos, |
|
945 literals.matchedLength(), |
|
946 result.at(pos) == |
|
947 QLatin1Char(' ') ? "@string" : "@char"); |
|
948 |
|
949 /* |
|
950 Look for 'var = new Class'. |
|
951 */ |
|
952 pos = 0; |
|
953 while ((pos = xNewY.indexIn(result, pos)) != -1) { |
|
954 QString x = xNewY.cap(1); |
|
955 QString y = xNewY.cap(2); |
|
956 typesForVariable[x].insert(y); |
|
957 |
|
958 pos += xNewY.matchedLength() + insertTagAround(result, |
|
959 xNewY.pos(2), |
|
960 y.length(), |
|
961 "@type"); |
|
962 } |
|
963 |
|
964 /* |
|
965 Insert some stuff that cannot harm. |
|
966 */ |
|
967 typesForVariable["qApp"].insert("QApplication"); |
|
968 |
|
969 /* |
|
970 Add link to ': Class'. |
|
971 */ |
|
972 pos = 0; |
|
973 while ((pos = classX.indexIn(result, pos)) != -1) |
|
974 pos += classX.matchedLength() |
|
975 + insertTagAround(result, |
|
976 classX.pos(1), |
|
977 classX.cap(1).length(), |
|
978 "@type") - 1; |
|
979 |
|
980 /* |
|
981 Find use of any of |
|
982 |
|
983 var.method() |
|
984 var->method() |
|
985 var, SIGNAL(method()) |
|
986 var, SLOT(method()). |
|
987 */ |
|
988 pos = 0; |
|
989 while ((pos = xDotY.indexIn(result, pos)) != -1) { |
|
990 QString x = xDotY.cap(1); |
|
991 QString y = xDotY.cap(2); |
|
992 |
|
993 QSet<QString> types = typesForVariable.value(x); |
|
994 pos += xDotY.matchedLength() |
|
995 + insertTagAround(result, |
|
996 xDotY.pos(2), |
|
997 xDotY.cap(2).length(), |
|
998 "@func", |
|
999 (types.count() == 1) ? "target=\"" |
|
1000 + protect(*types.begin() + "::" + y) |
|
1001 + "()\"" : QString()); |
|
1002 } |
|
1003 |
|
1004 /* |
|
1005 Add link to 'Class::method()'. |
|
1006 */ |
|
1007 pos = 0; |
|
1008 while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) { |
|
1009 QString x = xIsStaticZOfY.cap(1); |
|
1010 QString z = xIsStaticZOfY.cap(3); |
|
1011 |
|
1012 pos += insertTagAround(result, |
|
1013 xIsStaticZOfY.pos(3), |
|
1014 z.length(), |
|
1015 "@func", |
|
1016 "target=\"" + protect(x) + "()\""); |
|
1017 pos += insertTagAround(result, |
|
1018 xIsStaticZOfY.pos(2), |
|
1019 xIsStaticZOfY.cap(2).length(), |
|
1020 "@type"); |
|
1021 pos += xIsStaticZOfY.matchedLength() - 1; |
|
1022 } |
|
1023 |
|
1024 /* |
|
1025 Add link to 'globalFunction()'. |
|
1026 */ |
|
1027 pos = 0; |
|
1028 while ((pos = globalX.indexIn(result, pos)) != -1) { |
|
1029 QString x = globalX.cap(1); |
|
1030 if (x != "QT_FORWARD_DECLARE_CLASS") { |
|
1031 pos += globalX.matchedLength() |
|
1032 + insertTagAround(result, |
|
1033 globalX.pos(1), |
|
1034 x.length(), |
|
1035 "@func", |
|
1036 "target=\"" + protect(x) + "()\"") - 1; |
|
1037 } |
|
1038 else |
|
1039 pos += globalX.matchedLength(); |
|
1040 } |
|
1041 } |
|
1042 |
|
1043 /* |
|
1044 Do syntax highlighting of comments. Also alter the code in a |
|
1045 minor way, so that we can include comments in documentation |
|
1046 comments. |
|
1047 */ |
|
1048 pos = 0; |
|
1049 while (pos != -1) { |
|
1050 int mlpos; |
|
1051 int slpos; |
|
1052 int len; |
|
1053 slpos = singleLineComment.indexIn(result, pos); |
|
1054 mlpos = multiLineComment.indexIn(result, pos); |
|
1055 |
|
1056 if (slpos == -1 && mlpos == -1) |
|
1057 break; |
|
1058 |
|
1059 if (slpos == -1) { |
|
1060 pos = mlpos; |
|
1061 len = multiLineComment.matchedLength(); |
|
1062 } |
|
1063 else if (mlpos == -1) { |
|
1064 pos = slpos; |
|
1065 len = singleLineComment.matchedLength(); |
|
1066 } |
|
1067 else { |
|
1068 if (slpos < mlpos) { |
|
1069 pos = slpos; |
|
1070 len = singleLineComment.matchedLength(); |
|
1071 } |
|
1072 else { |
|
1073 pos = mlpos; |
|
1074 len = multiLineComment.matchedLength(); |
|
1075 } |
|
1076 } |
|
1077 |
|
1078 if (result.at(pos + 1) == QLatin1Char(' ')) { |
|
1079 result.remove(pos + len - 2, 1); |
|
1080 result.remove(pos + 1, 1); |
|
1081 len -= 2; |
|
1082 |
|
1083 forever { |
|
1084 int endcodePos = result.indexOf("\\ endcode", pos); |
|
1085 if (endcodePos == -1 || endcodePos >= pos + len) |
|
1086 break; |
|
1087 result.remove(endcodePos + 1, 1); |
|
1088 len -= 1; |
|
1089 } |
|
1090 } |
|
1091 pos += len + insertTagAround(result, pos, len, "@comment"); |
|
1092 } |
|
1093 |
|
1094 return result; |
|
1095 } |
|
1096 |
|
1097 #ifdef QDOC_QML |
|
1098 /*! |
|
1099 This function is for documenting QML properties. It returns |
|
1100 the list of documentation sections for the children of the |
|
1101 \a qmlClassNode. |
|
1102 |
|
1103 Currently, it only handles QML property groups. |
|
1104 */ |
|
1105 QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, |
|
1106 SynopsisStyle style) |
|
1107 { |
|
1108 QList<Section> sections; |
|
1109 if (qmlClassNode) { |
|
1110 if (style == Summary) { |
|
1111 FastSection qmlproperties(qmlClassNode, |
|
1112 "QML Properties", |
|
1113 "property", |
|
1114 "properties"); |
|
1115 FastSection qmlattachedproperties(qmlClassNode, |
|
1116 "QML Attached Properties", |
|
1117 "property", |
|
1118 "properties"); |
|
1119 FastSection qmlsignals(qmlClassNode, |
|
1120 "QML Signals", |
|
1121 "signal", |
|
1122 "signals"); |
|
1123 FastSection qmlmethods(qmlClassNode, |
|
1124 "QML Methods", |
|
1125 "method", |
|
1126 "methods"); |
|
1127 |
|
1128 NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); |
|
1129 while (c != qmlClassNode->childNodes().end()) { |
|
1130 if ((*c)->subType() == Node::QmlPropertyGroup) { |
|
1131 const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); |
|
1132 NodeList::ConstIterator p = qpgn->childNodes().begin(); |
|
1133 while (p != qpgn->childNodes().end()) { |
|
1134 if ((*p)->type() == Node::QmlProperty) { |
|
1135 const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p); |
|
1136 if (pn->isAttached()) |
|
1137 insert(qmlattachedproperties,*p,style,Okay); |
|
1138 else |
|
1139 insert(qmlproperties,*p,style,Okay); |
|
1140 } |
|
1141 ++p; |
|
1142 } |
|
1143 } |
|
1144 else if ((*c)->type() == Node::QmlSignal) { |
|
1145 insert(qmlsignals,*c,style,Okay); |
|
1146 } |
|
1147 else if ((*c)->type() == Node::QmlMethod) { |
|
1148 insert(qmlmethods,*c,style,Okay); |
|
1149 } |
|
1150 ++c; |
|
1151 } |
|
1152 append(sections,qmlproperties); |
|
1153 append(sections,qmlattachedproperties); |
|
1154 append(sections,qmlsignals); |
|
1155 append(sections,qmlmethods); |
|
1156 } |
|
1157 else if (style == Detailed) { |
|
1158 FastSection qmlproperties(qmlClassNode,"QML Property Documentation"); |
|
1159 FastSection qmlattachedproperties(qmlClassNode,"QML Attached Property Documentation"); |
|
1160 FastSection qmlsignals(qmlClassNode,"QML Signal Documentation"); |
|
1161 FastSection qmlmethods(qmlClassNode,"QML Method Documentation"); |
|
1162 NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); |
|
1163 while (c != qmlClassNode->childNodes().end()) { |
|
1164 if ((*c)->subType() == Node::QmlPropertyGroup) { |
|
1165 const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c); |
|
1166 if (pgn->isAttached()) |
|
1167 insert(qmlattachedproperties,*c,style,Okay); |
|
1168 else |
|
1169 insert(qmlproperties,*c,style,Okay); |
|
1170 } |
|
1171 else if ((*c)->type() == Node::QmlSignal) { |
|
1172 insert(qmlsignals,*c,style,Okay); |
|
1173 } |
|
1174 else if ((*c)->type() == Node::QmlMethod) { |
|
1175 insert(qmlmethods,*c,style,Okay); |
|
1176 } |
|
1177 ++c; |
|
1178 } |
|
1179 append(sections,qmlproperties); |
|
1180 append(sections,qmlattachedproperties); |
|
1181 append(sections,qmlsignals); |
|
1182 append(sections,qmlmethods); |
|
1183 } |
|
1184 } |
|
1185 |
|
1186 return sections; |
|
1187 } |
|
1188 #endif |
|
1189 |
|
1190 QT_END_NAMESPACE |