aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2018-05-17 13:43:00 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2018-05-18 13:12:45 +0000
commitdf1a619d65d8e5db91f3c8db46b00872b461e334 (patch)
tree3c36fe602b70c88cb3401d2470b79728ad337dde /sources
parent6989d6040fb58d62ba4a56983d41d7b065ad4a18 (diff)
Documentation: Improve function documentation extraction
The XQuery used to obtain the function description can fail due to argument type mismatches (typedefs or blank formatting). In that case, repeat the query restricting the search the argument count. If exactly one match is found, use that with a warning. Output the matches otherwise. Split out functions for the function queries and and helper function for creating the XQuery with flags. Task-number: PYSIDE-363 Change-Id: I83aaa53511896ee78a25f39a769ca907d0ac10bb Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'sources')
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.cpp6
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.cpp153
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.h9
3 files changed, 134 insertions, 34 deletions
diff --git a/sources/shiboken2/ApiExtractor/docparser.cpp b/sources/shiboken2/ApiExtractor/docparser.cpp
index d59411fe6..9305332ba 100644
--- a/sources/shiboken2/ApiExtractor/docparser.cpp
+++ b/sources/shiboken2/ApiExtractor/docparser.cpp
@@ -125,9 +125,9 @@ QString DocParser::msgCannotFindDocumentation(const QString &fileName,
const AbstractMetaFunction *function,
const QString &query)
{
- return msgCannotFindDocumentation(fileName, "function",
- metaClass->name() + QLatin1String("::") + function->name() + QLatin1String("()"),
- query);
+ const QString name = metaClass->name() + QLatin1String("::")
+ + function->minimalSignature();
+ return msgCannotFindDocumentation(fileName, "function", name, query);
}
QString DocParser::msgCannotFindDocumentation(const QString &fileName,
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
index b312c3d30..b0058d6ea 100644
--- a/sources/shiboken2/ApiExtractor/qtdocparser.cpp
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
@@ -35,6 +35,8 @@
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QXmlStreamReader>
#include <QUrl>
Documentation QtDocParser::retrieveModuleDocumentation()
@@ -89,6 +91,119 @@ static void formatFunctionArgTypeQuery(QTextStream &str, const AbstractMetaArgum
str << ' ' << QByteArray(metaType->indirections(), '*');
}
+enum FunctionMatchFlags
+{
+ MatchArgumentCount = 0x1,
+ MatchArgumentType = 0x2,
+ DescriptionOnly = 0x4
+};
+
+static QString functionXQuery(const QString &classQuery,
+ const AbstractMetaFunction *func,
+ unsigned matchFlags = MatchArgumentCount | MatchArgumentType
+ | DescriptionOnly)
+{
+ QString result;
+ QTextStream str(&result);
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ str << classQuery << "/function[@name=\"" << func->originalName()
+ << "\" and @const=\"" << (func->isConstant() ? "true" : "false") << '"';
+ if (matchFlags & MatchArgumentCount)
+ str << " and count(parameter)=" << arguments.size();
+ str << ']';
+ if (!arguments.isEmpty() && (matchFlags & MatchArgumentType)) {
+ for (int i = 0, size = arguments.size(); i < size; ++i) {
+ str << "/parameter[" << (i + 1) << "][@type=\"";
+ // Fixme: Use arguments.at(i)->type()->originalTypeDescription()
+ // instead to get unresolved typedefs?
+ formatFunctionArgTypeQuery(str, arguments.at(i));
+ str << "\"]/..";
+ }
+ }
+ if (matchFlags & DescriptionOnly)
+ str << "/description";
+ return result;
+}
+
+static QStringList signaturesFromWebXml(QString w)
+{
+ QStringList result;
+ if (w.isEmpty())
+ return result;
+ w.prepend(QLatin1String("<root>")); // Fake root element
+ w.append(QLatin1String("</root>"));
+ QXmlStreamReader reader(w);
+ while (!reader.atEnd()) {
+ if (reader.readNext() == QXmlStreamReader::StartElement
+ && reader.name() == QLatin1String("function")) {
+ result.append(reader.attributes().value(QStringLiteral("signature")).toString());
+ }
+ }
+ return result;
+}
+
+static QString msgArgumentCountMatch(const AbstractMetaFunction *func,
+ const QStringList &matches)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "\n Note: Querying for the argument count=="
+ << func->arguments().size() << " only yields " << matches.size()
+ << " matches";
+ if (!matches.isEmpty())
+ str << ": \"" << matches.join(QLatin1String("\", \"")) << '"';
+ return result;
+}
+
+QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName,
+ const AbstractMetaClass* metaClass,
+ const QString &classQuery,
+ const AbstractMetaFunction *func,
+ const DocModificationList &signedModifs,
+ QXmlQuery &xquery,
+ QString *errorMessage)
+{
+ DocModificationList funcModifs;
+ for (const DocModification &funcModif : signedModifs) {
+ if (funcModif.signature() == func->minimalSignature())
+ funcModifs.append(funcModif);
+ }
+
+ // Properties
+ if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) {
+ const QString propertyQuery = classQuery + QLatin1String("/property[@name=\"")
+ + func->propertySpec()->name() + QLatin1String("\"]/description");
+ const QString properyDocumentation = getDocumentation(xquery, propertyQuery, funcModifs);
+ if (properyDocumentation.isEmpty())
+ *errorMessage = msgCannotFindDocumentation(sourceFileName, metaClass, func, propertyQuery);
+ return properyDocumentation;
+ }
+
+ // Query with full match of argument types
+ const QString fullQuery = functionXQuery(classQuery, func);
+ const QString result = getDocumentation(xquery, fullQuery, funcModifs);
+ if (!result.isEmpty())
+ return result;
+ *errorMessage = msgCannotFindDocumentation(sourceFileName, metaClass, func, fullQuery);
+ if (func->arguments().isEmpty()) // No arguments, can't be helped
+ return result;
+ // Test whether some mismatch in argument types occurred by checking for
+ // the argument count only. Include the outer <function> element.
+ QString countOnlyQuery = functionXQuery(classQuery, func, MatchArgumentCount);
+ QStringList signatures =
+ signaturesFromWebXml(getDocumentation(xquery, countOnlyQuery, funcModifs));
+ if (signatures.size() == 1) {
+ // One match was found. Repeat the query restricted to the <description>
+ // element and use the result with a warning.
+ countOnlyQuery = functionXQuery(classQuery, func, MatchArgumentCount | DescriptionOnly);
+ errorMessage->append(QLatin1String("\n Falling back to \"") + signatures.constFirst()
+ + QLatin1String("\" obtained by matching the argument count only."));
+ return getDocumentation(xquery, countOnlyQuery, funcModifs);
+ }
+ *errorMessage += msgArgumentCountMatch(func, signatures);
+ return result;
+}
+
void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
{
if (!metaClass)
@@ -141,40 +256,16 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
qCWarning(lcShiboken(), "%s", qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query)));
metaClass->setDocumentation(doc);
-
//Functions Documentation
+ QString errorMessage;
const AbstractMetaFunctionList &funcs = DocParser::documentableFunctions(metaClass);
for (AbstractMetaFunction *func : funcs) {
- query.clear();
- QTextStream str(&query);
- str << classQuery;
- // properties
- if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) {
- str << "/property[@name=\"" << func->propertySpec()->name() << "\"]";
- } else { // normal methods
- str << "/function[@name=\"" << func->originalName() << "\" and count(parameter)="
- << func->arguments().count() << " and @const=\""
- << (func->isConstant() ? "true" : "false") << "\"]";
-
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (int i = 0, size = arguments.size(); i < size; ++i) {
- str << "/parameter[" << (i + 1) << "][@type=\"";
- formatFunctionArgTypeQuery(str, arguments.at(i));
- str << "\"]/..";
- }
- }
- str << "/description";
- DocModificationList funcModifs;
- for (const DocModification &funcModif : qAsConst(signedModifs)) {
- if (funcModif.signature() == func->minimalSignature())
- funcModifs.append(funcModif);
- }
- doc.setValue(getDocumentation(xquery, query, funcModifs));
- if (doc.isEmpty()) {
- qCWarning(lcShiboken(), "%s",
- qPrintable(msgCannotFindDocumentation(sourceFileName, metaClass, func, query)));
- }
- func->setDocumentation(doc);
+ const QString documentation =
+ queryFunctionDocumentation(sourceFileName, metaClass, classQuery,
+ func, signedModifs, xquery, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShiboken(), "%s", qPrintable(errorMessage));
+ func->setDocumentation(Documentation(documentation));
}
#if 0
// Fields
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.h b/sources/shiboken2/ApiExtractor/qtdocparser.h
index 3ea0122b4..b5f0e51d8 100644
--- a/sources/shiboken2/ApiExtractor/qtdocparser.h
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.h
@@ -38,6 +38,15 @@ public:
void fillDocumentation(AbstractMetaClass* metaClass) override;
Documentation retrieveModuleDocumentation() override;
Documentation retrieveModuleDocumentation(const QString& name) override;
+
+private:
+ QString queryFunctionDocumentation(const QString &sourceFileName,
+ const AbstractMetaClass* metaClass,
+ const QString &classQuery,
+ const AbstractMetaFunction *func,
+ const DocModificationList &signedModifs,
+ QXmlQuery &xquery,
+ QString *errorMessage);
};
#endif // QTDOCPARSER_H