1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the tools applications of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include <qobjectdefs.h>
43
#include "codemarker.h"
51
QString CodeMarker::defaultLang;
52
QList<CodeMarker *> CodeMarker::markers;
55
When a code marker constructs itself, it puts itself into
56
the static list of code markers. All the code markers in
57
the static list get initialized in initialize(), which is
58
not called until after the qdoc configuration file has
61
CodeMarker::CodeMarker()
63
markers.prepend(this);
67
When a code marker destroys itself, it removes itself from
68
the static list of code markers.
70
CodeMarker::~CodeMarker()
72
markers.removeAll(this);
76
A code market performs no initialization by default. Marker-specific
77
initialization is performed in subclasses.
79
void CodeMarker::initializeMarker(const Config& ) // config
84
Terminating a code marker is trivial.
86
void CodeMarker::terminateMarker()
92
All the code markers in the static list are initialized
93
here, after the qdoc configuration file has been loaded.
95
void CodeMarker::initialize(const Config& config)
97
defaultLang = config.getString(QLatin1String(CONFIG_LANGUAGE));
98
QList<CodeMarker *>::ConstIterator m = markers.constBegin();
99
while (m != markers.constEnd()) {
100
(*m)->initializeMarker(config);
106
All the code markers in the static list are terminated here.
108
void CodeMarker::terminate()
110
QList<CodeMarker *>::ConstIterator m = markers.constBegin();
111
while (m != markers.constEnd()) {
112
(*m)->terminateMarker();
117
CodeMarker *CodeMarker::markerForCode(const QString& code)
119
CodeMarker *defaultMarker = markerForLanguage(defaultLang);
120
if (defaultMarker != 0 && defaultMarker->recognizeCode(code))
121
return defaultMarker;
123
QList<CodeMarker *>::ConstIterator m = markers.constBegin();
124
while (m != markers.constEnd()) {
125
if ((*m)->recognizeCode(code))
129
return defaultMarker;
132
CodeMarker *CodeMarker::markerForFileName(const QString& fileName)
134
CodeMarker *defaultMarker = markerForLanguage(defaultLang);
136
while ((dot = fileName.lastIndexOf(QLatin1Char('.'), dot)) != -1) {
137
QString ext = fileName.mid(dot + 1);
138
if (defaultMarker != 0 && defaultMarker->recognizeExtension(ext))
139
return defaultMarker;
140
QList<CodeMarker *>::ConstIterator m = markers.constBegin();
141
while (m != markers.constEnd()) {
142
if ((*m)->recognizeExtension(ext))
148
return defaultMarker;
151
CodeMarker *CodeMarker::markerForLanguage(const QString& lang)
153
QList<CodeMarker *>::ConstIterator m = markers.constBegin();
154
while (m != markers.constEnd()) {
155
if ((*m)->recognizeLanguage(lang))
162
const Node *CodeMarker::nodeForString(const QString& string)
164
if (sizeof(const Node *) == sizeof(uint)) {
165
return reinterpret_cast<const Node *>(string.toUInt());
168
return reinterpret_cast<const Node *>(string.toULongLong());
172
QString CodeMarker::stringForNode(const Node *node)
174
if (sizeof(const Node *) == sizeof(ulong)) {
175
return QString::number(reinterpret_cast<quintptr>(node));
178
return QString::number(reinterpret_cast<qulonglong>(node));
182
static const QString samp = QLatin1String("&");
183
static const QString slt = QLatin1String("<");
184
static const QString sgt = QLatin1String(">");
185
static const QString squot = QLatin1String(""");
187
QString CodeMarker::protect(const QString& str)
189
int n = str.length();
191
marked.reserve(n * 2 + 30);
192
const QChar *data = str.constData();
193
for (int i = 0; i != n; ++i) {
194
switch (data[i].unicode()) {
195
case '&': marked += samp; break;
196
case '<': marked += slt; break;
197
case '>': marked += sgt; break;
198
case '"': marked += squot; break;
199
default : marked += data[i];
205
QString CodeMarker::typified(const QString &string)
210
for (int i = 0; i <= string.size(); ++i) {
212
if (i != string.size())
215
QChar lower = ch.toLower();
216
if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z'))
217
|| ch.digitValue() >= 0 || ch == QLatin1Char('_')
218
|| ch == QLatin1Char(':')) {
222
if (!pendingWord.isEmpty()) {
223
bool isProbablyType = (pendingWord != QLatin1String("const"));
225
result += QLatin1String("<@type>");
226
result += pendingWord;
228
result += QLatin1String("</@type>");
232
switch (ch.unicode()) {
236
result += QLatin1String("&");
239
result += QLatin1String("<");
242
result += QLatin1String(">");
252
QString CodeMarker::taggedNode(const Node* node)
255
QString name = node->name();
257
switch (node->type()) {
258
case Node::Namespace:
259
tag = QLatin1String("@namespace");
262
tag = QLatin1String("@class");
265
tag = QLatin1String("@enum");
268
tag = QLatin1String("@typedef");
271
tag = QLatin1String("@function");
274
tag = QLatin1String("@property");
278
Remove the "QML:" prefix, if present.
279
There shouldn't be any of these "QML:"
280
prefixes in the documentation sources
281
after the switch to using QML module
282
qualifiers, but this code is kept to
283
be backward compatible.
285
if (node->subType() == Node::QmlClass) {
286
if (node->name().startsWith(QLatin1String("QML:")))
289
tag = QLatin1String("@property");
291
case Node::QmlMethod:
292
case Node::QmlSignal:
293
case Node::QmlSignalHandler:
294
tag = QLatin1String("@function");
297
tag = QLatin1String("@unknown");
300
return (QLatin1Char('<') + tag + QLatin1Char('>') + protect(name)
301
+ QLatin1String("</") + tag + QLatin1Char('>'));
304
QString CodeMarker::taggedQmlNode(const Node* node)
307
switch (node->type()) {
308
case Node::QmlProperty:
309
tag = QLatin1String("@property");
311
case Node::QmlSignal:
312
tag = QLatin1String("@signal");
314
case Node::QmlSignalHandler:
315
tag = QLatin1String("@signalhandler");
317
case Node::QmlMethod:
318
tag = QLatin1String("@method");
321
tag = QLatin1String("@unknown");
324
return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
325
+ QLatin1String("</") + tag + QLatin1Char('>');
328
QString CodeMarker::linkTag(const Node *node, const QString& body)
330
return QLatin1String("<@link node=\"") + stringForNode(node)
331
+ QLatin1String("\">") + body + QLatin1String("</@link>");
334
QString CodeMarker::sortName(const Node *node, const QString* name)
340
nodeName = node->name();
342
for (int i = nodeName.size() - 1; i > 0; --i) {
343
if (nodeName.at(i).digitValue() == -1)
348
// we want 'qint8' to appear before 'qint16'
350
for (int i = 0; i < 4 - numDigits; ++i)
351
nodeName.insert(nodeName.size()-numDigits-1, QLatin1Char('0'));
354
if (node->type() == Node::Function) {
355
const FunctionNode *func = static_cast<const FunctionNode *>(node);
357
if (func->metaness() == FunctionNode::Ctor) {
358
sortNo = QLatin1String("C");
360
else if (func->metaness() == FunctionNode::Dtor) {
361
sortNo = QLatin1String("D");
364
if (nodeName.startsWith(QLatin1String("operator"))
365
&& nodeName.length() > 8
366
&& !nodeName[8].isLetterOrNumber())
367
sortNo = QLatin1String("F");
369
sortNo = QLatin1String("E");
371
return sortNo + nodeName + QLatin1Char(' ')
372
+ QString::number(func->overloadNumber(), 36);
375
if (node->type() == Node::Class)
376
return QLatin1Char('A') + nodeName;
378
if (node->type() == Node::Property || node->type() == Node::Variable)
379
return QLatin1Char('E') + nodeName;
381
if ((node->type() == Node::QmlMethod) ||
382
(node->type() == Node::QmlSignal) ||
383
(node->type() == Node::QmlSignalHandler)) {
384
const FunctionNode* func = static_cast<const FunctionNode *>(node);
385
return QLatin1Char('E') + func->signature();
388
return QLatin1Char('B') + nodeName;
391
void CodeMarker::insert(FastSection &fastSection,
396
bool irrelevant = false;
397
bool inheritedMember = false;
398
if (!node->relates()) {
399
if (node->parent() != fastSection.parent_) { // && !node->parent()->isAbstract()) {
400
if (node->type() != Node::QmlProperty) {
401
inheritedMember = true;
406
if (node->access() == Node::Private) {
409
else if (node->type() == Node::Function) {
410
FunctionNode *func = (FunctionNode *) node;
411
irrelevant = (inheritedMember
412
&& (func->metaness() == FunctionNode::Ctor ||
413
func->metaness() == FunctionNode::Dtor));
415
else if (node->type() == Node::Class || node->type() == Node::Enum
416
|| node->type() == Node::Typedef) {
417
irrelevant = (inheritedMember && style != Subpage);
418
if (!irrelevant && style == Detailed && node->type() == Node::Typedef) {
419
const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node);
420
if (typedeffe->associatedEnum())
426
if (status == Compat) {
427
irrelevant = (node->status() != Node::Compat);
429
else if (status == Obsolete) {
430
irrelevant = (node->status() != Node::Obsolete);
433
irrelevant = (node->status() == Node::Compat ||
434
node->status() == Node::Obsolete);
439
if (!inheritedMember || style == Subpage) {
440
QString key = sortName(node);
441
if (!fastSection.memberMap.contains(key))
442
fastSection.memberMap.insert(key, node);
445
if (node->parent()->type() == Node::Class) {
446
if (fastSection.inherited.isEmpty()
447
|| fastSection.inherited.last().first != node->parent()) {
448
QPair<InnerNode *, int> p(node->parent(), 0);
449
fastSection.inherited.append(p);
451
fastSection.inherited.last().second++;
457
void CodeMarker::insert(FastSection& fastSection,
460
bool /* includeClassName */)
462
if (node->status() == Node::Compat || node->status() == Node::Obsolete)
465
bool inheritedMember = false;
466
InnerNode* parent = node->parent();
467
if (parent && (parent->type() == Node::Document) &&
468
(parent->subType() == Node::QmlPropertyGroup)) {
469
parent = parent->parent();
471
inheritedMember = (parent != fastSection.parent_);
473
if (!inheritedMember || style == Subpage) {
474
QString key = sortName(node);
475
if (!fastSection.memberMap.contains(key))
476
fastSection.memberMap.insert(key, node);
479
if ((parent->type() == Node::Document) && (parent->subType() == Node::QmlClass)) {
480
if (fastSection.inherited.isEmpty()
481
|| fastSection.inherited.last().first != parent) {
482
QPair<InnerNode*, int> p(parent, 0);
483
fastSection.inherited.append(p);
485
fastSection.inherited.last().second++;
491
Returns true if \a node represents a reimplemented member
492
function in the class of the FastSection \a fs. If it is
493
a reimplemented function, then it is inserted into the
494
reimplemented member map in \a fs. The test is performed
495
only if \a status is \e OK. True is returned if \a node
496
is inserted into the map. Otherwise, false is returned.
498
bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status)
500
if ((node->access() != Node::Private) && (node->relates() == 0)) {
501
const FunctionNode* fn = static_cast<const FunctionNode*>(node);
502
if ((fn->reimplementedFrom() != 0) && (status == Okay)) {
503
if (fn->parent() == fs.parent_) {
504
QString key = sortName(fn);
505
if (!fs.reimpMemberMap.contains(key)) {
506
fs.reimpMemberMap.insert(key,node);
516
If \a fs is not empty, convert it to a Section and append
517
the new Section to \a sectionList.
519
void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs, bool includeKeys)
522
Section section(fs.name,fs.divClass,fs.singularMember,fs.pluralMember);
524
section.keys = fs.memberMap.keys();
526
section.members = fs.memberMap.values();
527
section.reimpMembers = fs.reimpMemberMap.values();
528
section.inherited = fs.inherited;
529
sectionList.append(section);
533
static QString encode(const QString &string)
538
QStringList CodeMarker::macRefsForNode(Node *node)
540
QString result = QLatin1String("cpp/");
541
switch (node->type()) {
544
const ClassNode *classe = static_cast<const ClassNode *>(node);
546
result += QLatin1String("cl/");
548
result += macName(classe); // ### Maybe plainName?
553
QStringList stringList;
554
stringList << encode(result + QLatin1String("tag/") +
556
foreach (const QString &enumName, node->doc().enumItemNames()) {
557
// ### Write a plainEnumValue() and use it here
558
stringList << encode(result + QLatin1String("econst/") +
559
macName(node->parent(), enumName));
564
result += QLatin1String("tdef/") + macName(node);
568
bool isMacro = false;
570
const FunctionNode *func = static_cast<const FunctionNode *>(node);
572
// overloads are too clever for the Xcode documentation browser
573
if (func->isOverload())
574
return QStringList();
576
if (func->metaness() == FunctionNode::MacroWithParams
577
|| func->metaness() == FunctionNode::MacroWithoutParams) {
578
result += QLatin1String("macro/");
580
else if (func->isStatic()) {
581
result += QLatin1String("clm/");
583
else if (!func->parent()->name().isEmpty()) {
584
result += QLatin1String("instm/");
587
result += QLatin1String("func/");
590
result += macName(func);
591
if (result.endsWith(QLatin1String("()")))
596
result += QLatin1String("data/") + macName(node);
600
NodeList list = static_cast<const PropertyNode*>(node)->functions();
601
QStringList stringList;
602
foreach (Node* node, list) {
603
stringList += macRefsForNode(node);
607
case Node::Namespace:
610
return QStringList();
613
return QStringList(encode(result));
616
QString CodeMarker::macName(const Node *node, const QString &name)
618
QString myName = name;
619
if (myName.isEmpty()) {
620
myName = node->name();
621
node = node->parent();
624
if (node->name().isEmpty()) {
625
return QLatin1Char('/') + protect(myName);
628
return node->plainFullName() + QLatin1Char('/') + protect(myName);
633
Returns an empty list of documentation sections.
635
QList<Section> CodeMarker::qmlSections(const QmlClassNode* , SynopsisStyle )
637
return QList<Section>();