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.cpp467
1 files changed, 321 insertions, 146 deletions
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index a7a176907..adcdfad35 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>
@@ -55,7 +56,8 @@ static bool shouldSkip(const AbstractMetaFunction* func)
// Search a const clone
if (!skipable && !func->isConstant()) {
const AbstractMetaArgumentList funcArgs = func->arguments();
- foreach (AbstractMetaFunction* f, func->ownerClass()->functions()) {
+ const AbstractMetaFunctionList &ownerFunctions = func->ownerClass()->functions();
+ for (AbstractMetaFunction *f : ownerFunctions) {
if (f != func
&& f->isConstant()
&& f->name() == func->name()
@@ -83,13 +85,26 @@ static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFu
return func1->name() < func2->name();
}
-static QString createRepeatedChar(int i, char c)
+class Pad
{
- QString out;
- for (int j = 0; j < i; ++j)
- out += QLatin1Char(c);
+public:
+ explicit Pad(char c, int count) : m_char(c), m_count(count) {}
- return out;
+ 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)
+{
+ pad.write(str);
+ return str;
}
static QString escape(QString str)
@@ -105,6 +120,33 @@ static QString escape(const QStringRef& strref)
return escape(str);
}
+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)
@@ -202,7 +244,8 @@ QString QtXmlToSphinx::expandFunction(const QString& function)
QStringList functionSpec = function.split(QLatin1Char('.'));
QString className = functionSpec.first();
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() == className) {
metaClass = cls;
break;
@@ -224,7 +267,8 @@ QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName)
QString currentClass = m_context.split(QLatin1Char('.')).last();
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 +277,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;
@@ -296,68 +341,78 @@ QString QtXmlToSphinx::transform(const QString& doc)
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
+ }
+
+ QString code = QLatin1String(""); // non-null
+ if (identifier.isEmpty()) {
+ while (!inputFile.atEnd())
+ code += QString::fromUtf8(inputFile.readLine());
+ return code;
}
- QRegExp searchString(QLatin1String("//!\\s*\\[") + identifier + QLatin1String("\\]"));
- QRegExp codeSnippetCode(QLatin1String("//!\\s*\\[[\\w\\d\\s]+\\]"));
- QString 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;
}
@@ -368,13 +423,13 @@ void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
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")).toString().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, heading.length()) << endl << endl;
} else if (token == QXmlStreamReader::Characters) {
heading = escape(reader.text()).trimmed();
m_output << endl << endl << heading << endl;
@@ -446,6 +501,40 @@ void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
m_output << endl;
}
+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)
{
QXmlStreamReader::TokenType token = reader.tokenType();
@@ -458,21 +547,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;
}
}
@@ -577,7 +683,7 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
if (!m_currentTable.isEmpty()) {
if (listType == QLatin1String("bullet")) {
m_output << endl;
- foreach (TableCell cell, m_currentTable.first()) {
+ for (const TableCell &cell : m_currentTable.constFirst()) {
QStringList itemLines = cell.data.split(QLatin1Char('\n'));
m_output << INDENT << "* " << itemLines.first() << endl;
for (int i = 1, max = itemLines.count(); i < max; ++i)
@@ -689,21 +795,75 @@ void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
}
}
+// 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;
+}
+
void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
{
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;
+ QString errorMessage;
+ if (!copyImage(href,m_generator->docDataDir(), m_context,
+ m_generator->outputDirectory(), &errorMessage)) {
+ qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
+ }
if (reader.name() == QLatin1String("image"))
- m_output << INDENT << ".. image:: " << imgPath << endl << endl;
+ m_output << INDENT << ".. image:: " << href << endl << endl;
else
- m_output << ".. image:: " << imgPath << ' ';
+ m_output << ".. image:: " << href << ' ';
}
}
@@ -714,8 +874,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 QStringList lst(reader.text().toString().split(QLatin1Char('\n')));
+ for (const QString &row : lst)
m_output << INDENT << INDENT << row << endl;
} else if (token == QXmlStreamReader::EndElement) {
m_output << endl << endl;
@@ -726,12 +886,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 QStringList lst(reader.text().toString().split(QLatin1Char('\n')));
+ for (const QString &row : lst)
m_output << INDENT << INDENT << row << endl;
} else if (token == QXmlStreamReader::EndElement) {
m_output << endl << endl;
@@ -795,14 +954,17 @@ void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
QString location = reader.text().toString();
QString identifier;
location.prepend(m_generator->libSourceDir() + QLatin1Char('/'));
- QString code = readFromLocation(location, identifier);
-
+ QString errorMessage;
+ QString code = readFromLocation(location, identifier, &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()) {
m_output << INDENT << "<Code snippet \"" << location << "\" not found>" << endl;
} else {
- foreach (QString line, code.split(QLatin1Char('\n'))) {
+ const QStringList lines = code.split(QLatin1Char('\n'));
+ for (const QString &line : lines) {
if (!QString(line).trimmed().isEmpty())
m_output << INDENT << line;
@@ -882,8 +1044,8 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
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 QStringList rowLines = row[j].data.split(QLatin1Char('\n')); // cache this would be a good idea
+ for (const QString &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 +1057,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('+');
}
@@ -913,7 +1075,7 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
c = '=';
else
c = '-';
- s << createRepeatedChar(colWidths[col], c) << '+';
+ s << Pad(c, colWidths.at(col)) << '+';
}
s << endl;
@@ -975,8 +1137,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 +1169,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 +1181,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 +1207,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 +1217,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,7 +1237,7 @@ 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
<< " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future...
@@ -1089,7 +1259,7 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex
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 +1268,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 +1291,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,7 +1328,6 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) {
QtXmlToSphinx::Table functionTable;
- QtXmlToSphinx::TableRow row;
s << "Synopsis" << endl
<< "--------" << endl << endl;
@@ -1180,7 +1350,7 @@ void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QS
s << ".. container:: function_list" << endl << endl;
Indentation indentation(INDENT);
- foreach (QString func, functions)
+ for (const QString &func : qAsConst(functions))
s << '*' << INDENT << func << endl;
s << endl << endl;
@@ -1191,9 +1361,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 +1376,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 +1390,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 +1406,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 +1416,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 +1432,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 +1484,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 +1498,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 +1542,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 +1551,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 +1635,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 +1691,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 +1702,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 +1727,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 +1771,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 +1804,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 +1862,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"));
}