summaryrefslogtreecommitdiffstats
path: root/src/tools/qdoc/codeparser.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2012-03-05 15:34:40 +0100
committerQt by Nokia <qt-info@nokia.com>2012-03-08 05:31:40 +0100
commit448a3cfe17735499cb43186200e8d52669b6a7ca (patch)
tree4792b705b7825126e62fc58cf69102ea0d009e0a /src/tools/qdoc/codeparser.cpp
parent6c612c933803ef57ea45e907d0181b40659148ac (diff)
Move qdoc into qtbase and bootstrap it
We need qdoc in qtbase to be able to properly modularize our documentation and build it when building the different Qt modules. qdoc does contain a copy of the qml parser from qmldevtools, but this is the lesser evil compared to how we are currently forced to genereate our docs (and the fact that no developer can run qdoc and check the docs for their module). Change-Id: I9f748459382a11cf5d5153d1ee611d7a5d3f4ac1 Reviewed-by: Casper van Donderen <casper.vandonderen@nokia.com> Reviewed-by: Martin Smith <martin.smith@nokia.com>
Diffstat (limited to 'src/tools/qdoc/codeparser.cpp')
-rw-r--r--src/tools/qdoc/codeparser.cpp409
1 files changed, 409 insertions, 0 deletions
diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp
new file mode 100644
index 0000000000..5173a404f2
--- /dev/null
+++ b/src/tools/qdoc/codeparser.cpp
@@ -0,0 +1,409 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ codeparser.cpp
+*/
+
+#include "codeparser.h"
+#include "node.h"
+#include "tree.h"
+#include "config.h"
+#include "generator.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#define COMMAND_COMPAT Doc::alias(QLatin1String("compat"))
+#define COMMAND_DEPRECATED Doc::alias(QLatin1String("deprecated")) // ### don't document
+#define COMMAND_INGROUP Doc::alias(QLatin1String("ingroup"))
+#define COMMAND_INMODULE Doc::alias(QLatin1String("inmodule")) // ### don't document
+#define COMMAND_INQMLMODULE Doc::alias(QLatin1String("inqmlmodule"))
+#define COMMAND_INTERNAL Doc::alias(QLatin1String("internal"))
+#define COMMAND_MAINCLASS Doc::alias(QLatin1String("mainclass"))
+#define COMMAND_NONREENTRANT Doc::alias(QLatin1String("nonreentrant"))
+#define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete"))
+#define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords"))
+#define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary"))
+#define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup"))
+#define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant"))
+#define COMMAND_SINCE Doc::alias(QLatin1String("since"))
+#define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle"))
+#define COMMAND_THREADSAFE Doc::alias(QLatin1String("threadsafe"))
+#define COMMAND_TITLE Doc::alias(QLatin1String("title"))
+
+QString CodeParser::currentSubDir_;
+QList<CodeParser *> CodeParser::parsers;
+bool CodeParser::showInternal = false;
+QMap<QString,QString> CodeParser::nameToTitle;
+
+/*!
+ The constructor adds this code parser to the static
+ list of code parsers.
+ */
+CodeParser::CodeParser()
+{
+ parsers.prepend(this);
+}
+
+/*!
+ The destructor removes this code parser from the static
+ list of code parsers.
+ */
+CodeParser::~CodeParser()
+{
+ parsers.removeAll(this);
+}
+
+/*!
+ Initialize the code parser base class.
+ */
+void CodeParser::initializeParser(const Config& config)
+{
+ showInternal = config.getBool(QLatin1String(CONFIG_SHOWINTERNAL));
+}
+
+/*!
+ Terminating a code parser is trivial.
+ */
+void CodeParser::terminateParser()
+{
+ // nothing.
+}
+
+QStringList CodeParser::headerFileNameFilter()
+{
+ return sourceFileNameFilter();
+}
+
+void CodeParser::parseHeaderFile(const Location& location,
+ const QString& filePath,
+ Tree *tree)
+{
+ parseSourceFile(location, filePath, tree);
+}
+
+void CodeParser::doneParsingHeaderFiles(Tree *tree)
+{
+ doneParsingSourceFiles(tree);
+}
+
+/*!
+ All the code parsers in the static list are initialized here,
+ after the qdoc configuration variables have been set.
+ */
+void CodeParser::initialize(const Config& config)
+{
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+ (*p)->initializeParser(config);
+ ++p;
+ }
+}
+
+/*!
+ All the code parsers in the static list are terminated here.
+ */
+void CodeParser::terminate()
+{
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+ (*p)->terminateParser();
+ ++p;
+ }
+}
+
+CodeParser *CodeParser::parserForLanguage(const QString& language)
+{
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+ if ((*p)->language() == language)
+ return *p;
+ ++p;
+ }
+ return 0;
+}
+
+CodeParser *CodeParser::parserForHeaderFile(const QString &filePath)
+{
+ QString fileName = QFileInfo(filePath).fileName();
+
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+
+ QStringList headerPatterns = (*p)->headerFileNameFilter();
+ foreach (QString pattern, headerPatterns) {
+ QRegExp re(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (re.exactMatch(fileName))
+ return *p;
+ }
+ ++p;
+ }
+ return 0;
+}
+
+CodeParser *CodeParser::parserForSourceFile(const QString &filePath)
+{
+ QString fileName = QFileInfo(filePath).fileName();
+
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+
+ QStringList sourcePatterns = (*p)->sourceFileNameFilter();
+ foreach (QString pattern, sourcePatterns) {
+ QRegExp re(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (re.exactMatch(fileName))
+ return *p;
+ }
+ ++p;
+ }
+ return 0;
+}
+
+/*!
+ Returns the set of strings representing the common metacommands.
+ */
+QSet<QString> CodeParser::commonMetaCommands()
+{
+ return QSet<QString>() << COMMAND_COMPAT
+ << COMMAND_DEPRECATED
+ << COMMAND_INGROUP
+ << COMMAND_INMODULE
+ << COMMAND_INQMLMODULE
+ << COMMAND_INTERNAL
+ << COMMAND_MAINCLASS
+ << COMMAND_NONREENTRANT
+ << COMMAND_OBSOLETE
+ << COMMAND_PAGEKEYWORDS
+ << COMMAND_PRELIMINARY
+ << COMMAND_INPUBLICGROUP
+ << COMMAND_REENTRANT
+ << COMMAND_SINCE
+ << COMMAND_SUBTITLE
+ << COMMAND_THREADSAFE
+ << COMMAND_TITLE;
+}
+
+/*!
+ The topic command has been processed. Now process the other
+ metacommands that were found. These are not the text markup
+ commands.
+ */
+void CodeParser::processCommonMetaCommand(const Location& location,
+ const QString& command,
+ const QString& arg,
+ Node* node,
+ Tree* tree)
+{
+ if (command == COMMAND_COMPAT) {
+ location.warning(tr("\\compat command used, but Qt3 compatibility is no longer supported"));
+ node->setStatus(Node::Compat);
+ }
+ else if (command == COMMAND_DEPRECATED) {
+ node->setStatus(Node::Deprecated);
+ }
+ else if (command == COMMAND_INGROUP) {
+ tree->addToGroup(node, arg);
+ }
+ else if (command == COMMAND_INPUBLICGROUP) {
+ tree->addToPublicGroup(node, arg);
+ }
+ else if (command == COMMAND_INMODULE) {
+ node->setModuleName(arg);
+ }
+ else if (command == COMMAND_INQMLMODULE) {
+ node->setQmlModuleName(arg);
+ tree->addToQmlModule(node,arg);
+ QString qmid = node->qmlModuleIdentifier();
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
+ QmlClassNode::moduleMap.insert(qmid + QLatin1String("::") + node->name(), qcn);
+ }
+ else if (command == COMMAND_MAINCLASS) {
+ node->setStatus(Node::Main);
+ }
+ else if (command == COMMAND_OBSOLETE) {
+ if (node->status() != Node::Compat)
+ node->setStatus(Node::Obsolete);
+ }
+ else if (command == COMMAND_NONREENTRANT) {
+ node->setThreadSafeness(Node::NonReentrant);
+ }
+ else if (command == COMMAND_PRELIMINARY) {
+ node->setStatus(Node::Preliminary);
+ }
+ else if (command == COMMAND_INTERNAL) {
+ if (!showInternal) {
+ node->setAccess(Node::Private);
+ node->setStatus(Node::Internal);
+ }
+ }
+ else if (command == COMMAND_REENTRANT) {
+ node->setThreadSafeness(Node::Reentrant);
+ }
+ else if (command == COMMAND_SINCE) {
+ node->setSince(arg);
+ }
+ else if (command == COMMAND_PAGEKEYWORDS) {
+ node->addPageKeywords(arg);
+ }
+ else if (command == COMMAND_SUBTITLE) {
+ if (node->type() == Node::Fake) {
+ FakeNode *fake = static_cast<FakeNode *>(node);
+ fake->setSubTitle(arg);
+ }
+ else
+ location.warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
+ }
+ else if (command == COMMAND_THREADSAFE) {
+ node->setThreadSafeness(Node::ThreadSafe);
+ }
+ else if (command == COMMAND_TITLE) {
+ if (node->type() == Node::Fake) {
+ FakeNode *fake = static_cast<FakeNode *>(node);
+ fake->setTitle(arg);
+ if (fake->subType() == Node::Example) {
+ ExampleNode::exampleNodeMap.insert(fake->title(),static_cast<ExampleNode*>(fake));
+ }
+ nameToTitle.insert(fake->name(),arg);
+ }
+ else
+ location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE));
+ }
+}
+
+/*!
+ Find the page title given the page \a name and return it.
+ */
+const QString CodeParser::titleFromName(const QString& name)
+{
+ const QString t = nameToTitle.value(name);
+ return t;
+}
+
+/*!
+ \internal
+ */
+void CodeParser::extractPageLinkAndDesc(const QString& arg,
+ QString* link,
+ QString* desc)
+{
+ QRegExp bracedRegExp(QLatin1String("\\{([^{}]*)\\}(?:\\{([^{}]*)\\})?"));
+
+ if (bracedRegExp.exactMatch(arg)) {
+ *link = bracedRegExp.cap(1);
+ *desc = bracedRegExp.cap(2);
+ if (desc->isEmpty())
+ *desc = *link;
+ }
+ else {
+ int spaceAt = arg.indexOf(QLatin1Char(' '));
+ if (arg.contains(QLatin1String(".html")) && spaceAt != -1) {
+ *link = arg.left(spaceAt).trimmed();
+ *desc = arg.mid(spaceAt).trimmed();
+ }
+ else {
+ *link = arg;
+ *desc = arg;
+ }
+ }
+}
+
+/*!
+ \internal
+ */
+void CodeParser::setLink(Node* node, Node::LinkType linkType, const QString& arg)
+{
+ QString link;
+ QString desc;
+ extractPageLinkAndDesc(arg, &link, &desc);
+ node->setLink(linkType, link, desc);
+}
+
+/*!
+ If the \e {basedir} variable is not set in the qdocconf
+ file, do nothing.
+
+ Otherwise, search for the basedir string string in the
+ \a filePath. It must be found, or else a warning message
+ is output. Extract the subdirectory name that follows the
+ basedir name and create a subdirectory using that name
+ in the output director.
+ */
+void CodeParser::createOutputSubdirectory(const Location& location,
+ const QString& filePath)
+{
+ QString bd = Generator::baseDir();
+ if (!bd.isEmpty()) {
+ int baseIdx = filePath.indexOf(bd);
+ if (baseIdx == -1)
+ location.warning(tr("File path: '%1' does not contain bundle base dir: '%2'")
+ .arg(filePath).arg(bd));
+ else {
+ int subDirIdx = filePath.indexOf(QLatin1Char('/'),baseIdx);
+ if (subDirIdx == -1)
+ location.warning(tr("File path: '%1' has no sub dir after bundle base dir: '%2'")
+ .arg(filePath).arg(bd));
+ else {
+ ++subDirIdx;
+ int fileNameIdx = filePath.indexOf(QLatin1Char('/'),subDirIdx);
+ if (fileNameIdx == -1)
+ location.warning(tr("File path: '%1' has no file name after sub dir: '%2/'")
+ .arg(filePath).arg(filePath.mid(subDirIdx)));
+ else {
+ currentSubDir_ = filePath.mid(subDirIdx,fileNameIdx-subDirIdx);
+ if (currentSubDir_.isEmpty())
+ location.warning(tr("File path: '%1' has no sub dir after bundle base dir: '%2'")
+ .arg(filePath).arg(bd));
+ else {
+ QString subDirPath = Generator::outputDir() + QLatin1Char('/') + currentSubDir_;
+ QDir dirInfo;
+ if (!dirInfo.exists(subDirPath)) {
+ if (!dirInfo.mkpath(subDirPath))
+ location.fatal(tr("Cannot create output sub-directory '%1'").arg(currentSubDir_));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE