diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/qtdocparser.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/qtdocparser.cpp | 197 |
1 files changed, 135 insertions, 62 deletions
diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.cpp b/sources/shiboken6/ApiExtractor/qtdocparser.cpp index b20a53632..5bd99bbd8 100644 --- a/sources/shiboken6/ApiExtractor/qtdocparser.cpp +++ b/sources/shiboken6/ApiExtractor/qtdocparser.cpp @@ -3,10 +3,11 @@ #include "qtdocparser.h" #include "classdocumentation.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" -#include "abstractmetafield.h" #include "abstractmetafunction.h" #include "abstractmetalang.h" +#include "abstractmetatype.h" #include "documentation.h" #include "modifications.h" #include "messages.h" @@ -14,6 +15,8 @@ #include "reporthandler.h" #include "flagstypeentry.h" #include "complextypeentry.h" +#include "functiontypeentry.h" +#include "enumtypeentry.h" #include "qtcompat.h" @@ -25,8 +28,9 @@ using namespace Qt::StringLiterals; enum { debugFunctionSearch = 0 }; -static inline QString briefStartElement() { return QStringLiteral("<brief>"); } -static inline QString briefEndElement() { return QStringLiteral("</brief>"); } +constexpr auto briefStartElement = "<brief>"_L1; +constexpr auto briefEndElement = "</brief>"_L1; +constexpr auto webxmlSuffix = ".webxml"_L1; Documentation QtDocParser::retrieveModuleDocumentation() { @@ -56,7 +60,7 @@ static void formatFunctionUnqualifiedArgTypeQuery(QTextStream &str, case AbstractMetaType::FlagsPattern: { // Modify qualified name "QFlags<Qt::AlignmentFlag>" with name "Alignment" // to "Qt::Alignment" as seen by qdoc. - const auto *flagsEntry = static_cast<const FlagsTypeEntry *>(metaType.typeEntry()); + const auto flagsEntry = std::static_pointer_cast<const FlagsTypeEntry>(metaType.typeEntry()); QString name = flagsEntry->qualifiedCppName(); if (name.endsWith(u'>') && name.startsWith(u"QFlags<")) { const int lastColon = name.lastIndexOf(u':'); @@ -73,7 +77,7 @@ static void formatFunctionUnqualifiedArgTypeQuery(QTextStream &str, case AbstractMetaType::ContainerPattern: { // QVector<int> str << metaType.typeEntry()->qualifiedCppName() << '<'; const auto instantiations = metaType.instantiations(); - for (int i = 0, size = instantiations.size(); i < size; ++i) { + for (qsizetype i = 0, size = instantiations.size(); i < size; ++i) { if (i) str << ", "; const auto &instantiation = instantiations.at(i); @@ -99,51 +103,34 @@ static QString formatFunctionArgTypeQuery(const AbstractMetaType &metaType) return result; } -QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName, - const ClassDocumentation &classDocumentation, - const AbstractMetaClass* metaClass, - const AbstractMetaFunctionCPtr &func, - const DocModificationList &signedModifs, - QString *errorMessage) +QString QtDocParser::functionDocumentation(const QString &sourceFileName, + const ClassDocumentation &classDocumentation, + const AbstractMetaClassCPtr &metaClass, + const AbstractMetaFunctionCPtr &func, + QString *errorMessage) { errorMessage->clear(); - DocModificationList funcModifs; - for (const DocModification &funcModif : signedModifs) { - if (funcModif.signature() == func->minimalSignature()) - funcModifs.append(funcModif); - } - const QString docString = queryFunctionDocumentation(sourceFileName, classDocumentation, metaClass, func, errorMessage); + const auto funcModifs = DocParser::getXpathDocModifications(func, metaClass); return docString.isEmpty() || funcModifs.isEmpty() ? docString : applyDocModifications(funcModifs, docString); } QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName, const ClassDocumentation &classDocumentation, - const AbstractMetaClass* metaClass, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaFunctionCPtr &func, QString *errorMessage) { - // Properties - if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) { - const QPropertySpec &prop = metaClass->propertySpecs().at(func->propertySpecIndex()); - const auto index = classDocumentation.indexOfProperty(prop.name()); - if (index == -1) { - *errorMessage = msgCannotFindDocumentation(sourceFileName, func.data()); - return {}; - } - return classDocumentation.properties.at(index).description; - } - // Search candidates by name and const-ness FunctionDocumentationList candidates = classDocumentation.findFunctionCandidates(func->name(), func->isConstant()); if (candidates.isEmpty()) { - *errorMessage = msgCannotFindDocumentation(sourceFileName, func.data()) + *errorMessage = msgCannotFindDocumentation(sourceFileName, func.get()) + u" (no matches)"_s; return {}; } @@ -188,13 +175,13 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName, candidates.erase(pend, candidates.end()); if (candidates.size() == 1) { const auto &match = candidates.constFirst(); - QTextStream(errorMessage) << msgFallbackForDocumentation(sourceFileName, func.data()) + QTextStream(errorMessage) << msgFallbackForDocumentation(sourceFileName, func.get()) << "\n Falling back to \"" << match.signature << "\" obtained by matching the argument count only."; return candidates.constFirst().description; } - QTextStream(errorMessage) << msgCannotFindDocumentation(sourceFileName, func.data()) + QTextStream(errorMessage) << msgCannotFindDocumentation(sourceFileName, func.get()) << " (" << candidates.size() << " candidates matching the argument count)"; return {}; } @@ -203,29 +190,100 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName, // from the source. static QString extractBrief(QString *value) { - const auto briefStart = value->indexOf(briefStartElement()); + const auto briefStart = value->indexOf(briefStartElement); if (briefStart < 0) return {}; - const auto briefEnd = value->indexOf(briefEndElement(), - briefStart + briefStartElement().size()); + const auto briefEnd = value->indexOf(briefEndElement, + briefStart + briefStartElement.size()); if (briefEnd < briefStart) return {}; - const auto briefLength = briefEnd + briefEndElement().size() - briefStart; + const auto briefLength = briefEnd + briefEndElement.size() - briefStart; QString briefValue = value->mid(briefStart, briefLength); - briefValue.insert(briefValue.size() - briefEndElement().size(), + briefValue.insert(briefValue.size() - briefEndElement.size(), u"<rst> More_...</rst>"_s); value->remove(briefStart, briefLength); return briefValue; } -void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) +// Find the webxml file for global functions/enums +// by the doc-file typesystem attribute or via include file. +static QString findGlobalWebXmLFile(const QString &documentationDataDirectory, + const QString &docFile, + const Include &include) +{ + QString result; + if (!docFile.isEmpty()) { + result = documentationDataDirectory + u'/' + docFile; + if (!result.endsWith(webxmlSuffix)) + result += webxmlSuffix; + return QFileInfo::exists(result) ? result : QString{}; + } + if (include.name().isEmpty()) + return {}; + // qdoc "\headerfile <QtLogging>" directive produces "qtlogging.webxml" + result = documentationDataDirectory + u'/' + + QFileInfo(include.name()).baseName() + webxmlSuffix; + if (QFileInfo::exists(result)) + return result; + // qdoc "\headerfile <qdrawutil.h>" produces "qdrawutil-h.webxml" + result.insert(result.size() - webxmlSuffix.size(), "-h"_L1); + return QFileInfo::exists(result) ? result : QString{}; +} + +void QtDocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f) +{ + auto te = f->typeEntry(); + if (te == nullptr) + return; + + const QString sourceFileName = + findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include()); + if (sourceFileName.isEmpty()) + return; + + QString errorMessage; + auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + if (!classDocumentationO.has_value()) { + qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + return; + } + const QString detailed = + functionDocumentation(sourceFileName, classDocumentationO.value(), + {}, f, &errorMessage); + if (!errorMessage.isEmpty()) + qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + const Documentation documentation(detailed, {}); + f->setDocumentation(documentation); +} + +void QtDocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &e) +{ + auto te = e.typeEntry(); + const QString sourceFileName = + findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include()); + if (sourceFileName.isEmpty()) + return; + + QString errorMessage; + auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + if (!classDocumentationO.has_value()) { + qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + return; + } + if (!extractEnumDocumentation(classDocumentationO.value(), e)) { + qCWarning(lcShibokenDoc, "%s", + qPrintable(msgCannotFindDocumentation(sourceFileName, {}, e, {}))); + } +} + +void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass) { if (!metaClass) return; - const AbstractMetaClass* context = metaClass->enclosingClass(); - while(context) { - if (context->enclosingClass() == nullptr) + auto context = metaClass->enclosingClass(); + while (context) { + if (!context->enclosingClass()) break; context = context->enclosingClass(); } @@ -234,9 +292,9 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) + metaClass->qualifiedCppName().toLower(); sourceFileRoot.replace(u"::"_s, u"-"_s); - QFileInfo sourceFile(sourceFileRoot + QStringLiteral(".webxml")); + QFileInfo sourceFile(sourceFileRoot + webxmlSuffix); if (!sourceFile.exists()) - sourceFile.setFile(sourceFileRoot + QStringLiteral(".xml")); + sourceFile.setFile(sourceFileRoot + ".xml"_L1); if (!sourceFile.exists()) { qCWarning(lcShibokenDoc).noquote().nospace() << "Can't find qdoc file for class " << metaClass->name() << ", tried: " @@ -247,22 +305,20 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) const QString sourceFileName = sourceFile.absoluteFilePath(); QString errorMessage; - ClassDocumentation classDocumentation = parseWebXml(sourceFileName, &errorMessage); - if (!classDocumentation) { + const auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + if (!classDocumentationO.has_value()) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return; } - DocModificationList signedModifs, classModifs; - const DocModificationList &mods = metaClass->typeEntry()->docModifications(); - for (const DocModification &docModif : mods) { - if (docModif.signature().isEmpty()) - classModifs.append(docModif); - else - signedModifs.append(docModif); + const auto &classDocumentation = classDocumentationO.value(); + for (const auto &p : classDocumentation.properties) { + Documentation doc(p.description, p.brief); + metaClass->setPropertyDocumentation(p.name, doc); } - QString docString = applyDocModifications(mods, classDocumentation.description); + QString docString = applyDocModifications(DocParser::getXpathDocModifications(metaClass), + classDocumentation.description); if (docString.isEmpty()) { QString className = metaClass->name(); @@ -281,12 +337,12 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) const auto &funcs = DocParser::documentableFunctions(metaClass); for (const auto &func : funcs) { const QString detailed = - queryFunctionDocumentation(sourceFileName, classDocumentation, - metaClass, func, signedModifs, &errorMessage); + functionDocumentation(sourceFileName, classDocumentation, + metaClass, func, &errorMessage); if (!errorMessage.isEmpty()) qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); const Documentation documentation(detailed, {}); - qSharedPointerConstCast<AbstractMetaFunction>(func)->setDocumentation(documentation); + std::const_pointer_cast<AbstractMetaFunction>(func)->setDocumentation(documentation); } #if 0 // Fields @@ -302,18 +358,35 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) #endif // Enums for (AbstractMetaEnum &meta_enum : metaClass->enums()) { - Documentation enumDoc; - const auto index = classDocumentation.indexOfEnum(meta_enum.name()); - if (index != -1) { - enumDoc.setValue(classDocumentation.enums.at(index).description); - meta_enum.setDocumentation(enumDoc); - } else { + if (!extractEnumDocumentation(classDocumentation, meta_enum)) { qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindDocumentation(sourceFileName, metaClass, meta_enum, {}))); } } } +bool QtDocParser::extractEnumDocumentation(const ClassDocumentation &classDocumentation, + AbstractMetaEnum &meta_enum) +{ + Documentation enumDoc; + const auto index = classDocumentation.indexOfEnum(meta_enum.name()); + if (index == -1) + return false; + QString doc = classDocumentation.enums.at(index).description; + const auto firstPara = doc.indexOf(u"<para>"); + if (firstPara != -1) { + const QString baseClass = QtDocParser::enumBaseClass(meta_enum); + if (baseClass != "Enum"_L1) { + const QString note = "(inherits <teletype>enum."_L1 + baseClass + + "</teletype>) "_L1; + doc.insert(firstPara + 6, note); + } + } + enumDoc.setValue(doc); + meta_enum.setDocumentation(enumDoc); + return true; +} + static QString qmlReferenceLink(const QFileInfo &qmlModuleFi) { QString result; |