diff options
Diffstat (limited to 'sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp')
-rw-r--r-- | sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp | 467 |
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")); } |