Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / qdoc3 / codemarker.cpp
blobee93080d41e25116dbc177069fdbfdbc7f0e20a6
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 ****************************************************************************/
42 #include <QMetaObject>
43 #include <QDebug>
44 #include "codemarker.h"
45 #include "config.h"
46 #include "node.h"
48 #include <stdio.h>
50 QT_BEGIN_NAMESPACE
52 QString CodeMarker::defaultLang;
53 QList<CodeMarker *> CodeMarker::markers;
55 /*!
56 When a code marker constructs itself, it puts itself into
57 the static list of code markers. All the code markers in
58 the static list get initialized in initialize(), which is
59 not called until after the qdoc configuration file has
60 been read.
62 CodeMarker::CodeMarker()
63 : slow(false)
65 markers.prepend(this);
68 /*!
69 When a code marker destroys itself, it removes itself from
70 the static list of code markers.
72 CodeMarker::~CodeMarker()
74 markers.removeAll(this);
77 /*!
78 The only thing a code market initializes is its \e{slow}
79 flag. The \e{slow} flag indicates whether the operations
80 that slow down qdoc are to be performed or not. It is
81 turned off by default.
83 void CodeMarker::initializeMarker(const Config &config)
85 slow = config.getBool(QLatin1String(CONFIG_SLOW));
88 /*!
89 Terminating a code marker is trivial.
91 void CodeMarker::terminateMarker()
93 // nothing.
96 /*!
97 All the code markers in the static list are initialized
98 here, after the qdoc configuration file has been loaded.
100 void CodeMarker::initialize(const Config& config)
102 defaultLang = config.getString(QLatin1String(CONFIG_LANGUAGE));
103 QList<CodeMarker *>::ConstIterator m = markers.begin();
104 while (m != markers.end()) {
105 (*m)->initializeMarker(config);
106 ++m;
111 All the code markers in the static list are terminated here.
113 void CodeMarker::terminate()
115 QList<CodeMarker *>::ConstIterator m = markers.begin();
116 while (m != markers.end()) {
117 (*m)->terminateMarker();
118 ++m;
122 CodeMarker *CodeMarker::markerForCode(const QString& code)
124 CodeMarker *defaultMarker = markerForLanguage(defaultLang);
125 if (defaultMarker != 0 && defaultMarker->recognizeCode(code))
126 return defaultMarker;
128 QList<CodeMarker *>::ConstIterator m = markers.begin();
129 while (m != markers.end()) {
130 if ((*m)->recognizeCode(code))
131 return *m;
132 ++m;
134 return defaultMarker;
137 CodeMarker *CodeMarker::markerForFileName(const QString& fileName)
139 CodeMarker *defaultMarker = markerForLanguage(defaultLang);
140 int dot = -1;
141 while ((dot = fileName.lastIndexOf(QLatin1Char('.'), dot)) != -1) {
142 QString ext = fileName.mid(dot + 1);
143 if (defaultMarker != 0 && defaultMarker->recognizeExtension(ext))
144 return defaultMarker;
145 QList<CodeMarker *>::ConstIterator m = markers.begin();
146 while (m != markers.end()) {
147 if ((*m)->recognizeExtension(ext))
148 return *m;
149 ++m;
151 --dot;
153 return defaultMarker;
156 CodeMarker *CodeMarker::markerForLanguage(const QString& lang)
158 QList<CodeMarker *>::ConstIterator m = markers.begin();
159 while (m != markers.end()) {
160 if ((*m)->recognizeLanguage(lang))
161 return *m;
162 ++m;
164 return 0;
167 const Node *CodeMarker::nodeForString(const QString& string)
169 if (sizeof(const Node *) == sizeof(uint)) {
170 return reinterpret_cast<const Node *>(string.toUInt());
172 else {
173 return reinterpret_cast<const Node *>(string.toULongLong());
177 QString CodeMarker::stringForNode(const Node *node)
179 if (sizeof(const Node *) == sizeof(ulong)) {
180 return QString::number(reinterpret_cast<ulong>(node));
182 else {
183 return QString::number(reinterpret_cast<qulonglong>(node));
187 static const QString samp = QLatin1String("&amp;");
188 static const QString slt = QLatin1String("&lt;");
189 static const QString sgt = QLatin1String("&gt;");
190 static const QString squot = QLatin1String("&quot;");
192 QString CodeMarker::protect(const QString& str)
194 int n = str.length();
195 QString marked;
196 marked.reserve(n * 2 + 30);
197 const QChar *data = str.constData();
198 for (int i = 0; i != n; ++i) {
199 switch (data[i].unicode()) {
200 case '&': marked += samp; break;
201 case '<': marked += slt; break;
202 case '>': marked += sgt; break;
203 case '"': marked += squot; break;
204 default : marked += data[i];
207 return marked;
210 QString CodeMarker::typified(const QString &string)
212 QString result;
213 QString pendingWord;
215 for (int i = 0; i <= string.size(); ++i) {
216 QChar ch;
217 if (i != string.size())
218 ch = string.at(i);
220 QChar lower = ch.toLower();
221 if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z'))
222 || ch.digitValue() >= 0 || ch == QLatin1Char('_')
223 || ch == QLatin1Char(':')) {
224 pendingWord += ch;
226 else {
227 if (!pendingWord.isEmpty()) {
228 bool isProbablyType = (pendingWord != QLatin1String("const"));
229 if (isProbablyType)
230 result += QLatin1String("<@type>");
231 result += pendingWord;
232 if (isProbablyType)
233 result += QLatin1String("</@type>");
235 pendingWord.clear();
237 switch (ch.unicode()) {
238 case '\0':
239 break;
240 case '&':
241 result += QLatin1String("&amp;");
242 break;
243 case '<':
244 result += QLatin1String("&lt;");
245 break;
246 case '>':
247 result += QLatin1String("&gt;");
248 break;
249 default:
250 result += ch;
254 return result;
257 QString CodeMarker::taggedNode(const Node* node)
259 QString tag;
261 switch (node->type()) {
262 case Node::Namespace:
263 tag = QLatin1String("@namespace");
264 break;
265 case Node::Class:
266 tag = QLatin1String("@class");
267 break;
268 case Node::Enum:
269 tag = QLatin1String("@enum");
270 break;
271 case Node::Typedef:
272 tag = QLatin1String("@typedef");
273 break;
274 case Node::Function:
275 tag = QLatin1String("@function");
276 break;
277 case Node::Property:
278 tag = QLatin1String("@property");
279 break;
280 default:
281 tag = QLatin1String("@unknown");
282 break;
284 return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
285 + QLatin1String("</") + tag + QLatin1Char('>');
288 #ifdef QDOC_QML
289 QString CodeMarker::taggedQmlNode(const Node* node)
291 QString tag;
292 switch (node->type()) {
293 case Node::QmlProperty:
294 tag = QLatin1String("@property");
295 break;
296 case Node::QmlSignal:
297 tag = QLatin1String("@signal");
298 break;
299 case Node::QmlMethod:
300 tag = QLatin1String("@method");
301 break;
302 default:
303 tag = QLatin1String("@unknown");
304 break;
306 return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
307 + QLatin1String("</") + tag + QLatin1Char('>');
309 #endif
311 QString CodeMarker::linkTag(const Node *node, const QString& body)
313 return QLatin1String("<@link node=\"") + stringForNode(node)
314 + QLatin1String("\">") + body + QLatin1String("</@link>");
317 QString CodeMarker::sortName(const Node *node)
319 QString nodeName = node->name();
320 int numDigits = 0;
321 for (int i = nodeName.size() - 1; i > 0; --i) {
322 if (nodeName.at(i).digitValue() == -1)
323 break;
324 ++numDigits;
327 // we want 'qint8' to appear before 'qint16'
328 if (numDigits > 0) {
329 for (int i = 0; i < 4 - numDigits; ++i)
330 nodeName.insert(nodeName.size()-numDigits-1, QLatin1String("0"));
333 if (node->type() == Node::Function) {
334 const FunctionNode *func = static_cast<const FunctionNode *>(node);
335 QString sortNo;
336 if (func->metaness() == FunctionNode::Ctor) {
337 sortNo = QLatin1String("C");
339 else if (func->metaness() == FunctionNode::Dtor) {
340 sortNo = QLatin1String("D");
342 else {
343 if (nodeName.startsWith(QLatin1String("operator"))
344 && nodeName.length() > 8
345 && !nodeName[8].isLetterOrNumber())
346 sortNo = QLatin1String("F");
347 else
348 sortNo = QLatin1String("E");
350 return sortNo + nodeName + QLatin1Char(' ')
351 + QString::number(func->overloadNumber(), 36);
354 if (node->type() == Node::Class)
355 return QLatin1Char('A') + nodeName;
357 if (node->type() == Node::Property || node->type() == Node::Variable)
358 return QLatin1Char('E') + nodeName;
360 return QLatin1Char('B') + nodeName;
363 void CodeMarker::insert(FastSection &fastSection,
364 Node *node,
365 SynopsisStyle style,
366 Status status)
368 bool irrelevant = false;
369 bool inheritedMember = false;
370 if (!node->relates()) {
371 if (node->parent() != (const InnerNode*)fastSection.innerNode) {
372 if (node->type() != Node::QmlProperty)
373 inheritedMember = true;
377 if (node->access() == Node::Private) {
378 irrelevant = true;
380 else if (node->type() == Node::Function) {
381 FunctionNode *func = (FunctionNode *) node;
382 irrelevant = (inheritedMember
383 && (func->metaness() == FunctionNode::Ctor ||
384 func->metaness() == FunctionNode::Dtor));
386 else if (node->type() == Node::Class || node->type() == Node::Enum
387 || node->type() == Node::Typedef) {
388 irrelevant = (inheritedMember && style != SeparateList);
389 if (!irrelevant && style == Detailed && node->type() == Node::Typedef) {
390 const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node);
391 if (typedeffe->associatedEnum())
392 irrelevant = true;
396 if (!irrelevant) {
397 if (status == Compat) {
398 irrelevant = (node->status() != Node::Compat);
400 else if (status == Obsolete) {
401 irrelevant = (node->status() != Node::Obsolete);
403 else {
404 irrelevant = (node->status() == Node::Compat ||
405 node->status() == Node::Obsolete);
409 if (!irrelevant) {
410 if (!inheritedMember || style == SeparateList) {
411 QString key = sortName(node);
412 if (!fastSection.memberMap.contains(key))
413 fastSection.memberMap.insert(key, node);
415 else {
416 if (node->parent()->type() == Node::Class) {
417 if (fastSection.inherited.isEmpty()
418 || fastSection.inherited.last().first != node->parent()) {
419 QPair<ClassNode *, int> p((ClassNode *)node->parent(), 0);
420 fastSection.inherited.append(p);
422 fastSection.inherited.last().second++;
429 Returns true if \a node represents a reimplemented member function.
430 If it is, then it is inserted in the reimplemented member map in the
431 section \a fs. And, the test is only performed if \a status is \e OK.
432 Otherwise, false is returned.
434 bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status)
436 if (node->access() == Node::Private)
437 return false;
439 const FunctionNode* fn = static_cast<const FunctionNode*>(node);
440 if ((fn->reimplementedFrom() != 0) && (status == Okay)) {
441 bool inherited = (!fn->relates() && (fn->parent() != (const InnerNode*)fs.innerNode));
442 if (!inherited) {
443 QString key = sortName(fn);
444 if (!fs.reimpMemberMap.contains(key)) {
445 fs.reimpMemberMap.insert(key,node);
446 return true;
450 return false;
454 If \a fs is not empty, convert it to a Section and append
455 the new Section to \a sectionList.
457 void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs)
459 if (!fs.isEmpty()) {
460 Section section(fs.name,fs.singularMember,fs.pluralMember);
461 section.members = fs.memberMap.values();
462 section.reimpMembers = fs.reimpMemberMap.values();
463 section.inherited = fs.inherited;
464 sectionList.append(section);
468 static QString encode(const QString &string)
470 #if 0
471 QString result = string;
473 for (int i = string.size() - 1; i >= 0; --i) {
474 uint ch = string.at(i).unicode();
475 if (ch > 0xFF)
476 ch = '?';
477 if ((ch - '0') >= 10 && (ch - 'a') >= 26 && (ch - 'A') >= 26
478 && ch != '/' && ch != '(' && ch != ')' && ch != ',' && ch != '*'
479 && ch != '&' && ch != '_' && ch != '<' && ch != '>' && ch != ':'
480 && ch != '~')
481 result.replace(i, 1, QString("%") + QString("%1").arg(ch, 2, 16));
483 return result;
484 #else
485 return string;
486 #endif
489 QStringList CodeMarker::macRefsForNode(const Node *node)
491 QString result = QLatin1String("cpp/");
492 switch (node->type()) {
493 case Node::Class:
495 const ClassNode *classe = static_cast<const ClassNode *>(node);
496 #if 0
497 if (!classe->templateStuff().isEmpty()) {
498 result += QLatin1String("tmplt/");
500 else
501 #endif
503 result += QLatin1String("cl/");
505 result += macName(classe); // ### Maybe plainName?
507 break;
508 case Node::Enum:
510 QStringList stringList;
511 stringList << encode(result + QLatin1String("tag/") +
512 macName(node));
513 foreach (const QString &enumName, node->doc().enumItemNames()) {
514 // ### Write a plainEnumValue() and use it here
515 stringList << encode(result + QLatin1String("econst/") +
516 macName(node->parent(), enumName));
518 return stringList;
520 case Node::Typedef:
521 result += QLatin1String("tdef/") + macName(node);
522 break;
523 case Node::Function:
525 bool isMacro = false;
526 const FunctionNode *func = static_cast<const FunctionNode *>(node);
528 // overloads are too clever for the Xcode documentation browser
529 if (func->isOverload())
530 return QStringList();
532 if (func->metaness() == FunctionNode::MacroWithParams
533 || func->metaness() == FunctionNode::MacroWithoutParams) {
534 result += QLatin1String("macro/");
535 isMacro = true;
536 #if 0
538 else if (!func->templateStuff().isEmpty()) {
539 result += QLatin1String("ftmplt/");
540 #endif
542 else if (func->isStatic()) {
543 result += QLatin1String("clm/");
545 else if (!func->parent()->name().isEmpty()) {
546 result += QLatin1String("instm/");
548 else {
549 result += QLatin1String("func/");
552 result += macName(func);
553 if (result.endsWith(QLatin1String("()")))
554 result.chop(2);
555 #if 0
556 // this code is too clever for the Xcode documentation
557 // browser and/or pbhelpindexer
558 if (!isMacro) {
559 result += "/" + QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/(";
560 const QList<Parameter> &params = func->parameters();
561 for (int i = 0; i < params.count(); ++i) {
562 QString type = params.at(i).leftType() +
563 params.at(i).rightType();
564 type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData()));
565 if (i != 0)
566 result += ",";
567 result += type;
569 result += ")";
571 #endif
573 break;
574 case Node::Variable:
575 result += QLatin1String("data/") + macName(node);
576 break;
577 case Node::Property:
579 NodeList list = static_cast<const PropertyNode*>(node)->functions();
580 QStringList stringList;
581 foreach (const Node *node, list) {
582 stringList += macRefsForNode(node);
584 return stringList;
586 case Node::Namespace:
587 case Node::Fake:
588 case Node::Target:
589 default:
590 return QStringList();
593 return QStringList(encode(result));
596 QString CodeMarker::macName(const Node *node, const QString &name)
598 QString myName = name;
599 if (myName.isEmpty()) {
600 myName = node->name();
601 node = node->parent();
604 if (node->name().isEmpty()) {
605 return QLatin1Char('/') + protect(myName);
607 else {
608 return plainFullName(node) + QLatin1Char('/') + protect(myName);
612 #ifdef QDOC_QML
614 Get the list of documentation sections for the children of
615 the specified QmlClassNode.
617 QList<Section> CodeMarker::qmlSections(const QmlClassNode* , SynopsisStyle )
619 return QList<Section>();
621 #endif
623 QT_END_NAMESPACE