From d1604053e9ae354963a2b2447b3d196fc5dda73e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 26 Feb 2020 15:24:12 +0100 Subject: Change the dumpcodemodel tool to output typesystem XML Make the previously existing debug output an option and output typesystem XML by default. Change-Id: I3d95bdb56446097377880e1ca0b54d3b8b93ea24 Reviewed-by: Christian Tismer --- .../shiboken2/ApiExtractor/parser/codemodel.cpp | 14 ++ sources/shiboken2/ApiExtractor/parser/codemodel.h | 2 + sources/shiboken2/tests/dumpcodemodel/main.cpp | 143 +++++++++++++++++++-- 3 files changed, 148 insertions(+), 11 deletions(-) diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp index 099ab8860..4fafa0c2c 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -1127,6 +1127,20 @@ void _FunctionModelItem::setInvokable(bool isInvokable) m_isInvokable = isInvokable; } +QString _FunctionModelItem::typeSystemSignature() const // For dumping out type system files +{ + QString result; + QTextStream str(&result); + str << name() << '('; + for (int a = 0, size = m_arguments.size(); a < size; ++a) { + if (a) + str << ','; + str << m_arguments.at(a)->type().qualifiedName().join(QLatin1String("::")); + } + str << ')'; + return result; +} + #ifndef QT_NO_DEBUG_STREAM void _FunctionModelItem::formatDebug(QDebug &d) const { diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h index 80db2cce5..e851c9c8e 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -618,6 +618,8 @@ public: ExceptionSpecification exceptionSpecification() const; void setExceptionSpecification(ExceptionSpecification e); + QString typeSystemSignature() const; // For dumping out type system files + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif diff --git a/sources/shiboken2/tests/dumpcodemodel/main.cpp b/sources/shiboken2/tests/dumpcodemodel/main.cpp index e132c97b3..52d64be94 100644 --- a/sources/shiboken2/tests/dumpcodemodel/main.cpp +++ b/sources/shiboken2/tests/dumpcodemodel/main.cpp @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -48,23 +50,146 @@ static inline QString languageLevelDescription() + QLatin1Char(')'); } +static void formatDebugOutput(const FileModelItem &dom, bool verbose) +{ + QString output; + { + QDebug debug(&output); + if (verbose) + debug.setVerbosity(3); + debug << dom.data(); + } + std::cout << qPrintable(output) << '\n'; +} + +static const char *primitiveTypes[] = { + "int", "unsigned", "short", "unsigned short", "long", "unsigned long", + "float", "double" +}; + +static inline QString nameAttribute() { return QStringLiteral("name"); } + +static void formatXmlNamespace(QXmlStreamWriter &writer, const NamespaceModelItem &nsp); +static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass); + +static void formatXmlEnum(QXmlStreamWriter &writer, const EnumModelItem &en) +{ + writer.writeStartElement(QStringLiteral("enum-type")); + writer.writeAttribute(nameAttribute(), en->name()); + writer.writeEndElement(); +} + +static void formatXmlScopeMembers(QXmlStreamWriter &writer, const ScopeModelItem &nsp) +{ + for (const auto &klass : nsp->classes()) { + if (klass->classType() != CodeModel::Union && klass->templateParameters().isEmpty()) + formatXmlClass(writer, klass); + } + for (const auto &en : nsp->enums()) + formatXmlEnum(writer, en); +} + +static bool isPublicCopyConstructor(const FunctionModelItem &f) +{ + return f->functionType() == CodeModel::CopyConstructor + && f->accessPolicy() == CodeModel::Public && !f->isDeleted(); +} + +static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass) +{ + // Heuristics for value types: check on public copy constructors. + const auto functions = klass->functions(); + const bool isValueType = std::any_of(functions.cbegin(), functions.cend(), + isPublicCopyConstructor); + writer.writeStartElement(isValueType ? QStringLiteral("value-type") + : QStringLiteral("object-type")); + writer.writeAttribute(nameAttribute(), klass->name()); + formatXmlScopeMembers(writer, klass); + writer.writeEndElement(); +} + +static void formatXmlNamespaceMembers(QXmlStreamWriter &writer, const NamespaceModelItem &nsp) +{ + for (const auto &nested : nsp->namespaces()) + formatXmlNamespace(writer, nested); + for (auto func : nsp->functions()) { + const QString signature = func->typeSystemSignature(); + if (!signature.contains(QLatin1String("operator"))) { // Skip free operators + writer.writeStartElement(QStringLiteral("function")); + writer.writeAttribute(QStringLiteral("signature"), signature); + writer.writeEndElement(); + } + } + formatXmlScopeMembers(writer, nsp); +} + +static void formatXmlNamespace(QXmlStreamWriter &writer, const NamespaceModelItem &nsp) +{ + writer.writeStartElement(QStringLiteral("namespace-type")); + writer.writeAttribute(nameAttribute(), nsp->name()); + formatXmlNamespaceMembers(writer, nsp); + writer.writeEndElement(); +} + +static void formatXmlOutput(const FileModelItem &dom) +{ + QString output; + QXmlStreamWriter writer(&output); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + writer.writeStartElement(QStringLiteral("typesystem")); + writer.writeAttribute(QStringLiteral("package"), QStringLiteral("insert_name")); + writer.writeComment(QStringLiteral("Auto-generated ") + + QDateTime::currentDateTime().toString(Qt::ISODate)); + for (auto p : primitiveTypes) { + writer.writeStartElement(QStringLiteral("primitive-type")); + writer.writeAttribute(nameAttribute(), QLatin1String(p)); + writer.writeEndElement(); + } + formatXmlNamespaceMembers(writer, dom); + writer.writeEndElement(); + writer.writeEndDocument(); + std::cout << qPrintable(output) << '\n'; +} + +static const char descriptionFormat[] = R"( +Type system dumper + +Parses a C++ header and dumps out the classes found in typesystem XML syntax. +Arguments are arguments to the compiler the last of which should be the header +or source file. +It is recommended to create a .hh include file including the desired headers +and pass that along with the required include paths. + +Based on Qt %1 and LibClang v%2.)"; + int main(int argc, char **argv) { QCoreApplication app(argc, argv); QCommandLineParser parser; parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - parser.setApplicationDescription(QStringLiteral("Code model tester")); + parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); + const QString description = + QString::fromLatin1(descriptionFormat).arg(QLatin1String(qVersion()), + clang::libClangVersion().toString()); + parser.setApplicationDescription(description); parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption verboseOption(QStringLiteral("d"), + QCommandLineOption verboseOption(QStringLiteral("verbose"), QStringLiteral("Display verbose output about types")); parser.addOption(verboseOption); + QCommandLineOption debugOption(QStringLiteral("debug"), + QStringLiteral("Display debug output")); + parser.addOption(debugOption); + QCommandLineOption languageLevelOption(QStringLiteral("std"), languageLevelDescription(), QStringLiteral("level")); parser.addOption(languageLevelOption); - parser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("C++ source file")); + parser.addPositionalArgument(QStringLiteral("argument"), + QStringLiteral("C++ compiler argument"), + QStringLiteral("argument(s)")); parser.process(app); const QStringList &positionalArguments = parser.positionalArguments(); @@ -93,14 +218,10 @@ int main(int argc, char **argv) return -2; } - QString output; - { - QDebug debug(&output); - if (parser.isSet(verboseOption)) - debug.setVerbosity(3); - debug << dom.data(); - } - std::cout << qPrintable(output) << '\n'; + if (parser.isSet(debugOption)) + formatDebugOutput(dom, parser.isSet(verboseOption)); + else + formatXmlOutput(dom); return 0; } -- cgit v1.2.3