1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the tools applications of the Qt Toolkit.
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
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.
40 ****************************************************************************/
42 #include <QMetaObject>
44 #include "codemarker.h"
52 QString
CodeMarker::defaultLang
;
53 QList
<CodeMarker
*> CodeMarker::markers
;
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
62 CodeMarker::CodeMarker()
65 markers
.prepend(this);
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);
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
));
89 Terminating a code marker is trivial.
91 void CodeMarker::terminateMarker()
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
);
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();
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
))
134 return defaultMarker
;
137 CodeMarker
*CodeMarker::markerForFileName(const QString
& fileName
)
139 CodeMarker
*defaultMarker
= markerForLanguage(defaultLang
);
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
))
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
))
167 const Node
*CodeMarker::nodeForString(const QString
& string
)
169 if (sizeof(const Node
*) == sizeof(uint
)) {
170 return reinterpret_cast<const Node
*>(string
.toUInt());
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
));
183 return QString::number(reinterpret_cast<qulonglong
>(node
));
187 static const QString samp
= QLatin1String("&");
188 static const QString slt
= QLatin1String("<");
189 static const QString sgt
= QLatin1String(">");
190 static const QString squot
= QLatin1String(""");
192 QString
CodeMarker::protect(const QString
& str
)
194 int n
= str
.length();
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
];
210 QString
CodeMarker::typified(const QString
&string
)
215 for (int i
= 0; i
<= string
.size(); ++i
) {
217 if (i
!= string
.size())
220 QChar lower
= ch
.toLower();
221 if ((lower
>= QLatin1Char('a') && lower
<= QLatin1Char('z'))
222 || ch
.digitValue() >= 0 || ch
== QLatin1Char('_')
223 || ch
== QLatin1Char(':')) {
227 if (!pendingWord
.isEmpty()) {
228 bool isProbablyType
= (pendingWord
!= QLatin1String("const"));
230 result
+= QLatin1String("<@type>");
231 result
+= pendingWord
;
233 result
+= QLatin1String("</@type>");
237 switch (ch
.unicode()) {
241 result
+= QLatin1String("&");
244 result
+= QLatin1String("<");
247 result
+= QLatin1String(">");
257 QString
CodeMarker::taggedNode(const Node
* node
)
261 switch (node
->type()) {
262 case Node::Namespace
:
263 tag
= QLatin1String("@namespace");
266 tag
= QLatin1String("@class");
269 tag
= QLatin1String("@enum");
272 tag
= QLatin1String("@typedef");
275 tag
= QLatin1String("@function");
278 tag
= QLatin1String("@property");
281 tag
= QLatin1String("@unknown");
284 return QLatin1Char('<') + tag
+ QLatin1Char('>') + protect(node
->name())
285 + QLatin1String("</") + tag
+ QLatin1Char('>');
289 QString
CodeMarker::taggedQmlNode(const Node
* node
)
292 switch (node
->type()) {
293 case Node::QmlProperty
:
294 tag
= QLatin1String("@property");
296 case Node::QmlSignal
:
297 tag
= QLatin1String("@signal");
299 case Node::QmlMethod
:
300 tag
= QLatin1String("@method");
303 tag
= QLatin1String("@unknown");
306 return QLatin1Char('<') + tag
+ QLatin1Char('>') + protect(node
->name())
307 + QLatin1String("</") + tag
+ QLatin1Char('>');
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();
321 for (int i
= nodeName
.size() - 1; i
> 0; --i
) {
322 if (nodeName
.at(i
).digitValue() == -1)
327 // we want 'qint8' to appear before 'qint16'
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
);
336 if (func
->metaness() == FunctionNode::Ctor
) {
337 sortNo
= QLatin1String("C");
339 else if (func
->metaness() == FunctionNode::Dtor
) {
340 sortNo
= QLatin1String("D");
343 if (nodeName
.startsWith(QLatin1String("operator"))
344 && nodeName
.length() > 8
345 && !nodeName
[8].isLetterOrNumber())
346 sortNo
= QLatin1String("F");
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
,
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
) {
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())
397 if (status
== Compat
) {
398 irrelevant
= (node
->status() != Node::Compat
);
400 else if (status
== Obsolete
) {
401 irrelevant
= (node
->status() != Node::Obsolete
);
404 irrelevant
= (node
->status() == Node::Compat
||
405 node
->status() == Node::Obsolete
);
410 if (!inheritedMember
|| style
== SeparateList
) {
411 QString key
= sortName(node
);
412 if (!fastSection
.memberMap
.contains(key
))
413 fastSection
.memberMap
.insert(key
, node
);
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
)
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
));
443 QString key
= sortName(fn
);
444 if (!fs
.reimpMemberMap
.contains(key
)) {
445 fs
.reimpMemberMap
.insert(key
,node
);
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
)
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
)
471 QString result
= string
;
473 for (int i
= string
.size() - 1; i
>= 0; --i
) {
474 uint ch
= string
.at(i
).unicode();
477 if ((ch
- '0') >= 10 && (ch
- 'a') >= 26 && (ch
- 'A') >= 26
478 && ch
!= '/' && ch
!= '(' && ch
!= ')' && ch
!= ',' && ch
!= '*'
479 && ch
!= '&' && ch
!= '_' && ch
!= '<' && ch
!= '>' && ch
!= ':'
481 result
.replace(i
, 1, QString("%") + QString("%1").arg(ch
, 2, 16));
489 QStringList
CodeMarker::macRefsForNode(const Node
*node
)
491 QString result
= QLatin1String("cpp/");
492 switch (node
->type()) {
495 const ClassNode
*classe
= static_cast<const ClassNode
*>(node
);
497 if (!classe
->templateStuff().isEmpty()) {
498 result
+= QLatin1String("tmplt/");
503 result
+= QLatin1String("cl/");
505 result
+= macName(classe
); // ### Maybe plainName?
510 QStringList stringList
;
511 stringList
<< encode(result
+ QLatin1String("tag/") +
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
));
521 result
+= QLatin1String("tdef/") + macName(node
);
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/");
538 else if (!func
->templateStuff().isEmpty()) {
539 result
+= QLatin1String("ftmplt/");
542 else if (func
->isStatic()) {
543 result
+= QLatin1String("clm/");
545 else if (!func
->parent()->name().isEmpty()) {
546 result
+= QLatin1String("instm/");
549 result
+= QLatin1String("func/");
552 result
+= macName(func
);
553 if (result
.endsWith(QLatin1String("()")))
556 // this code is too clever for the Xcode documentation
557 // browser and/or pbhelpindexer
559 result
+= "/" + QLatin1String(QMetaObject::normalizedSignature(func
->returnType().toLatin1().constData())) + "/(";
560 const QList
<Parameter
> ¶ms
= 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()));
575 result
+= QLatin1String("data/") + macName(node
);
579 NodeList list
= static_cast<const PropertyNode
*>(node
)->functions();
580 QStringList stringList
;
581 foreach (const Node
*node
, list
) {
582 stringList
+= macRefsForNode(node
);
586 case Node::Namespace
:
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
);
608 return plainFullName(node
) + QLatin1Char('/') + protect(myName
);
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
>();