aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp')
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp956
1 files changed, 628 insertions, 328 deletions
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index a7a176907..7cce97ae1 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -35,6 +35,7 @@
#include <typedatabase.h>
#include <algorithm>
#include <QtCore/QStack>
+#include <QtCore/QRegularExpression>
#include <QtCore/QTextStream>
#include <QtCore/QXmlStreamReader>
#include <QtCore/QFile>
@@ -46,36 +47,36 @@ static Indentor INDENT;
static bool shouldSkip(const AbstractMetaFunction* func)
{
- bool skipable = func->isConstructor()
- || func->isModifiedRemoved()
- || func->declaringClass() != func->ownerClass()
- || func->isCastOperator()
- || func->name() == QLatin1String("operator=");
-
- // Search a const clone
- if (!skipable && !func->isConstant()) {
- const AbstractMetaArgumentList funcArgs = func->arguments();
- foreach (AbstractMetaFunction* f, func->ownerClass()->functions()) {
- if (f != func
- && f->isConstant()
- && f->name() == func->name()
- && f->arguments().count() == funcArgs.count()) {
- // Compare each argument
- bool cloneFound = true;
-
- const AbstractMetaArgumentList fargs = f->arguments();
- for (int i = 0, max = funcArgs.count(); i < max; ++i) {
- if (funcArgs.at(i)->type()->typeEntry() != fargs.at(i)->type()->typeEntry()) {
- cloneFound = false;
- break;
- }
+ // Constructors go to separate section
+ if (DocParser::skipForQuery(func) || func->isConstructor())
+ return true;
+
+ // Search a const clone (QImage::bits() vs QImage::bits() const)
+ if (func->isConstant())
+ return false;
+
+ const AbstractMetaArgumentList funcArgs = func->arguments();
+ const AbstractMetaFunctionList &ownerFunctions = func->ownerClass()->functions();
+ for (AbstractMetaFunction *f : ownerFunctions) {
+ if (f != func
+ && f->isConstant()
+ && f->name() == func->name()
+ && f->arguments().count() == funcArgs.count()) {
+ // Compare each argument
+ bool cloneFound = true;
+
+ const AbstractMetaArgumentList fargs = f->arguments();
+ for (int i = 0, max = funcArgs.count(); i < max; ++i) {
+ if (funcArgs.at(i)->type()->typeEntry() != fargs.at(i)->type()->typeEntry()) {
+ cloneFound = false;
+ break;
}
- if (cloneFound)
- return true;
}
+ if (cloneFound)
+ return true;
}
}
- return skipable;
+ return false;
}
static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFunction* func2)
@@ -83,28 +84,106 @@ static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFu
return func1->name() < func2->name();
}
-static QString createRepeatedChar(int i, char c)
+class Pad
+{
+public:
+ explicit Pad(char c, int count) : m_char(c), m_count(count) {}
+
+ void write(QTextStream &str) const
+ {
+ for (int i = 0; i < m_count; ++i)
+ str << m_char;
+ }
+
+private:
+ const char m_char;
+ const int m_count;
+};
+
+inline QTextStream &operator<<(QTextStream &str, const Pad &pad)
{
- QString out;
- for (int j = 0; j < i; ++j)
- out += QLatin1Char(c);
+ pad.write(str);
+ return str;
+}
- return out;
+template <class String>
+static int writeEscapedRstText(QTextStream &str, const String &s)
+{
+ int escaped = 0;
+ for (const QChar &c : s) {
+ switch (c.unicode()) {
+ case '*':
+ case '`':
+ case '_':
+ case '\\':
+ str << '\\';
+ ++escaped;
+ break;
+ }
+ str << c;
+ }
+ return s.size() + escaped;
}
-static QString escape(QString str)
+class escape
{
- str.replace(QLatin1Char('*'), QLatin1String("\\*"));
- str.replace(QLatin1Char('_'), QLatin1String("\\_"));
+public:
+ explicit escape(const QStringRef &s) : m_string(s) {}
+
+ void write(QTextStream &str) const { writeEscapedRstText(str, m_string); }
+
+private:
+ const QStringRef m_string;
+};
+
+inline QTextStream &operator<<(QTextStream &str, const escape &e)
+{
+ e.write(str);
return str;
}
-static QString escape(const QStringRef& strref)
+// Return last character of a QString-buffered stream.
+static QChar lastChar(const QTextStream &str)
{
- QString str = strref.toString();
- return escape(str);
+ const QString *string = str.string();
+ Q_ASSERT(string);
+ return string->isEmpty() ? QChar() : *(string->crbegin());
}
+static QTextStream &ensureEndl(QTextStream &s)
+{
+ if (lastChar(s) != QLatin1Char('\n'))
+ s << endl;
+ return s;
+}
+
+static QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &message)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "While handling <";
+ const QStringRef currentTag = reader.name();
+ if (currentTag.isEmpty())
+ str << tag;
+ else
+ str << currentTag;
+ str << "> in " << context << ", line "<< reader.lineNumber()
+ << ": " << message;
+ return result;
+}
+
+static QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &location, const QString &identifier,
+ const QString &fallback)
+{
+ QString message = QLatin1String("Falling back to \"")
+ + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"") + location
+ + QLatin1Char('"');
+ if (!identifier.isEmpty())
+ message += QLatin1String(" [") + identifier + QLatin1Char(']');
+ return msgTagWarning(reader, context, tag, message);
+}
QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context)
: m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
@@ -125,7 +204,7 @@ QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, cons
m_handlerMap.insert(QLatin1String("argument"), &QtXmlToSphinx::handleArgumentTag);
m_handlerMap.insert(QLatin1String("teletype"), &QtXmlToSphinx::handleArgumentTag);
m_handlerMap.insert(QLatin1String("link"), &QtXmlToSphinx::handleLinkTag);
- m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleImageTag);
+ m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleInlineImageTag);
m_handlerMap.insert(QLatin1String("image"), &QtXmlToSphinx::handleImageTag);
m_handlerMap.insert(QLatin1String("list"), &QtXmlToSphinx::handleListTag);
m_handlerMap.insert(QLatin1String("term"), &QtXmlToSphinx::handleTermTag);
@@ -197,34 +276,34 @@ QString QtXmlToSphinx::popOutputBuffer()
return strcpy;
}
-QString QtXmlToSphinx::expandFunction(const QString& function)
+QString QtXmlToSphinx::expandFunction(const QString& function) const
{
- QStringList functionSpec = function.split(QLatin1Char('.'));
- QString className = functionSpec.first();
- const AbstractMetaClass* metaClass = 0;
- foreach (const AbstractMetaClass* cls, m_generator->classes()) {
- if (cls->name() == className) {
- metaClass = cls;
- break;
+ const int firstDot = function.indexOf(QLatin1Char('.'));
+ const AbstractMetaClass *metaClass = nullptr;
+ if (firstDot != -1) {
+ const QStringRef className = function.leftRef(firstDot);
+ const AbstractMetaClassList &classes = m_generator->classes();
+ for (const AbstractMetaClass *cls : classes) {
+ if (cls->name() == className) {
+ metaClass = cls;
+ break;
+ }
}
}
- if (metaClass) {
- functionSpec.removeFirst();
- return metaClass->typeEntry()->qualifiedTargetLangName()
- + QLatin1Char('.') + functionSpec.join(QLatin1Char('.'));
- } else {
- return function;
- }
+ return metaClass
+ ? metaClass->typeEntry()->qualifiedTargetLangName()
+ + function.right(function.size() - firstDot)
+ : function;
}
-QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName)
+QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) const
{
- // avoid constLast to stay Qt 5.5 compatible
- QString currentClass = m_context.split(QLatin1Char('.')).last();
+ const QStringRef currentClass = m_context.splitRef(QLatin1Char('.')).constLast();
const AbstractMetaClass* metaClass = 0;
- foreach (const AbstractMetaClass* cls, m_generator->classes()) {
+ const AbstractMetaClassList &classes = m_generator->classes();
+ for (const AbstractMetaClass *cls : classes) {
if (cls->name() == currentClass) {
metaClass = cls;
break;
@@ -233,13 +312,14 @@ QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName)
if (metaClass) {
QList<const AbstractMetaFunction*> funcList;
- foreach (const AbstractMetaFunction* func, metaClass->queryFunctionsByName(methodName)) {
+ const AbstractMetaFunctionList &methods = metaClass->queryFunctionsByName(methodName);
+ for (const AbstractMetaFunction *func : methods) {
if (methodName == func->name())
funcList.append(func);
}
const AbstractMetaClass* implementingClass = 0;
- foreach (const AbstractMetaFunction* func, funcList) {
+ for (const AbstractMetaFunction *func : qAsConst(funcList)) {
implementingClass = func->implementingClass();
if (implementingClass->name() == currentClass)
break;
@@ -290,94 +370,115 @@ QString QtXmlToSphinx::transform(const QString& doc)
m_lastTagName = reader.name().toString();
}
}
+
+ if (!m_inlineImages.isEmpty()) {
+ // Write out inline image definitions stored in handleInlineImageTag().
+ m_output << endl;
+ for (const InlineImage &img : qAsConst(m_inlineImages))
+ m_output << ".. |" << img.tag << "| image:: " << img.href << endl;
+ m_output << endl;
+ m_inlineImages.clear();
+ }
+
m_output.flush();
QString retval = popOutputBuffer();
Q_ASSERT(m_buffers.isEmpty());
return retval;
}
-QString QtXmlToSphinx::readFromLocations(const QStringList& locations, const QString& path, const QString& identifier)
+static QString resolveFile(const QStringList &locations, const QString &path)
{
- QString result;
- bool ok;
- foreach (QString location, locations) {
+ for (QString location : locations) {
location.append(QLatin1Char('/'));
location.append(path);
- result = readFromLocation(location, identifier, &ok);
- if (ok)
- break;
+ if (QFileInfo::exists(location))
+ return location;
}
- if (!ok) {
- qCDebug(lcShiboken).noquote().nospace() << "Couldn't read code snippet file: {"
- << locations.join(QLatin1Char('|')) << '}' << path;
- }
- return result;
+ return QString();
+}
+QString QtXmlToSphinx::readFromLocations(const QStringList &locations, const QString &path,
+ const QString &identifier, QString *errorMessage)
+{
+ QString result;
+ const QString resolvedPath = resolveFile(locations, path);
+ if (resolvedPath.isEmpty()) {
+ QTextStream(errorMessage) << "Could not resolve \"" << path << "\" in \""
+ << locations.join(QLatin1String("\", \""));
+ return QString(); // null
+ }
+ qCDebug(lcShiboken).noquote().nospace() << "snippet file " << path
+ << " [" << identifier << ']' << " resolved to " << resolvedPath;
+ return readFromLocation(resolvedPath, identifier, errorMessage);
}
-QString QtXmlToSphinx::readFromLocation(const QString& location, const QString& identifier, bool* ok)
+QString QtXmlToSphinx::readFromLocation(const QString &location, const QString &identifier,
+ QString *errorMessage)
{
QFile inputFile;
inputFile.setFileName(location);
if (!inputFile.open(QIODevice::ReadOnly)) {
- if (!ok) {
- qCDebug(lcShiboken).noquote().nospace() << "Couldn't read code snippet file: "
- << QDir::toNativeSeparators(inputFile.fileName());
- } else {
- *ok = false;
- }
- return QString();
+ QTextStream(errorMessage) << "Could not read code snippet file: "
+ << QDir::toNativeSeparators(inputFile.fileName())
+ << ": " << inputFile.errorString();
+ return QString(); // null
}
- QRegExp searchString(QLatin1String("//!\\s*\\[") + identifier + QLatin1String("\\]"));
- QRegExp codeSnippetCode(QLatin1String("//!\\s*\\[[\\w\\d\\s]+\\]"));
- QString code;
+ QString code = QLatin1String(""); // non-null
+ if (identifier.isEmpty()) {
+ while (!inputFile.atEnd())
+ code += QString::fromUtf8(inputFile.readLine());
+ return code;
+ }
+
+ const QRegularExpression searchString(QLatin1String("//!\\s*\\[")
+ + identifier + QLatin1String("\\]"));
+ Q_ASSERT(searchString.isValid());
+ static const QRegularExpression codeSnippetCode(QLatin1String("//!\\s*\\[[\\w\\d\\s]+\\]"));
+ Q_ASSERT(codeSnippetCode.isValid());
- bool identifierIsEmpty = identifier.isEmpty();
bool getCode = false;
while (!inputFile.atEnd()) {
QString line = QString::fromUtf8(inputFile.readLine());
- if (identifierIsEmpty) {
- code += line;
- } else if (getCode && !line.contains(searchString)) {
+ if (getCode && !line.contains(searchString)) {
line.remove(codeSnippetCode);
code += line;
} else if (line.contains(searchString)) {
if (getCode)
break;
- else
- getCode = true;
+ getCode = true;
}
}
- if (!identifierIsEmpty && !getCode) {
- qCDebug(lcShiboken).noquote().nospace() << "Code snippet file found ("
- << location << "), but snippet " << identifier << " not found.";
+ if (!getCode) {
+ QTextStream(errorMessage) << "Code snippet file found ("
+ << QDir::toNativeSeparators(location) << "), but snippet ["
+ << identifier << "] not found.";
+ return QString(); // null
}
- if (ok)
- *ok = true;
return code;
}
void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
{
- static QString heading;
+ static int headingSize = 0;
static char type;
static char types[] = { '-', '^' };
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::StartElement) {
- uint typeIdx = reader.attributes().value(QLatin1String("level")).toString().toInt();
+ uint typeIdx = reader.attributes().value(QLatin1String("level")).toUInt();
if (typeIdx >= sizeof(types))
type = types[sizeof(types)-1];
else
type = types[typeIdx];
} else if (token == QXmlStreamReader::EndElement) {
- m_output << createRepeatedChar(heading.length(), type) << endl << endl;
+ m_output << Pad(type, headingSize) << endl << endl;
} else if (token == QXmlStreamReader::Characters) {
- heading = escape(reader.text()).trimmed();
- m_output << endl << endl << heading << endl;
+ m_output << endl << endl;
+ headingSize = writeEscapedRstText(m_output, reader.text().trimmed());
+ m_output << endl;
}
}
@@ -395,14 +496,14 @@ void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader)
m_output << INDENT << result << endl << endl;
} else if (token == QXmlStreamReader::Characters) {
- QString text = escape(reader.text());
- if (!m_output.string()->isEmpty()) {
+ const QStringRef text = reader.text();
+ const QChar end = lastChar(m_output);
+ if (!text.isEmpty() && INDENT.indent == 0 && !end.isNull()) {
QChar start = text[0];
- QChar end = m_output.string()->at(m_output.string()->length() - 1);
if ((end == QLatin1Char('*') || end == QLatin1Char('`')) && start != QLatin1Char(' ') && !start.isPunct())
m_output << '\\';
}
- m_output << INDENT << text;
+ m_output << INDENT << escape(text);
}
}
@@ -413,7 +514,7 @@ void QtXmlToSphinx::handleItalicTag(QXmlStreamReader& reader)
m_insideItalic = !m_insideItalic;
m_output << '*';
} else if (token == QXmlStreamReader::Characters) {
- m_output << escape(reader.text()).trimmed();
+ m_output << escape(reader.text().trimmed());
}
}
@@ -424,7 +525,7 @@ void QtXmlToSphinx::handleBoldTag(QXmlStreamReader& reader)
m_insideBold = !m_insideBold;
m_output << "**";
} else if (token == QXmlStreamReader::Characters) {
- m_output << escape(reader.text()).trimmed();
+ m_output << escape(reader.text().trimmed());
}
}
@@ -434,16 +535,102 @@ void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader)
if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement)
m_output << "``";
else if (token == QXmlStreamReader::Characters)
- m_output << reader.text().toString().trimmed();
+ m_output << reader.text().trimmed();
}
+static inline QString functionLinkType() { return QStringLiteral("function"); }
+static inline QString classLinkType() { return QStringLiteral("class"); }
+
+static inline QString fixLinkType(const QStringRef &type)
+{
+ // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
+ // are recognized as such or not in the binding
+ if (type == QLatin1String("property"))
+ return functionLinkType();
+ if (type == QLatin1String("typedef"))
+ return classLinkType();
+ return type.toString();
+}
+
+static inline QString linkSourceAttribute(const QString &type)
+{
+ if (type == functionLinkType() || type == classLinkType())
+ return QLatin1String("raw");
+ return type == QLatin1String("enum") || type == QLatin1String("page")
+ ? type : QLatin1String("href");
+}
+
+// "See also" links may appear as nested links:
+// <see-also>QAbstractXmlReceiver<link raw="isValid()" href="qxmlquery.html#isValid" type="function">isValid()</link>
+// which is handled in handleLinkTag
+// or direct text:
+// <see-also>rootIsDecorated()</see-also>
+// which is handled here.
+
void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement)
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
m_output << INDENT << ".. seealso:: ";
- else if (token == QXmlStreamReader::EndElement)
+ break;
+ case QXmlStreamReader::Characters: {
+ // Direct embedded link: <see-also>rootIsDecorated()</see-also>
+ const QStringRef textR = reader.text().trimmed();
+ if (!textR.isEmpty()) {
+ const QString text = textR.toString();
+ if (m_seeAlsoContext.isNull()) {
+ const QString type = text.endsWith(QLatin1String("()"))
+ ? functionLinkType() : classLinkType();
+ m_seeAlsoContext.reset(handleLinkStart(type, text));
+ }
+ handleLinkText(m_seeAlsoContext.data(), text);
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (!m_seeAlsoContext.isNull()) { // direct, no nested </link> seen
+ handleLinkEnd(m_seeAlsoContext.data());
+ m_seeAlsoContext.reset();
+ }
m_output << endl;
+ break;
+ default:
+ break;
+ }
+}
+
+static inline QString fallbackPathAttribute() { return QStringLiteral("path"); }
+
+static inline bool snippetComparison()
+{
+ return ReportHandler::debugLevel() >= ReportHandler::FullDebug;
+}
+
+template <class Indent> // const char*/class Indentor
+void formatSnippet(QTextStream &str, Indent indent, const QString &snippet)
+{
+ const QVector<QStringRef> lines = snippet.splitRef(QLatin1Char('\n'));
+ for (const QStringRef &line : lines) {
+ if (!line.trimmed().isEmpty())
+ str << indent << line;
+ str << endl;
+ }
+}
+
+static QString msgSnippetComparison(const QString &location, const QString &identifier,
+ const QString &pythonCode, const QString &fallbackCode)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Python snippet " << location;
+ if (!identifier.isEmpty())
+ str << " [" << identifier << ']';
+ str << ":\n";
+ formatSnippet(str, " ", pythonCode);
+ str << "Corresponding fallback snippet:\n";
+ formatSnippet(str, " ", fallbackCode);
+ str << "-- end --\n";
+ return result;
}
void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
@@ -458,21 +645,38 @@ void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
}
QString location = reader.attributes().value(QLatin1String("location")).toString();
QString identifier = reader.attributes().value(QLatin1String("identifier")).toString();
- QString code = readFromLocations(m_generator->codeSnippetDirs(), location, identifier);
+ QString errorMessage;
+ const QString pythonCode =
+ readFromLocations(m_generator->codeSnippetDirs(), location, identifier, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShiboken, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)));
+ // Fall back to C++ snippet when "path" attribute is present.
+ // Also read fallback snippet when comparison is desired.
+ QString fallbackCode;
+ if ((pythonCode.isNull() || snippetComparison())
+ && reader.attributes().hasAttribute(fallbackPathAttribute())) {
+ const QString fallback = reader.attributes().value(fallbackPathAttribute()).toString();
+ if (QFileInfo::exists(fallback)) {
+ if (pythonCode.isNull())
+ qCWarning(lcShiboken, "%s", qPrintable(msgFallbackWarning(reader, m_context, m_lastTagName, location, identifier, fallback)));
+ fallbackCode = readFromLocation(fallback, identifier, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShiboken, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)));
+ }
+ }
+
+ if (!pythonCode.isEmpty() && !fallbackCode.isEmpty() && snippetComparison())
+ qCDebug(lcShiboken, "%s", qPrintable(msgSnippetComparison(location, identifier, pythonCode, fallbackCode)));
+
if (!consecutiveSnippet)
m_output << INDENT << "::\n\n";
Indentation indentation(INDENT);
- if (code.isEmpty()) {
+ const QString code = pythonCode.isNull() ? fallbackCode : pythonCode;
+ if (code.isEmpty())
m_output << INDENT << "<Code snippet \"" << location << ':' << identifier << "\" not found>" << endl;
- } else {
- foreach (const QString &line, code.split(QLatin1Char('\n'))) {
- if (!QString(line).trimmed().isEmpty())
- m_output << INDENT << line;
-
- m_output << endl;
- }
- }
+ else
+ formatSnippet(m_output, INDENT, code);
m_output << endl;
}
}
@@ -489,7 +693,7 @@ void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader)
Indentation indentation(INDENT);
pushOutputBuffer();
m_output << INDENT;
- int indent = reader.attributes().value(QLatin1String("indent")).toString().toInt();
+ int indent = reader.attributes().value(QLatin1String("indent")).toInt();
for (int i = 0; i < indent; ++i)
m_output << ' ';
} else if (token == QXmlStreamReader::Characters) {
@@ -509,7 +713,7 @@ void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader)
// write the table on m_output
m_currentTable.enableHeader(m_tableHasHeader);
m_currentTable.normalize();
- m_output << m_currentTable;
+ m_output << ensureEndl << m_currentTable;
m_currentTable.clear();
}
}
@@ -537,8 +741,8 @@ void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader)
m_currentTable << TableRow();
TableRow& row = m_currentTable.last();
TableCell cell;
- cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toString().toShort();
- cell.rowSpan = reader.attributes().value(QLatin1String("rowspan")).toString().toShort();
+ cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toShort();
+ cell.rowSpan = reader.attributes().value(QLatin1String("rowspan")).toShort();
row << cell;
pushOutputBuffer();
} else if (token == QXmlStreamReader::EndElement) {
@@ -577,9 +781,9 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
if (!m_currentTable.isEmpty()) {
if (listType == QLatin1String("bullet")) {
m_output << endl;
- foreach (TableCell cell, m_currentTable.first()) {
- QStringList itemLines = cell.data.split(QLatin1Char('\n'));
- m_output << INDENT << "* " << itemLines.first() << endl;
+ for (const TableCell &cell : m_currentTable.constFirst()) {
+ const QVector<QStringRef> itemLines = cell.data.splitRef(QLatin1Char('\n'));
+ m_output << INDENT << "* " << itemLines.constFirst() << endl;
for (int i = 1, max = itemLines.count(); i < max; ++i)
m_output << INDENT << " " << itemLines[i] << endl;
}
@@ -587,7 +791,7 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
} else if (listType == QLatin1String("enum")) {
m_currentTable.enableHeader(m_tableHasHeader);
m_currentTable.normalize();
- m_output << m_currentTable;
+ m_output << ensureEndl << m_currentTable;
}
}
m_currentTable.clear();
@@ -596,115 +800,197 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
{
- static QString l_linktag;
- static QString l_linkref;
- static QString l_linktext;
- static QString l_linktagending;
- static QString l_type;
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- l_linktagending = QLatin1String("` ");
- if (m_insideBold) {
- l_linktag.prepend(QLatin1String("**"));
- l_linktagending.append(QLatin1String("**"));
- } else if (m_insideItalic) {
- l_linktag.prepend(QLatin1Char('*'));
- l_linktagending.append(QLatin1Char('*'));
- }
- l_type = reader.attributes().value(QLatin1String("type")).toString();
-
- // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
- // are recognized as such or not in the binding
- if (l_type == QLatin1String("property"))
- l_type = QLatin1String("function");
-
- if (l_type == QLatin1String("typedef"))
- l_type = QLatin1String("class");
-
- QString linkSource;
- if (l_type == QLatin1String("function") || l_type == QLatin1String("class")) {
- linkSource = QLatin1String("raw");
- } else if (l_type == QLatin1String("enum")) {
- linkSource = QLatin1String("enum");
- } else if (l_type == QLatin1String("page")) {
- linkSource = QLatin1String("page");
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement: {
+ // <link> embedded in <see-also> means the characters of <see-also> are no link.
+ m_seeAlsoContext.reset();
+ const QString type = fixLinkType(reader.attributes().value(QLatin1String("type")));
+ const QString ref = reader.attributes().value(linkSourceAttribute(type)).toString();
+ m_linkContext.reset(handleLinkStart(type, ref));
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ Q_ASSERT(!m_linkContext.isNull());
+ handleLinkText(m_linkContext.data(), reader.text().toString());
+ break;
+ case QXmlStreamReader::EndElement:
+ Q_ASSERT(!m_linkContext.isNull());
+ handleLinkEnd(m_linkContext.data());
+ m_linkContext.reset();
+ break;
+ default:
+ break;
+ }
+}
+
+QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, const QString &ref) const
+{
+ LinkContext *result = new LinkContext(ref, type);
+
+ result->linkTagEnding = QLatin1String("` ");
+ if (m_insideBold) {
+ result->linkTag.prepend(QLatin1String("**"));
+ result->linkTagEnding.append(QLatin1String("**"));
+ } else if (m_insideItalic) {
+ result->linkTag.prepend(QLatin1Char('*'));
+ result->linkTagEnding.append(QLatin1Char('*'));
+ }
+
+ result->linkRef.replace(QLatin1String("::"), QLatin1String("."));
+ result->linkRef.remove(QLatin1String("()"));
+
+ if (result->type == functionLinkType() && !m_context.isEmpty()) {
+ result->linkTag = QLatin1String(" :meth:`");
+ const QVector<QStringRef> rawlinklist = result->linkRef.splitRef(QLatin1Char('.'));
+ if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) {
+ QString context = resolveContextForMethod(rawlinklist.constLast().toString());
+ if (!result->linkRef.startsWith(context))
+ result->linkRef.prepend(context + QLatin1Char('.'));
} else {
- linkSource = QLatin1String("href");
+ result->linkRef = expandFunction(result->linkRef);
}
-
- l_linkref = reader.attributes().value(linkSource).toString();
- l_linkref.replace(QLatin1String("::"), QLatin1String("."));
- l_linkref.remove(QLatin1String("()"));
-
- if (l_type == QLatin1String("function") && !m_context.isEmpty()) {
- l_linktag = QLatin1String(" :meth:`");
- QStringList rawlinklist = l_linkref.split(QLatin1Char('.'));
- if (rawlinklist.size() == 1 || rawlinklist.first() == m_context) {
- QString context = resolveContextForMethod(rawlinklist.last());
- if (!l_linkref.startsWith(context))
- l_linkref.prepend(context + QLatin1Char('.'));
- } else {
- l_linkref = expandFunction(l_linkref);
+ } else if (result->type == functionLinkType() && m_context.isEmpty()) {
+ result->linkTag = QLatin1String(" :func:`");
+ } else if (result->type == classLinkType()) {
+ result->linkTag = QLatin1String(" :class:`");
+ if (const TypeEntry *type = TypeDatabase::instance()->findType(result->linkRef)) {
+ result->linkRef = type->qualifiedTargetLangName();
+ } else { // fall back to the old heuristic if the type wasn't found.
+ const QVector<QStringRef> rawlinklist = result->linkRef.splitRef(QLatin1Char('.'));
+ QStringList splittedContext = m_context.split(QLatin1Char('.'));
+ if (rawlinklist.size() == 1 || rawlinklist.constFirst() == splittedContext.constLast()) {
+ splittedContext.removeLast();
+ result->linkRef.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.'))
+ + QLatin1Char('.'));
}
- } else if (l_type == QLatin1String("function") && m_context.isEmpty()) {
- l_linktag = QLatin1String(" :func:`");
- } else if (l_type == QLatin1String("class")) {
- l_linktag = QLatin1String(" :class:`");
- TypeEntry* type = TypeDatabase::instance()->findType(l_linkref);
- if (type) {
- l_linkref = type->qualifiedTargetLangName();
- } else { // fall back to the old heuristic if the type wasn't found.
- QStringList rawlinklist = l_linkref.split(QLatin1Char('.'));
- QStringList splittedContext = m_context.split(QLatin1Char('.'));
- if (rawlinklist.size() == 1 || rawlinklist.first() == splittedContext.last()) {
- splittedContext.removeLast();
- l_linkref.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.'))
- + QLatin1Char('.'));
- }
- }
- } else if (l_type == QLatin1String("enum")) {
- l_linktag = QLatin1String(" :attr:`");
- } else if (l_type == QLatin1String("page") && l_linkref == m_generator->moduleName()) {
- l_linktag = QLatin1String(" :mod:`");
- } else {
- l_linktag = QLatin1String(" :ref:`");
}
+ } else if (result->type == QLatin1String("enum")) {
+ result->linkTag = QLatin1String(" :attr:`");
+ } else if (result->type == QLatin1String("page") && result->linkRef == m_generator->moduleName()) {
+ result->linkTag = QLatin1String(" :mod:`");
+ } else {
+ result->linkTag = QLatin1String(" :ref:`");
+ }
+ return result;
+}
- } else if (token == QXmlStreamReader::Characters) {
- QString linktext = reader.text().toString();
- linktext.replace(QLatin1String("::"), QLatin1String("."));
- // avoid constLast to stay Qt 5.5 compatible
- QString item = l_linkref.split(QLatin1Char('.')).last();
- if (l_linkref == linktext
- || (l_linkref + QLatin1String("()")) == linktext
- || item == linktext
- || (item + QLatin1String("()")) == linktext)
- l_linktext.clear();
- else
- l_linktext = linktext + QLatin1Char('<');
- } else if (token == QXmlStreamReader::EndElement) {
- if (!l_linktext.isEmpty())
- l_linktagending.prepend(QLatin1Char('>'));
- m_output << l_linktag << l_linktext << escape(l_linkref) << l_linktagending;
+void QtXmlToSphinx::handleLinkText(LinkContext *linkContext, QString linktext) const
+{
+ linktext.replace(QLatin1String("::"), QLatin1String("."));
+ const QStringRef item = linkContext->linkRef.splitRef(QLatin1Char('.')).constLast();
+ if (linkContext->linkRef == linktext
+ || (linkContext->linkRef + QLatin1String("()")) == linktext
+ || item == linktext
+ || (item + QLatin1String("()")) == linktext) {
+ linkContext->linkText.clear();
+ } else {
+ linkContext->linkText = linktext + QLatin1Char('<');
}
}
-void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
+void QtXmlToSphinx::handleLinkEnd(LinkContext *linkContext)
{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- QString href = reader.attributes().value(QLatin1String("href")).toString();
- QString packageName = m_generator->packageName();
- packageName.replace(QLatin1Char('.'), QLatin1Char('/'));
- QDir dir(m_generator->outputDirectory() + QLatin1Char('/') + packageName);
- QString imgPath = dir.relativeFilePath(m_generator->libSourceDir() + QLatin1String("/doc/src/"))
- + QLatin1Char('/') + href;
-
- if (reader.name() == QLatin1String("image"))
- m_output << INDENT << ".. image:: " << imgPath << endl << endl;
- else
- m_output << ".. image:: " << imgPath << ' ';
+ if (!linkContext->linkText.isEmpty())
+ linkContext->linkTagEnding.prepend(QLatin1Char('>'));
+ m_output << linkContext->linkTag << linkContext->linkText;
+ writeEscapedRstText(m_output, linkContext->linkRef);
+ m_output << linkContext->linkTagEnding;
+}
+
+// Copy images that are placed in a subdirectory "images" under the webxml files
+// by qdoc to a matching subdirectory under the "rst/PySide2/<module>" directory
+static bool copyImage(const QString &href, const QString &docDataDir,
+ const QString &context, const QString &outputDir,
+ QString *errorMessage)
+{
+ const QChar slash = QLatin1Char('/');
+ const int lastSlash = href.lastIndexOf(slash);
+ const QString imagePath = lastSlash != -1 ? href.left(lastSlash) : QString();
+ const QString imageFileName = lastSlash != -1 ? href.right(href.size() - lastSlash - 1) : href;
+ QFileInfo imageSource(docDataDir + slash + href);
+ if (!imageSource.exists()) {
+ QTextStream(errorMessage) << "Image " << href << " does not exist in "
+ << QDir::toNativeSeparators(docDataDir);
+ return false;
+ }
+ // Determine directory from context, "Pyside2.QtGui.QPainter" ->"Pyside2/QtGui".
+ // FIXME: Not perfect yet, should have knowledge about namespaces (DataVis3D) or
+ // nested classes "Pyside2.QtGui.QTouchEvent.QTouchPoint".
+ QString relativeTargetDir = context;
+ const int lastDot = relativeTargetDir.lastIndexOf(QLatin1Char('.'));
+ if (lastDot != -1)
+ relativeTargetDir.truncate(lastDot);
+ relativeTargetDir.replace(QLatin1Char('.'), slash);
+ if (!imagePath.isEmpty())
+ relativeTargetDir += slash + imagePath;
+
+ const QString targetDir = outputDir + slash + relativeTargetDir;
+ const QString targetFileName = targetDir + slash + imageFileName;
+ if (QFileInfo::exists(targetFileName))
+ return true;
+ if (!QFileInfo::exists(targetDir)) {
+ const QDir outDir(outputDir);
+ if (!outDir.mkpath(relativeTargetDir)) {
+ QTextStream(errorMessage) << "Cannot create " << QDir::toNativeSeparators(relativeTargetDir)
+ << " under " << QDir::toNativeSeparators(outputDir);
+ return false;
+ }
+ }
+
+ QFile source(imageSource.absoluteFilePath());
+ if (!source.copy(targetFileName)) {
+ QTextStream(errorMessage) << "Cannot copy " << QDir::toNativeSeparators(source.fileName())
+ << " to " << QDir::toNativeSeparators(targetFileName) << ": "
+ << source.errorString();
+ return false;
}
+ qCDebug(lcShiboken()).noquote().nospace() << __FUNCTION__ << " href=\""
+ << href << "\", context=\"" << context << "\", docDataDir=\""
+ << docDataDir << "\", outputDir=\"" << outputDir << "\", copied \""
+ << source.fileName() << "\"->\"" << targetFileName << '"';
+ return true;
+}
+
+bool QtXmlToSphinx::copyImage(const QString &href) const
+{
+ QString errorMessage;
+ const bool result =
+ ::copyImage(href, m_generator->docDataDir(), m_context,
+ m_generator->outputDirectory(), &errorMessage);
+ if (!result)
+ qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
+ return result;
+}
+
+void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() != QXmlStreamReader::StartElement)
+ return;
+ const QString href = reader.attributes().value(QLatin1String("href")).toString();
+ if (copyImage(href))
+ m_output << INDENT << ".. image:: " << href << endl << endl;
+}
+
+void QtXmlToSphinx::handleInlineImageTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() != QXmlStreamReader::StartElement)
+ return;
+ const QString href = reader.attributes().value(QLatin1String("href")).toString();
+ if (!copyImage(href))
+ return;
+ // Handle inline images by substitution references. Insert a unique tag
+ // enclosed by '|' and define it further down. Determine tag from the base
+ //file name with number.
+ QString tag = href;
+ int pos = tag.lastIndexOf(QLatin1Char('/'));
+ if (pos != -1)
+ tag.remove(0, pos + 1);
+ pos = tag.indexOf(QLatin1Char('.'));
+ if (pos != -1)
+ tag.truncate(pos);
+ tag += QString::number(m_inlineImages.size() + 1);
+ m_inlineImages.append(InlineImage{tag, href});
+ m_output << '|' << tag << '|' << ' ';
}
void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
@@ -714,8 +1000,8 @@ void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
QString format = reader.attributes().value(QLatin1String("format")).toString();
m_output << INDENT << ".. raw:: " << format.toLower() << endl << endl;
} else if (token == QXmlStreamReader::Characters) {
- QStringList lst(reader.text().toString().split(QLatin1Char('\n')));
- foreach(QString row, lst)
+ const QVector<QStringRef> lst(reader.text().split(QLatin1Char('\n')));
+ for (const QStringRef &row : lst)
m_output << INDENT << INDENT << row << endl;
} else if (token == QXmlStreamReader::EndElement) {
m_output << endl << endl;
@@ -726,12 +1012,11 @@ void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader)
{
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::StartElement) {
- QString format = reader.attributes().value(QLatin1String("format")).toString();
m_output << INDENT << "::" << endl << endl;
INDENT.indent++;
} else if (token == QXmlStreamReader::Characters) {
- QStringList lst(reader.text().toString().split(QLatin1Char('\n')));
- foreach(QString row, lst)
+ const QVector<QStringRef> lst(reader.text().split(QLatin1Char('\n')));
+ for (const QStringRef &row : lst)
m_output << INDENT << INDENT << row << endl;
} else if (token == QXmlStreamReader::EndElement) {
m_output << endl << endl;
@@ -793,22 +1078,17 @@ void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::Characters) {
QString location = reader.text().toString();
- QString identifier;
location.prepend(m_generator->libSourceDir() + QLatin1Char('/'));
- QString code = readFromLocation(location, identifier);
-
+ QString errorMessage;
+ QString code = readFromLocation(location, QString(), &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShiboken(), "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)));
m_output << INDENT << "::\n\n";
Indentation indentation(INDENT);
- if (code.isEmpty()) {
+ if (code.isEmpty())
m_output << INDENT << "<Code snippet \"" << location << "\" not found>" << endl;
- } else {
- foreach (QString line, code.split(QLatin1Char('\n'))) {
- if (!QString(line).trimmed().isEmpty())
- m_output << INDENT << line;
-
- m_output << endl;
- }
- }
+ else
+ formatCode(m_output, code, INDENT);
m_output << endl;
}
}
@@ -877,13 +1157,14 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
}
// calc width and height of each column and row
- QVector<int> colWidths(table.first().count());
+ const int headerColumnCount = table.constFirst().count();
+ QVector<int> colWidths(headerColumnCount);
QVector<int> rowHeights(table.count());
for (int i = 0, maxI = table.count(); i < maxI; ++i) {
const QtXmlToSphinx::TableRow& row = table[i];
for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) {
- QStringList rowLines = row[j].data.split(QLatin1Char('\n')); // cache this would be a good idea
- foreach (QString str, rowLines)
+ const QVector<QStringRef> rowLines = row[j].data.splitRef(QLatin1Char('\n')); // cache this would be a good idea
+ for (const QStringRef &str : rowLines)
colWidths[j] = std::max(colWidths[j], str.count());
rowHeights[i] = std::max(rowHeights[i], row[j].data.count(QLatin1Char('\n')) + 1);
}
@@ -895,7 +1176,7 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
// create a horizontal line to be used later.
QString horizontalLine = QLatin1String("+");
for (int i = 0, max = colWidths.count(); i < max; ++i) {
- horizontalLine += createRepeatedChar(colWidths[i], '-');
+ horizontalLine += QString(colWidths.at(i), QLatin1Char('-'));
horizontalLine += QLatin1Char('+');
}
@@ -905,7 +1186,7 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
// print line
s << INDENT << '+';
- for (int col = 0, max = colWidths.count(); col < max; ++col) {
+ for (int col = 0; col < headerColumnCount; ++col) {
char c;
if (col >= row.length() || row[col].rowSpan == -1)
c = ' ';
@@ -913,16 +1194,17 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
c = '=';
else
c = '-';
- s << createRepeatedChar(colWidths[col], c) << '+';
+ s << Pad(c, colWidths.at(col)) << '+';
}
s << endl;
// Print the table cells
for (int rowLine = 0; rowLine < rowHeights[i]; ++rowLine) { // for each line in a row
- for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) { // for each column
+ int j = 0;
+ for (int maxJ = std::min(row.count(), headerColumnCount); j < maxJ; ++j) { // for each column
const QtXmlToSphinx::TableCell& cell = row[j];
- QStringList rowLines = cell.data.split(QLatin1Char('\n')); // FIXME: Cache this!!!
+ const QVector<QStringRef> rowLines = cell.data.splitRef(QLatin1Char('\n')); // FIXME: Cache this!!!
if (!j) // First column, so we need print the identation
s << INDENT;
@@ -930,10 +1212,13 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
s << '|';
else
s << ' ';
- s << qSetFieldWidth(colWidths[j]) << left;
- s << (rowLine < rowLines.count() ? rowLines[rowLine] : QString());
- s << qSetFieldWidth(0);
+ if (rowLine < rowLines.count())
+ s << qSetFieldWidth(colWidths[j]) << left << rowLines.at(rowLine) << qSetFieldWidth(0);
+ else
+ s << Pad(' ', colWidths.at(j));
}
+ for ( ; j < headerColumnCount; ++j) // pad
+ s << '|' << Pad(' ', colWidths.at(j));
s << '|' << endl;
}
}
@@ -975,8 +1260,8 @@ static QString getFuncName(const AbstractMetaFunction* cppFunc) {
hashInitialized = true;
}
- QHash<QString, QString>::const_iterator it = operatorsHash.find(cppFunc->name());
- QString result = it != operatorsHash.end() ? it.value() : cppFunc->name();
+ QHash<QString, QString>::const_iterator it = operatorsHash.constFind(cppFunc->name());
+ QString result = it != operatorsHash.cend() ? it.value() : cppFunc->name();
result.replace(QLatin1String("::"), QLatin1String("."));
return result;
}
@@ -1007,7 +1292,8 @@ QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const
}
}
-void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass)
+void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc,
+ const AbstractMetaClass *metaClass)
{
QString metaClassName;
@@ -1018,17 +1304,24 @@ void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc,
QtXmlToSphinx x(this, doc.value(), metaClassName);
s << x;
} else {
- QStringList lines = doc.value().split(QLatin1Char('\n'));
- QRegExp regex(QLatin1String("\\S")); // non-space character
+ const QString &value = doc.value();
+ const QVector<QStringRef> lines = value.splitRef(QLatin1Char('\n'));
int typesystemIndentation = std::numeric_limits<int>().max();
- // check how many spaces must be removed from the begining of each line
- foreach (QString line, lines) {
- int idx = line.indexOf(regex);
- if (idx >= 0)
- typesystemIndentation = qMin(typesystemIndentation, idx);
+ // check how many spaces must be removed from the beginning of each line
+ for (const QStringRef &line : lines) {
+ const auto it = std::find_if(line.cbegin(), line.cend(),
+ [] (QChar c) { return !c.isSpace(); });
+ if (it != line.cend())
+ typesystemIndentation = qMin(typesystemIndentation, int(it - line.cbegin()));
+ }
+ if (typesystemIndentation == std::numeric_limits<int>().max())
+ typesystemIndentation = 0;
+ for (const QStringRef &line : lines) {
+ s << INDENT
+ << (typesystemIndentation > 0 && typesystemIndentation < line.size()
+ ? line.right(line.size() - typesystemIndentation) : line)
+ << endl;
}
- foreach (QString line, lines)
- s << INDENT << line.remove(0, typesystemIndentation) << endl;
}
s << endl;
@@ -1037,7 +1330,7 @@ void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc,
static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaClass, const AbstractMetaClassList& allClasses)
{
AbstractMetaClassList res;
- foreach (AbstractMetaClass* c, allClasses) {
+ for (AbstractMetaClass *c : allClasses) {
if (c != metaClass && c->inheritsFrom(metaClass))
res << c;
}
@@ -1047,7 +1340,7 @@ static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaCl
s << "**Inherited by:** ";
QStringList classes;
- foreach (AbstractMetaClass* c, res)
+ for (AbstractMetaClass *c : qAsConst(res))
classes << QLatin1String(":ref:`") + getClassTargetFullName(c, false) + QLatin1Char('`');
s << classes.join(QLatin1String(", ")) << endl << endl;
}
@@ -1067,9 +1360,9 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex
s << ".. _" << className << ":" << endl << endl;
s << className << endl;
- s << createRepeatedChar(className.count(), '*') << endl << endl;
+ s << Pad('*', className.count()) << endl << endl;
- s << ".. inheritance-diagram:: " << className << endl
+ s << ".. inheritance-diagram:: " << getClassTargetFullName(metaClass, true) << endl
<< " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future...
@@ -1084,12 +1377,13 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex
AbstractMetaFunctionList functionList = metaClass->functions();
qSort(functionList.begin(), functionList.end(), functionSort);
- s << "Detailed Description\n"
- "--------------------\n\n";
+ s << endl
+ << "Detailed Description\n"
+ "--------------------\n\n";
writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, 0);
if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, 0))
- writeFormatedText(s, metaClass->documentation(), metaClass);
+ writeFormattedText(s, metaClass->documentation(), metaClass);
if (!metaClass->isNamespace())
writeConstructors(s, metaClass);
@@ -1098,7 +1392,7 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex
writeFields(s, metaClass);
- foreach (AbstractMetaFunction* func, functionList) {
+ for (AbstractMetaFunction *func : qAsConst(functionList)) {
if (shouldSkip(func))
continue;
@@ -1121,7 +1415,8 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
QStringList slotList;
QStringList staticFunctionList;
- foreach (AbstractMetaFunction* func, cppClass->functions()) {
+ const AbstractMetaFunctionList &classFunctions = cppClass->functions();
+ for (AbstractMetaFunction *func : classFunctions) {
if (shouldSkip(func))
continue;
@@ -1157,9 +1452,9 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) {
QtXmlToSphinx::Table functionTable;
- QtXmlToSphinx::TableRow row;
- s << "Synopsis" << endl
+ s << endl
+ << "Synopsis" << endl
<< "--------" << endl << endl;
writeFunctionBlock(s, QLatin1String("Functions"), functionList);
@@ -1180,8 +1475,8 @@ void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QS
s << ".. container:: function_list" << endl << endl;
Indentation indentation(INDENT);
- foreach (QString func, functions)
- s << '*' << INDENT << func << endl;
+ for (const QString &func : qAsConst(functions))
+ s << INDENT << '*' << ' ' << func << endl;
s << endl << endl;
}
@@ -1191,9 +1486,10 @@ void QtDocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClas
{
static const QString section_title = QLatin1String(".. attribute:: ");
- foreach (AbstractMetaEnum* en, cppClass->enums()) {
+ const AbstractMetaEnumList &enums = cppClass->enums();
+ for (AbstractMetaEnum *en : enums) {
s << section_title << getClassTargetFullName(cppClass) << '.' << en->name() << endl << endl;
- writeFormatedText(s, en->documentation(), cppClass);
+ writeFormattedText(s, en->documentation(), cppClass);
if (en->typeEntry() && (en->typeEntry()->version() != 0))
s << ".. note:: This enum was introduced or modified in Qt " << en->typeEntry()->version() << endl;
@@ -1205,10 +1501,11 @@ void QtDocGenerator::writeFields(QTextStream& s, const AbstractMetaClass* cppCla
{
static const QString section_title = QLatin1String(".. attribute:: ");
- foreach (AbstractMetaField* field, cppClass->fields()) {
+ const AbstractMetaFieldList &fields = cppClass->fields();
+ for (AbstractMetaField *field : fields) {
s << section_title << getClassTargetFullName(cppClass) << "." << field->name() << endl << endl;
//TODO: request for member ‘documentation’ is ambiguous
- writeFormatedText(s, field->AbstractMetaAttributes::documentation(), cppClass);
+ writeFormattedText(s, field->AbstractMetaAttributes::documentation(), cppClass);
}
}
@@ -1218,14 +1515,15 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass*
static const QString sectionTitleSpace = QString(sectionTitle.size(), QLatin1Char(' '));
AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible);
+ for (int i = lst.size() - 1; i >= 0; --i) {
+ if (lst.at(i)->isModifiedRemoved() || lst.at(i)->functionType() == AbstractMetaFunction::MoveConstructorFunction)
+ lst.removeAt(i);
+ }
bool first = true;
QHash<QString, AbstractMetaArgument*> arg_map;
- foreach(AbstractMetaFunction* func, lst) {
- if (func->isModifiedRemoved())
- continue;
-
+ for (AbstractMetaFunction *func : qAsConst(lst)) {
if (first) {
first = false;
s << sectionTitle;
@@ -1233,8 +1531,8 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass*
s << sectionTitleSpace;
}
writeFunction(s, false, cppClass, func);
- foreach(AbstractMetaArgument* arg, func->arguments())
- {
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
if (!arg_map.contains(arg->name())) {
arg_map.insert(arg->name(), arg);
}
@@ -1243,16 +1541,15 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass*
s << endl;
- foreach (AbstractMetaArgument* arg, arg_map.values()) {
+ for (QHash<QString, AbstractMetaArgument*>::const_iterator it = arg_map.cbegin(), end = arg_map.cend(); it != end; ++it) {
Indentation indentation(INDENT);
- writeParamerteType(s, cppClass, arg);
+ writeParameterType(s, cppClass, it.value());
}
s << endl;
- foreach (AbstractMetaFunction* func, lst) {
- writeFormatedText(s, func->documentation(), cppClass);
- }
+ for (AbstractMetaFunction *func : qAsConst(lst))
+ writeFormattedText(s, func->documentation(), cppClass);
}
QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
@@ -1260,7 +1557,8 @@ QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, cons
QString ret;
int optArgs = 0;
- foreach (AbstractMetaArgument* arg, func->arguments()) {
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
if (func->argumentRemoved(arg->argumentIndex() + 1))
continue;
@@ -1311,7 +1609,7 @@ void QtDocGenerator::writeDocSnips(QTextStream &s,
invalidStrings << QLatin1String("*") << QLatin1String("//") << QLatin1String("/*") << QLatin1String("*/");
- foreach (CodeSnip snip, codeSnips) {
+ for (const CodeSnip &snip : codeSnips) {
if ((snip.position != position) ||
!(snip.language & language))
continue;
@@ -1325,14 +1623,13 @@ void QtDocGenerator::writeDocSnips(QTextStream &s,
break;
QString codeBlock = code.mid(startBlock, endBlock - startBlock);
- QStringList rows = codeBlock.split(QLatin1Char('\n'));
+ const QStringList rows = codeBlock.split(QLatin1Char('\n'));
int currenRow = 0;
int offset = 0;
- foreach(QString row, rows) {
- foreach(QString invalidString, invalidStrings) {
- row = row.remove(invalidString);
- }
+ for (QString row : rows) {
+ for (const QString &invalidString : qAsConst(invalidStrings))
+ row.remove(invalidString);
if (row.trimmed().size() == 0) {
if (currenRow == 0)
@@ -1370,7 +1667,8 @@ bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
Indentation indentation(INDENT);
bool didSomething = false;
- foreach (DocModification mod, cppClass->typeEntry()->docModifications()) {
+ const DocModificationList &mods = cppClass->typeEntry()->docModifications();
+ for (const DocModification &mod : mods) {
if (mod.mode() == mode) {
bool modOk = func ? mod.signature() == func->minimalSignature() : mod.signature().isEmpty();
@@ -1378,15 +1676,15 @@ bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
Documentation doc;
Documentation::Format fmt;
- if (mod.format == TypeSystem::NativeCode)
+ if (mod.format() == TypeSystem::NativeCode)
fmt = Documentation::Native;
- else if (mod.format == TypeSystem::TargetLangCode)
+ else if (mod.format() == TypeSystem::TargetLangCode)
fmt = Documentation::Target;
else
continue;
doc.setValue(mod.code() , fmt);
- writeFormatedText(s, doc, cppClass);
+ writeFormattedText(s, doc, cppClass);
didSomething = true;
}
}
@@ -1462,31 +1760,34 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, cons
return strType;
}
-void QtDocGenerator::writeParamerteType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaArgument* arg)
+void QtDocGenerator::writeParameterType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaArgument* arg)
{
s << INDENT << ":param " << arg->name() << ": "
<< translateToPythonType(arg->type(), cppClass) << endl;
}
-void QtDocGenerator::writeFunctionParametersType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+void QtDocGenerator::writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass,
+ const AbstractMetaFunction *func)
{
Indentation indentation(INDENT);
s << endl;
- foreach (AbstractMetaArgument* arg, func->arguments()) {
+ const AbstractMetaArgumentList &funcArgs = func->arguments();
+ for (AbstractMetaArgument *arg : funcArgs) {
if (func->argumentRemoved(arg->argumentIndex() + 1))
continue;
- writeParamerteType(s, cppClass, arg);
+ writeParameterType(s, cppClass, arg);
}
if (!func->isConstructor() && func->type()) {
QString retType;
// check if the return type was modified
- foreach (FunctionModification mod, func->modifications()) {
- foreach (ArgumentModification argMod, mod.argument_mods) {
+ const FunctionModificationList &mods = func->modifications();
+ for (const FunctionModification &mod : mods) {
+ for (const ArgumentModification &argMod : mod.argument_mods) {
if (argMod.index == 0) {
retType = argMod.modified_type;
break;
@@ -1515,7 +1816,7 @@ void QtDocGenerator::writeFunction(QTextStream& s, bool writeDoc, const Abstract
s << endl;
writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func);
if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func))
- writeFormatedText(s, func->documentation(), cppClass);
+ writeFormattedText(s, func->documentation(), cppClass);
writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func);
}
}
@@ -1526,7 +1827,7 @@ static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4
TocMap tocMap;
QChar Q = QLatin1Char('Q');
QChar idx;
- foreach (QString item, items) {
+ for (QString item : items) {
if (item.isEmpty())
continue;
if (item.startsWith(Q) && item.length() > 1)
@@ -1551,7 +1852,7 @@ static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4
ss << "**" << it.key() << "**" << endl << endl;
i += 2; // a letter title is equivalent to two entries in space
- foreach (QString item, it.value()) {
+ for (const QString &item : qAsConst(it.value())) {
ss << "* :doc:`" << item << "`" << endl;
++i;
@@ -1595,7 +1896,7 @@ bool QtDocGenerator::finishGeneration()
QString title = it.key();
s << title << endl;
- s << createRepeatedChar(title.length(), '*') << endl << endl;
+ s << Pad('*', title.length()) << endl << endl;
/* Avoid showing "Detailed Description for *every* class in toc tree */
Indentation indentation(INDENT);
@@ -1628,7 +1929,7 @@ bool QtDocGenerator::finishGeneration()
s << INDENT << ".. toctree::" << endl;
Indentation deeperIndentation(INDENT);
s << INDENT << ":maxdepth: 1" << endl << endl;
- foreach (QString className, it.value())
+ for (const QString &className : qAsConst(it.value()))
s << INDENT << className << endl;
s << endl << endl;
}
@@ -1686,19 +1987,18 @@ bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
}
-QMap<QString, QString> QtDocGenerator::options() const
+Generator::OptionDescriptions QtDocGenerator::options() const
{
- QMap<QString, QString> options;
- options.insert(QLatin1String("doc-parser"),
- QLatin1String("The documentation parser used to interpret the documentation input files (qdoc3|doxygen)"));
- options.insert(QLatin1String("library-source-dir"),
- QLatin1String("Directory where library source code is located"));
- options.insert(QLatin1String("documentation-data-dir"),
- QLatin1String("Directory with XML files generated by documentation tool (qdoc3 or Doxygen)"));
- options.insert(QLatin1String("documentation-code-snippets-dir"),
- QLatin1String("Directory used to search code snippets used by the documentation"));
- options.insert(QLatin1String("documentation-extra-sections-dir"),
- QLatin1String("Directory used to search for extra documentation sections"));
- return options;
+ return OptionDescriptions()
+ << qMakePair(QLatin1String("doc-parser"),
+ QLatin1String("The documentation parser used to interpret the documentation input files (qdoc3|doxygen)"))
+ << qMakePair(QLatin1String("documentation-code-snippets-dir"),
+ QLatin1String("Directory used to search code snippets used by the documentation"))
+ << qMakePair(QLatin1String("documentation-data-dir"),
+ QLatin1String("Directory with XML files generated by documentation tool (qdoc3 or Doxygen)"))
+ << qMakePair(QLatin1String("documentation-extra-sections-dir"),
+ QLatin1String("Directory used to search for extra documentation sections"))
+ << qMakePair(QLatin1String("library-source-dir"),
+ QLatin1String("Directory where library source code is located"));
}