aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2018-09-11 08:53:32 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2018-09-12 06:47:40 +0000
commit8a62536b1071ac86c86c82089a53b7a4cd172f90 (patch)
treedf595b8c7b750ae7d50b09adb66607da7a4b4709
parentdbb78237ef6622a2daae32fa3f5fa0cd9b1ffda5 (diff)
shiboken: Introduce DefaultValue
Introduce a small class storing the return value of Generator::minimalConstructor() consisting of a type enumeration and a value, offering formatting for the use cases variable initializations, return values and constructor arguments lists. Having distinct formatting for the different use cases has some advantages: - Can use nullptr without casts (except in constructor arguments lists, where the type is needed for disambiguation). - In the previous implementation using a string, "" indicated an error; so, it was not possible to use it for default-constructors. It is now possible to handle default-constructors for initialization ("Foo f" instead of "Foo f = Foo()". - Can use {} for return values. Task-number: PYSIDE-62 Change-Id: I73229cb957d4b92b43de4cdbc3c66703f48faa61 Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r--sources/shiboken2/generator/generator.cpp191
-rw-r--r--sources/shiboken2/generator/generator.h41
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp28
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp29
4 files changed, 225 insertions, 64 deletions
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 9cf26b52f..cf850356c 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -40,6 +40,106 @@
#include <QDebug>
#include <typedatabase.h>
+/**
+ * DefaultValue is used for storing default values of types for which code is
+ * generated in different contexts:
+ *
+ * Context | Example: "Class *" | Example: "Class" with default Constructor
+ * --------------------+-------------------------------+------------------------------------------
+ * Variable | var{nullptr}; | var;
+ * initializations | |
+ * --------------------+-------------------------------+------------------------------------------
+ * Return values | return nullptr; | return {}
+ * --------------------+-------------------------------+------------------------------------------
+ * constructor | static_cast<Class *>(nullptr) | Class()
+ * arguments lists | |
+ * (recursive, precise | |
+ * matching). | |
+ */
+
+DefaultValue::DefaultValue(Type t, QString value) :
+ m_type(t), m_value(std::move(value))
+{
+}
+
+DefaultValue::DefaultValue(QString customValue) :
+ m_type(Custom), m_value(std::move(customValue))
+{
+}
+
+QString DefaultValue::returnValue() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("false");
+ case DefaultValue::CppScalar:
+ return QLatin1String("0");
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ return QLatin1String("nullptr");
+ case DefaultValue::Void:
+ return QString();
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return QLatin1String("{}");
+}
+
+QString DefaultValue::initialization() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("{false}");
+ case DefaultValue::CppScalar:
+ return QLatin1String("{0}");
+ case DefaultValue::Custom:
+ return QLatin1String(" = ") + m_value;
+ case DefaultValue::Enum:
+ return QLatin1Char('{') + m_value + QLatin1Char('}');
+ case DefaultValue::Pointer:
+ return QLatin1String("{nullptr}");
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return QString();
+}
+
+QString DefaultValue::constructorParameter() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("false");
+ case DefaultValue::CppScalar:
+ return m_value + QLatin1String("(0)");
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ // Be precise here to be able to differentiate between constructors
+ // taking different pointer types, cf
+ // QTreeWidgetItemIterator(QTreeWidget *) and
+ // QTreeWidgetItemIterator(QTreeWidgetItemIterator *).
+ return QLatin1String("static_cast<") + m_value + QLatin1String("*>(nullptr)");
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return m_value + QLatin1String("()");
+}
+
struct Generator::GeneratorPrivate
{
const ApiExtractor* apiextractor = nullptr;
@@ -560,63 +660,72 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type)
return QLatin1String("::") + typeName;
}
-QString Generator::minimalConstructor(const AbstractMetaType* type) const
+DefaultValue Generator::minimalConstructor(const AbstractMetaType* type) const
{
if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type)))
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isContainer()) {
QString ctor = type->cppSignature();
- if (ctor.endsWith(QLatin1Char('*')))
- return QLatin1String("0");
+ if (ctor.endsWith(QLatin1Char('*'))) {
+ ctor.chop(1);
+ return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
+ }
if (ctor.startsWith(QLatin1String("const ")))
ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
if (ctor.endsWith(QLatin1Char('&'))) {
ctor.chop(1);
ctor = ctor.trimmed();
}
- return QLatin1String("::") + ctor + QLatin1String("()");
+ return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor);
}
if (type->isNativePointer())
- return QLatin1String("static_cast<") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, type->typeEntry()->qualifiedCppName());
if (Generator::isPointer(type))
- return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type->typeEntry()->qualifiedCppName());
if (type->typeEntry()->isComplex()) {
const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(type->typeEntry());
- QString ctor = cType->defaultConstructor();
- if (!ctor.isEmpty())
- return ctor;
- ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
- if (type->hasInstantiations())
- ctor = ctor.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ if (cType->hasDefaultConstructor())
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ auto ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
+ if (ctor.isValid() && type->hasInstantiations()) {
+ QString v = ctor.value();
+ v.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ ctor.setValue(v);
+ }
return ctor;
}
return minimalConstructor(type->typeEntry());
}
-QString Generator::minimalConstructor(const TypeEntry* type) const
+DefaultValue Generator::minimalConstructor(const TypeEntry* type) const
{
if (!type)
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isCppPrimitive()) {
const QString &name = type->qualifiedCppName();
return name == QLatin1String("bool")
- ? QLatin1String("false") : name + QLatin1String("(0)");
+ ? DefaultValue(DefaultValue::Boolean)
+ : DefaultValue(DefaultValue::CppScalar, name);
}
if (type->isEnum()) {
const auto enumEntry = static_cast<const EnumTypeEntry *>(type);
if (const auto *nullValue = enumEntry->nullValue())
- return nullValue->name();
- return QLatin1String("static_cast< ::") + type->qualifiedCppName() + QLatin1String(">(0)");
+ return DefaultValue(DefaultValue::Enum, nullValue->name());
+ return DefaultValue(DefaultValue::Custom,
+ QLatin1String("static_cast< ::") + type->qualifiedCppName()
+ + QLatin1String(">(0)"));
}
- if (type->isFlags())
- return type->qualifiedCppName() + QLatin1String("(0)");
+ if (type->isFlags()) {
+ return DefaultValue(DefaultValue::Custom,
+ type->qualifiedCppName() + QLatin1String("(0)"));
+ }
if (type->isPrimitive()) {
QString ctor = static_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor();
@@ -625,24 +734,31 @@ QString Generator::minimalConstructor(const TypeEntry* type) const
// heuristically returned. If this is wrong the build of the generated
// bindings will tell.
return ctor.isEmpty()
- ? (QLatin1String("::") + type->qualifiedCppName() + QLatin1String("()"))
- : ctor;
+ ? DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::")
+ + type->qualifiedCppName())
+ : DefaultValue(DefaultValue::Custom, ctor);
}
if (type->isComplex())
return minimalConstructor(AbstractMetaClass::findClass(classes(), type));
- return QString();
+ return DefaultValue(DefaultValue::Error);
}
-QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
+static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
+{
+ return QLatin1String("::") + qualifiedCppName + QLatin1Char('(')
+ + args.join(QLatin1String(", ")) + QLatin1Char(')');
+}
+
+DefaultValue Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
{
if (!metaClass)
- return QString();
+ return DefaultValue(DefaultValue::Error);
const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
if (cType->hasDefaultConstructor())
- return cType->defaultConstructor();
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
const AbstractMetaFunctionList &constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
int maxArgs = 0;
@@ -667,7 +783,7 @@ QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
// Empty constructor.
if (maxArgs == 0)
- return QLatin1String("::") + qualifiedCppName + QLatin1String("()");
+ return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + qualifiedCppName);
QVector<const AbstractMetaFunction *> candidates;
@@ -699,12 +815,12 @@ QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
}
if (type->isCppPrimitive() || type->isEnum() || isPointer(arg->type())) {
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
+ auto argValue = minimalConstructor(arg->type());
+ if (!argValue.isValid()) {
args.clear();
break;
}
- args << argValue;
+ args << argValue.constructorParameter();
} else {
args.clear();
break;
@@ -712,7 +828,7 @@ QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
}
if (!args.isEmpty())
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+ return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
candidates << ctor;
}
@@ -729,19 +845,18 @@ QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
args.clear();
break;
}
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
+ auto argValue = minimalConstructor(arg->type());
+ if (!argValue.isValid()) {
args.clear();
break;
}
- args << argValue;
- }
- if (!args.isEmpty()) {
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+ args << argValue.constructorParameter();
}
+ if (!args.isEmpty())
+ return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
}
- return QString();
+ return DefaultValue(DefaultValue::Error);
}
QString Generator::translateType(const AbstractMetaType *cType,
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
index ac6009d73..dd30f324e 100644
--- a/sources/shiboken2/generator/generator.h
+++ b/sources/shiboken2/generator/generator.h
@@ -95,6 +95,41 @@ const int alwaysGenerateDestructor = 1;
const int alwaysGenerateDestructor = 0;
#endif
+class DefaultValue
+{
+public:
+ enum Type
+ {
+ Error,
+ Boolean,
+ CppScalar, // A C++ scalar type (int,..) specified by value()
+ Custom, // A custom constructor/expression, uses value() as is
+ DefaultConstructor, // For classes named value()
+ Enum, // Enum value as specified by value()
+ Pointer, // Pointer of type value()
+ Void // "", for return values only
+ };
+
+ explicit DefaultValue(Type t = Error, QString value = QString());
+ explicit DefaultValue(QString customValue);
+
+ bool isValid() const { return m_type != Error; }
+
+ QString returnValue() const;
+ QString initialization() const;
+ QString constructorParameter() const;
+
+ QString value() const { return m_value; }
+ void setValue(const QString &value) { m_value = value; }
+
+ Type type() const { return m_type; }
+ void setType(Type type) { m_type = type; }
+
+private:
+ Type m_type;
+ QString m_value;
+};
+
/**
* A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
* AbstractMetaType, for which code is currently being generated.
@@ -330,9 +365,9 @@ protected:
* It will check first for a user defined default constructor.
* Returns a null string if it fails.
*/
- QString minimalConstructor(const TypeEntry* type) const;
- QString minimalConstructor(const AbstractMetaType* type) const;
- QString minimalConstructor(const AbstractMetaClass* metaClass) const;
+ DefaultValue minimalConstructor(const TypeEntry* type) const;
+ DefaultValue minimalConstructor(const AbstractMetaType* type) const;
+ DefaultValue minimalConstructor(const AbstractMetaClass* metaClass) const;
/**
* Returns the file name used to write the binding code of an AbstractMetaClass/Type.
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index b992a5ca8..4bb1e02b6 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -733,7 +733,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
Indentation indentation(INDENT);
- QString defaultReturnExpr;
+ DefaultValue defaultReturnExpr;
if (retType) {
const FunctionModificationList &mods = func->modifications();
for (const FunctionModification &mod : mods) {
@@ -741,9 +741,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
Q_ASSERT(regex.isValid());
- defaultReturnExpr = argMod.replacedDefaultExpression;
+ QString expr = argMod.replacedDefaultExpression;
for (int offset = 0; ; ) {
- const QRegularExpressionMatch match = regex.match(defaultReturnExpr, offset);
+ const QRegularExpressionMatch match = regex.match(expr, offset);
if (!match.hasMatch())
break;
const int argId = match.capturedRef(1).toInt() - 1;
@@ -751,15 +751,17 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
qCWarning(lcShiboken) << "The expression used in return value contains an invalid index.";
break;
}
- defaultReturnExpr.replace(match.captured(0), func->arguments().at(argId)->name());
+ expr.replace(match.captured(0), func->arguments().at(argId)->name());
offset = match.capturedStart(1);
}
+ defaultReturnExpr.setType(DefaultValue::Custom);
+ defaultReturnExpr.setValue(expr);
}
}
}
- if (defaultReturnExpr.isEmpty())
+ if (!defaultReturnExpr.isValid())
defaultReturnExpr = minimalConstructor(func->type());
- if (defaultReturnExpr.isEmpty()) {
+ if (!defaultReturnExpr.isValid()) {
QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
if (const AbstractMetaClass *c = func->implementingClass())
errorMsg += c->qualifiedCppName() + QLatin1String("::");
@@ -768,6 +770,8 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
qCWarning(lcShiboken).noquote().nospace() << errorMsg;
s << endl << INDENT << "#error " << errorMsg << endl;
}
+ } else {
+ defaultReturnExpr.setType(DefaultValue::Void);
}
if (func->isAbstract() && func->isModifiedRemoved()) {
@@ -775,7 +779,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
<< QString::fromLatin1("Pure virtual method '%1::%2' must be implement but was "\
"completely removed on type system.")
.arg(func->ownerClass()->name(), func->minimalSignature());
- s << INDENT << returnStatement(defaultReturnExpr) << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
s << '}' << endl << endl;
return;
}
@@ -794,7 +798,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "if (PyErr_Occurred())" << endl;
{
Indentation indentation(INDENT);
- s << INDENT << returnStatement(defaultReturnExpr) << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR << "(Shiboken::BindingManager::instance().getOverride(this, \"";
@@ -817,7 +821,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << "()' not implemented.\");" << endl;
s << INDENT << "return";
if (retType)
- s << ' ' << defaultReturnExpr;
+ s << ' ' << defaultReturnExpr.returnValue();
} else {
s << INDENT << "gil.release();" << endl;
s << INDENT;
@@ -922,7 +926,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
{
Indentation indent(INDENT);
s << INDENT << "PyErr_Print();" << endl;
- s << INDENT << returnStatement(defaultReturnExpr) << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
@@ -944,7 +948,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
"\"Invalid return value in function %s, expected %s, got %s.\", \"";
s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl;
- s << INDENT << returnStatement(defaultReturnExpr) << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
@@ -965,7 +969,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
"\"Invalid return value in function %s, expected %s, got %s.\", \"";
s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl;
- s << INDENT << returnStatement(defaultReturnExpr) << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 6a7cef6ef..6d263dd01 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -2653,30 +2653,37 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
{
- if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ if (!defaultCtor.isEmpty()) {
+ s << " = " << defaultCtor;
+ return;
+ }
+ if (isCppPrimitive(type))
return;
- QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
- if (ctor.isEmpty()) {
+ const auto ctor = minimalConstructor(type);
+ if (ctor.isValid()) {
+ s << ctor.initialization();
+ } else {
const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature());
qCWarning(lcShiboken()).noquote() << message;
s << ";\n#error " << message << '\n';
- } else {
- s << " = " << ctor;
}
}
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor)
{
- if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ if (!defaultCtor.isEmpty()) {
+ s << " = " << defaultCtor;
+ return;
+ }
+ if (isCppPrimitive(type))
return;
- QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
-
- if (ctor.isEmpty()) {
+ const auto ctor = minimalConstructor(type);
+ if (ctor.isValid()) {
+ s << ctor.initialization();
+ } else {
const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
qCWarning(lcShiboken()).noquote() << message;
s << ";\n#error " << message << endl;
- } else {
- s << " = " << ctor;
}
}