aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/tests/dumpcodemodel/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/tests/dumpcodemodel/main.cpp')
-rw-r--r--sources/shiboken2/tests/dumpcodemodel/main.cpp197
1 files changed, 186 insertions, 11 deletions
diff --git a/sources/shiboken2/tests/dumpcodemodel/main.cpp b/sources/shiboken2/tests/dumpcodemodel/main.cpp
index e132c97b3..37c964fc0 100644
--- a/sources/shiboken2/tests/dumpcodemodel/main.cpp
+++ b/sources/shiboken2/tests/dumpcodemodel/main.cpp
@@ -33,14 +33,18 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QCommandLineOption>
#include <QtCore/QCommandLineParser>
+#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
+#include <QtCore/QXmlStreamWriter>
#include <iostream>
#include <algorithm>
#include <iterator>
+static bool optJoinNamespaces = false;
+
static inline QString languageLevelDescription()
{
return QLatin1String("C++ Language level (c++11..c++17, default=")
@@ -48,23 +52,196 @@ 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 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 bool useClass(const ClassModelItem &c)
+{
+ return c->classType() != CodeModel::Union && c->templateParameters().isEmpty()
+ && !c->name().isEmpty(); // No anonymous structs
+}
+
+static void formatXmlScopeMembers(QXmlStreamWriter &writer, const ScopeModelItem &nsp)
+{
+ for (const auto &klass : nsp->classes()) {
+ if (useClass(klass))
+ 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 formatXmlLocationComment(QXmlStreamWriter &writer, const CodeModelItem &i)
+{
+ QString comment;
+ QTextStream(&comment) << ' ' << i->fileName() << ':' << i->startLine() << ' ';
+ writer.writeComment(comment);
+}
+
+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);
+ formatXmlLocationComment(writer, klass);
+ writer.writeStartElement(isValueType ? QStringLiteral("value-type")
+ : QStringLiteral("object-type"));
+ writer.writeAttribute(nameAttribute(), klass->name());
+ formatXmlScopeMembers(writer, klass);
+ writer.writeEndElement();
+}
+
+// Check whether a namespace is relevant for type system
+// output, that is, has non template classes, functions or enumerations.
+static bool hasMembers(const NamespaceModelItem &nsp)
+{
+ if (!nsp->namespaces().isEmpty() || !nsp->enums().isEmpty()
+ || !nsp->functions().isEmpty()) {
+ return true;
+ }
+ const auto classes = nsp->classes();
+ return std::any_of(classes.cbegin(), classes.cend(), useClass);
+}
+
+static void startXmlNamespace(QXmlStreamWriter &writer, const NamespaceModelItem &nsp)
+{
+ formatXmlLocationComment(writer, nsp);
+ writer.writeStartElement(QStringLiteral("namespace-type"));
+ writer.writeAttribute(nameAttribute(), nsp->name());
+}
+
+static void formatXmlNamespaceMembers(QXmlStreamWriter &writer, const NamespaceModelItem &nsp)
+{
+ auto nestedNamespaces = nsp->namespaces();
+ for (int i = nestedNamespaces.size() - 1; i >= 0; --i) {
+ if (!hasMembers(nestedNamespaces.at(i)))
+ nestedNamespaces.removeAt(i);
+ }
+ while (!nestedNamespaces.isEmpty()) {
+ auto current = nestedNamespaces.takeFirst();
+ startXmlNamespace(writer, current);
+ formatXmlNamespaceMembers(writer, current);
+ if (optJoinNamespaces) {
+ // Write out members of identical namespaces and remove
+ const QString name = current->name();
+ for (int i = 0; i < nestedNamespaces.size(); ) {
+ if (nestedNamespaces.at(i)->name() == name) {
+ formatXmlNamespaceMembers(writer, nestedNamespaces.at(i));
+ nestedNamespaces.removeAt(i);
+ } else {
+ ++i;
+ }
+ }
+ }
+ writer.writeEndElement();
+ }
+
+ 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 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 joinNamespacesOption({QStringLiteral("j"), QStringLiteral("join-namespaces")},
+ QStringLiteral("Join namespaces"));
+ parser.addOption(joinNamespacesOption);
+
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();
@@ -86,6 +263,8 @@ int main(int argc, char **argv)
}
}
+ optJoinNamespaces = parser.isSet(joinNamespacesOption);
+
const FileModelItem dom = AbstractMetaBuilderPrivate::buildDom(arguments, level, 0);
if (dom.isNull()) {
QString message = QLatin1String("Unable to parse ") + positionalArguments.join(QLatin1Char(' '));
@@ -93,14 +272,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;
}