diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:34:13 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:34:13 (GMT) |
commit | 67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch) | |
tree | 1dbf50b3dff8d5ca7e9344733968c72704eb15ff /tools/qdoc3/codemarker.cpp | |
download | Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2 |
Long live Qt!
Diffstat (limited to 'tools/qdoc3/codemarker.cpp')
-rw-r--r-- | tools/qdoc3/codemarker.cpp | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/tools/qdoc3/codemarker.cpp b/tools/qdoc3/codemarker.cpp new file mode 100644 index 0000000..a803281 --- /dev/null +++ b/tools/qdoc3/codemarker.cpp @@ -0,0 +1,538 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QMetaObject> +#include <QDebug> +#include "codemarker.h" +#include "config.h" +#include "node.h" + +#include <stdio.h> + +QT_BEGIN_NAMESPACE + +QString CodeMarker::defaultLang; +QList<CodeMarker *> CodeMarker::markers; + +/*! + When a code marker constructs itself, it puts itself into + the static list of code markers. All the code markers in + the static list get initialized in initialize(), which is + not called until after the qdoc configuration file has + been read. + */ +CodeMarker::CodeMarker() + : slow(false) +{ + markers.prepend(this); +} + +/*! + When a code marker destroys itself, it removes itself from + the static list of code markers. + */ +CodeMarker::~CodeMarker() +{ + markers.removeAll(this); +} + +/*! + The only thing a code market initializes is its \e{slow} + flag. The \e{slow} flag indicates whether the operations + that slow down qdoc are to be performed or not. It is + turned off by default. + */ +void CodeMarker::initializeMarker(const Config &config) +{ + slow = config.getBool(QLatin1String(CONFIG_SLOW)); +} + +/*! + Terminating a code marker is trivial. + */ +void CodeMarker::terminateMarker() +{ + // nothing. +} + +/*! + All the code markers in the static list are initialized + here, after the qdoc configuration file has been loaded. + */ +void CodeMarker::initialize(const Config& config) +{ + defaultLang = config.getString(QLatin1String(CONFIG_LANGUAGE)); + QList<CodeMarker *>::ConstIterator m = markers.begin(); + while (m != markers.end()) { + (*m)->initializeMarker(config); + ++m; + } +} + +/*! + All the code markers in the static list are terminated here. + */ +void CodeMarker::terminate() +{ + QList<CodeMarker *>::ConstIterator m = markers.begin(); + while (m != markers.end()) { + (*m)->terminateMarker(); + ++m; + } +} + +CodeMarker *CodeMarker::markerForCode(const QString& code) +{ + CodeMarker *defaultMarker = markerForLanguage(defaultLang); + if (defaultMarker != 0 && defaultMarker->recognizeCode(code)) + return defaultMarker; + + QList<CodeMarker *>::ConstIterator m = markers.begin(); + while (m != markers.end()) { + if ((*m)->recognizeCode(code)) + return *m; + ++m; + } + return defaultMarker; +} + +CodeMarker *CodeMarker::markerForFileName(const QString& fileName) +{ + CodeMarker *defaultMarker = markerForLanguage(defaultLang); + int dot = -1; + while ((dot = fileName.lastIndexOf(QLatin1Char('.'), dot)) != -1) { + QString ext = fileName.mid(dot + 1); + if (defaultMarker != 0 && defaultMarker->recognizeExtension(ext)) + return defaultMarker; + QList<CodeMarker *>::ConstIterator m = markers.begin(); + while (m != markers.end()) { + if ((*m)->recognizeExtension(ext)) + return *m; + ++m; + } + --dot; + } + return defaultMarker; +} + +CodeMarker *CodeMarker::markerForLanguage(const QString& lang) +{ + QList<CodeMarker *>::ConstIterator m = markers.begin(); + while (m != markers.end()) { + if ((*m)->recognizeLanguage(lang)) + return *m; + ++m; + } + return 0; +} + +const Node *CodeMarker::nodeForString(const QString& string) +{ + if (sizeof(const Node *) == sizeof(uint)) { + return reinterpret_cast<const Node *>(string.toUInt()); + } else { + return reinterpret_cast<const Node *>(string.toULongLong()); + } +} + +QString CodeMarker::stringForNode(const Node *node) +{ + if (sizeof(const Node *) == sizeof(ulong)) { + return QString::number(reinterpret_cast<ulong>(node)); + } else { + return QString::number(reinterpret_cast<qulonglong>(node)); + } +} + +static const QString samp = QLatin1String("&"); +static const QString slt = QLatin1String("<"); +static const QString sgt = QLatin1String(">"); +static const QString squot = QLatin1String("""); + +QString CodeMarker::protect(const QString& str) +{ + int n = str.length(); + QString marked; + marked.reserve(n * 2 + 30); + const QChar *data = str.constData(); + for (int i = 0; i != n; ++i) { + switch (data[i].unicode()) { + case '&': marked += samp; break; + case '<': marked += slt; break; + case '>': marked += sgt; break; + case '"': marked += squot; break; + default : marked += data[i]; + } + } + return marked; +} + +QString CodeMarker::typified(const QString &string) +{ + QString result; + QString pendingWord; + + for (int i = 0; i <= string.size(); ++i) { + QChar ch; + if (i != string.size()) + ch = string.at(i); + + QChar lower = ch.toLower(); + if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) + || ch.digitValue() >= 0 || ch == QLatin1Char('_') + || ch == QLatin1Char(':')) { + pendingWord += ch; + } else { + if (!pendingWord.isEmpty()) { + bool isProbablyType = (pendingWord != QLatin1String("const")); + if (isProbablyType) + result += QLatin1String("<@type>"); + result += pendingWord; + if (isProbablyType) + result += QLatin1String("</@type>"); + } + pendingWord.clear(); + + switch (ch.unicode()) { + case '\0': + break; + case '&': + result += QLatin1String("&"); + break; + case '<': + result += QLatin1String("<"); + break; + case '>': + result += QLatin1String(">"); + break; + default: + result += ch; + } + } + } + return result; +} + +QString CodeMarker::taggedNode(const Node *node) +{ + QString tag; + + switch (node->type()) { + case Node::Namespace: + tag = QLatin1String("@namespace"); + break; + case Node::Class: + tag = QLatin1String("@class"); + break; + case Node::Enum: + tag = QLatin1String("@enum"); + break; + case Node::Typedef: + tag = QLatin1String("@typedef"); + break; + case Node::Function: + tag = QLatin1String("@function"); + break; + case Node::Property: + tag = QLatin1String("@property"); + break; + default: + tag = QLatin1String("@unknown"); + } + return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + + QLatin1String("</") + tag + QLatin1Char('>'); +} + +QString CodeMarker::linkTag(const Node *node, const QString& body) +{ + return QLatin1String("<@link node=\"") + stringForNode(node) + + QLatin1String("\">") + body + QLatin1String("</@link>"); +} + +QString CodeMarker::sortName(const Node *node) +{ + QString nodeName = node->name(); + int numDigits = 0; + for (int i = nodeName.size() - 1; i > 0; --i) { + if (nodeName.at(i).digitValue() == -1) + break; + ++numDigits; + } + + // we want 'qint8' to appear before 'qint16' + if (numDigits > 0) { + for (int i = 0; i < 4 - numDigits; ++i) + nodeName.insert(nodeName.size()-numDigits-1, QLatin1String("0")); + } + + if (node->type() == Node::Function) { + const FunctionNode *func = static_cast<const FunctionNode *>(node); + QString sortNo; + if (func->metaness() == FunctionNode::Ctor) { + sortNo = QLatin1String("C"); + } else if (func->metaness() == FunctionNode::Dtor) { + sortNo = QLatin1String("D"); + } else { + if (nodeName.startsWith(QLatin1String("operator")) + && nodeName.length() > 8 + && !nodeName[8].isLetterOrNumber()) + sortNo = QLatin1String("F"); + else + sortNo = QLatin1String("E"); + } + return sortNo + nodeName + QLatin1Char(' ') + + QString::number(func->overloadNumber(), 36); + } + + if (node->type() == Node::Class) + return QLatin1Char('A') + nodeName; + + if (node->type() == Node::Property || node->type() == Node::Variable) + return QLatin1Char('E') + nodeName; + + return QLatin1Char('B') + nodeName; +} + +void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle style, Status status) +{ + bool inheritedMember = (!node->relates() && + (node->parent() != (const InnerNode *)fastSection.innerNode)); + bool irrelevant = false; + + if (node->access() == Node::Private) { + irrelevant = true; + } else if (node->type() == Node::Function) { + FunctionNode *func = (FunctionNode *) node; + irrelevant = (inheritedMember + && (func->metaness() == FunctionNode::Ctor || + func->metaness() == FunctionNode::Dtor)); + } else if (node->type() == Node::Class || node->type() == Node::Enum + || node->type() == Node::Typedef) { + irrelevant = (inheritedMember && style != SeparateList); + if (!irrelevant && style == Detailed && node->type() == Node::Typedef) { + const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node); + if (typedeffe->associatedEnum()) + irrelevant = true; + } + } + + if (!irrelevant) { + if (status == Compat) { + irrelevant = (node->status() != Node::Compat); + } else if (status == Obsolete) { + irrelevant = (node->status() != Node::Obsolete); + } else { + irrelevant = (node->status() == Node::Compat || + node->status() == Node::Obsolete); + } + } + + if (!irrelevant) { + if (!inheritedMember || style == SeparateList) { + QString key = sortName(node); + if (!fastSection.memberMap.contains(key)) + fastSection.memberMap.insert(key, node); + } else { + if (node->parent()->type() == Node::Class) { + if (fastSection.inherited.isEmpty() + || fastSection.inherited.last().first != node->parent()) { + QPair<ClassNode *, int> p((ClassNode *)node->parent(), 0); + fastSection.inherited.append(p); + } + fastSection.inherited.last().second++; + } + } + } +} + +void CodeMarker::append(QList<Section>& sectionList, + const FastSection& fastSection) +{ + if (!fastSection.memberMap.isEmpty() || + !fastSection.inherited.isEmpty()) { + Section section(fastSection.name, + fastSection.singularMember, + fastSection.pluralMember); + section.members = fastSection.memberMap.values(); + section.inherited = fastSection.inherited; + sectionList.append(section); + } +} + +static QString encode(const QString &string) +{ +#if 0 + QString result = string; + + for (int i = string.size() - 1; i >= 0; --i) { + uint ch = string.at(i).unicode(); + if (ch > 0xFF) + ch = '?'; + if ((ch - '0') >= 10 && (ch - 'a') >= 26 && (ch - 'A') >= 26 + && ch != '/' && ch != '(' && ch != ')' && ch != ',' && ch != '*' + && ch != '&' && ch != '_' && ch != '<' && ch != '>' && ch != ':' + && ch != '~') + result.replace(i, 1, QString("%") + QString("%1").arg(ch, 2, 16)); + } + return result; +#else + return string; +#endif +} + +QStringList CodeMarker::macRefsForNode(const Node *node) +{ + QString result = QLatin1String("cpp/"); + switch (node->type()) { + case Node::Class: + { + const ClassNode *classe = static_cast<const ClassNode *>(node); +#if 0 + if (!classe->templateStuff().isEmpty()) { + result += QLatin1String("tmplt/"); + } else +#endif + { + result += QLatin1String("cl/"); + } + result += macName(classe); // ### Maybe plainName? + } + break; + case Node::Enum: + { + QStringList stringList; + stringList << encode(result + QLatin1String("tag/") + + macName(node)); + foreach (const QString &enumName, node->doc().enumItemNames()) { + // ### Write a plainEnumValue() and use it here + stringList << encode(result + QLatin1String("econst/") + + macName(node->parent(), enumName)); + } + return stringList; + } + case Node::Typedef: + result += QLatin1String("tdef/") + macName(node); + break; + case Node::Function: + { + bool isMacro = false; + const FunctionNode *func = static_cast<const FunctionNode *>(node); + + // overloads are too clever for the Xcode documentation browser + if (func->isOverload()) + return QStringList(); + + if (func->metaness() == FunctionNode::MacroWithParams + || func->metaness() == FunctionNode::MacroWithoutParams) { + result += QLatin1String("macro/"); + isMacro = true; +#if 0 + } else if (!func->templateStuff().isEmpty()) { + result += QLatin1String("ftmplt/"); +#endif + } else if (func->isStatic()) { + result += QLatin1String("clm/"); + } else if (!func->parent()->name().isEmpty()) { + result += QLatin1String("instm/"); + } else { + result += QLatin1String("func/"); + } + + result += macName(func); + if (result.endsWith(QLatin1String("()"))) + result.chop(2); +#if 0 + // this code is too clever for the Xcode documentation + // browser and/or pbhelpindexer + if (!isMacro) { + result += "/" + QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/("; + const QList<Parameter> ¶ms = func->parameters(); + for (int i = 0; i < params.count(); ++i) { + QString type = params.at(i).leftType() + params.at(i).rightType(); + type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData())); + if (i != 0) + result += ","; + result += type; + } + result += ")"; + } +#endif + } + break; + case Node::Variable: + result += QLatin1String("data/") + macName(node); + break; + case Node::Property: + { + NodeList list = static_cast<const PropertyNode*>(node)->functions(); + QStringList stringList; + foreach (const Node *node, list) { + stringList += macRefsForNode(node); + } + return stringList; + } + case Node::Namespace: + case Node::Fake: + case Node::Target: + default: + return QStringList(); + } + + return QStringList(encode(result)); +} + +QString CodeMarker::macName(const Node *node, const QString &name) +{ + QString myName = name; + if (myName.isEmpty()) { + myName = node->name(); + node = node->parent(); + } + + if (node->name().isEmpty()) { + return QLatin1Char('/') + myName; + } else { + return plainFullName(node) + QLatin1Char('/') + myName; + } +} + + +QT_END_NAMESPACE |