diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2017-05-18 16:32:17 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2017-05-18 16:32:18 +0200 |
commit | b68f2b96866c0422c2c02c9ca93874c0081d857b (patch) | |
tree | 6e4ff89b5f20001a4ef2c1d5499a85cf0164744f | |
parent | b7567daf8c73aff0decfdf8f16794334a23f5184 (diff) | |
parent | ba47a265cc4ea881f758704058ac5bbbb547c4ec (diff) |
Change-Id: I78bace9fbc5e8f19bf345ce3f978826507672227
-rw-r--r-- | ApiExtractor/abstractmetabuilder.cpp | 95 | ||||
-rw-r--r-- | ApiExtractor/typedatabase.cpp | 103 | ||||
-rw-r--r-- | ApiExtractor/typedatabase.h | 18 | ||||
-rw-r--r-- | ApiExtractor/typesystem.cpp | 96 | ||||
-rw-r--r-- | ApiExtractor/typesystem.h | 23 | ||||
-rw-r--r-- | CMakeLists.txt | 29 | ||||
-rw-r--r-- | generator/shiboken2/cppgenerator.cpp | 6 | ||||
-rw-r--r-- | generator/shiboken2/shibokengenerator.cpp | 27 | ||||
-rw-r--r-- | generator/shiboken2/shibokengenerator.h | 4 |
9 files changed, 304 insertions, 97 deletions
diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 31c78ce..3b2ecf8 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1083,10 +1083,11 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte if (m_currentClass) className = m_currentClass->typeEntry()->qualifiedCppName(); - if (TypeDatabase::instance()->isEnumRejected(className, enumName)) { + QString rejectReason; + if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { if (typeEntry) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::GenerationDisabled); + m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled); return 0; } @@ -1416,8 +1417,9 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem f if (field->accessPolicy() == CodeModel::Private) return 0; - if (TypeDatabase::instance()->isFieldRejected(className, fieldName)) { - m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field), + QString rejectReason; + if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) { + m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason, AbstractMetaBuilder::GenerationDisabled); return 0; } @@ -2038,16 +2040,35 @@ static QString functionSignature(FunctionModelItem functionItem) return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')'); } -static inline QString functionSignatureWithReturnType(FunctionModelItem functionItem) +static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem, + const QString &className = QString()) { - return functionSignature(functionItem) - + QStringLiteral(" -> ") + functionItem->type().toString(); + QString result = functionItem->type().toString() + QLatin1Char(' '); + if (!className.isEmpty()) + result += className + colonColon(); + result += functionSignature(functionItem); + return result; +} + +static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n) +{ + QString result; + QTextStream str(&result); + str << "unmatched type '" << arg->type().toString() << "' in parameter #" + << (n + 1); + if (!arg->name().isEmpty()) + str << " \"" << arg->name() << '"'; + return result; } -static inline QString qualifiedFunctionSignatureWithType(const QString &className, - FunctionModelItem functionItem) +static inline QString msgVoidParameterType(const ArgumentModelItem &arg, int n) { - return className + colonColon() + functionSignatureWithReturnType(functionItem); + QString result; + QTextStream str(&result); + str << "'void' encountered at parameter #" << (n + 1); + if (!arg->name().isEmpty()) + str << " \"" << arg->name() << '"'; + return result; } AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem) @@ -2056,7 +2077,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel return nullptr; QString functionName = functionItem->name(); QString className; - QString rejectedFunctionSignature; if (m_currentClass) { // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT // and overridden metaObject(), QGADGET helpers @@ -2069,15 +2089,18 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel return nullptr; } - if (TypeDatabase::instance()->isFunctionRejected(className, functionName)) { - rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::GenerationDisabled); + // Store original signature with unresolved typedefs for message/log purposes + const QString originalQualifiedSignatureWithReturn = + qualifiedFunctionSignatureWithType(functionItem, className); + + QString rejectReason; + if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) { + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); return 0; } else if (TypeDatabase::instance()->isFunctionRejected(className, - functionSignature(functionItem))) { - rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::GenerationDisabled); + functionSignature(functionItem), &rejectReason)) { + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); return 0; } @@ -2129,6 +2152,13 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel strippedClassName = strippedClassName.mid(cc_pos + 2); TypeInfo functionType = functionItem->type(); + + if (TypeDatabase::instance()->isReturnTypeRejected(className, functionType.toString(), &rejectReason)) { + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + delete metaFunction; + return nullptr; + } + if (functionName.startsWith(QLatin1Char('~'))) { metaFunction->setFunctionType(AbstractMetaFunction::DestructorFunction); metaFunction->setInvalid(true); @@ -2144,11 +2174,10 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel if (!ok) { Q_ASSERT(type == 0); qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("skipping function '%1::%2', unmatched return type '%3'") - .arg(className, functionItem->name(), + << QStringLiteral("skipping function '%1', unmatched return type '%2'") + .arg(originalQualifiedSignatureWithReturn, functionItem->type().toString()); - rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedReturnType); + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); metaFunction->setInvalid(true); return metaFunction; } @@ -2175,26 +2204,34 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel for (int i = 0; i < arguments.size(); ++i) { ArgumentModelItem arg = arguments.at(i); + if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + delete metaFunction; + return nullptr; + } + bool ok; AbstractMetaType* metaType = translateType(arg->type(), &ok); if (!ok) { Q_ASSERT(metaType == 0); + const QString reason = msgUnmatchedParameterType(arg, i); qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("skipping function '%1::%2', unmatched parameter type '%3'") - .arg(className, functionItem->name(), arg->type().toString()); - rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + << QStringLiteral("skipping function '%1', %2") + .arg(originalQualifiedSignatureWithReturn, reason); + const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn + + QLatin1String(": ") + reason; m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); metaFunction->setInvalid(true); return metaFunction; } if (metaType == Q_NULLPTR) { + const QString reason = msgVoidParameterType(arg, i); qCWarning(lcShiboken).noquote().nospace() - << QString::fromLatin1("skipping function '%1::%2', 'void' encountered at parameter " - "position %3, but it can only be the the first and only " - "parameter") - .arg(className, functionItem->name()).arg(i); - rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + << QString::fromLatin1("skipping function '%1': %2") + .arg(originalQualifiedSignatureWithReturn, reason); + const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn + + QLatin1String(": ") + reason; m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); metaFunction->setInvalid(true); return metaFunction; diff --git a/ApiExtractor/typedatabase.cpp b/ApiExtractor/typedatabase.cpp index 8530d15..a1b2807 100644 --- a/ApiExtractor/typedatabase.cpp +++ b/ApiExtractor/typedatabase.cpp @@ -31,6 +31,7 @@ #include "typesystem_p.h" #include <QtCore/QFile> +#include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QPair> #include <QtCore/QVector> @@ -226,65 +227,109 @@ ContainerTypeEntryList TypeDatabase::containerTypes() const } return returned; } -void TypeDatabase::addRejection(const QString& className, const QString& functionName, - const QString& fieldName, const QString& enumName) + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeRejection &r) { - TypeRejection r; - r.class_name = className; - r.function_name = functionName; - r.field_name = fieldName; - r.enum_name = enumName; + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "TypeRejection(type=" << r.matchType << ", class=" + << r.className.pattern() << ", pattern=" << r.pattern.pattern() << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM +void TypeDatabase::addRejection(const TypeRejection &r) +{ m_rejections << r; } -bool TypeDatabase::isClassRejected(const QString& className) const +static inline QString msgRejectReason(const TypeRejection &r, const QString &needle = QString()) +{ + QString result; + QTextStream str(&result); + switch (r.matchType) { + case TypeRejection::ExcludeClass: + str << " matches class exclusion \"" << r.className.pattern() << '"'; + break; + case TypeRejection::Function: + case TypeRejection::Field: + case TypeRejection::Enum: + str << " matches class \"" << r.className.pattern() << "\" and \"" << r.pattern.pattern() << '"'; + break; + case TypeRejection::ArgumentType: + case TypeRejection::ReturnType: + str << " matches class \"" << r.className.pattern() << "\" and \"" << needle + << "\" matches \"" << r.pattern.pattern() << '"'; + break; + } + return result; +} + +// Match class name only +bool TypeDatabase::isClassRejected(const QString& className, QString *reason) const { for (const TypeRejection& r : m_rejections) { - if (r.class_name == className && r.function_name == QLatin1String("*") - && r.field_name == QLatin1String("*") && r.enum_name == QLatin1String("*")) { + if (r.matchType == TypeRejection::ExcludeClass && r.className.match(className).hasMatch()) { + if (reason) + *reason = msgRejectReason(r); return true; } } return false; } -bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName) const +// Match class name and function/enum/field +static bool findRejection(const QVector<TypeRejection> &rejections, + TypeRejection::MatchType matchType, + const QString& className, const QString& name, + QString *reason = nullptr) { - for (const TypeRejection& r : m_rejections) { - if (r.enum_name == enumName - && (r.class_name == className || r.class_name == QLatin1String("*"))) { + Q_ASSERT(matchType != TypeRejection::ExcludeClass); + for (const TypeRejection& r : rejections) { + if (r.matchType == matchType && r.pattern.match(name).hasMatch() + && r.className.match(className).hasMatch()) { + if (reason) + *reason = msgRejectReason(r, name); return true; } } - return false; } +bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName, QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::Enum, className, enumName, reason); +} + void TypeDatabase::addType(TypeEntry *e) { m_entries[e->qualifiedCppName()].append(e); } -bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName) const +bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName, + QString *reason) const { - for (const TypeRejection &r : m_rejections) { - if (r.function_name == functionName && - (r.class_name == className || r.class_name == QLatin1String("*"))) - return true; - } - return false; + return findRejection(m_rejections, TypeRejection::Function, className, functionName, reason); } +bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName, + QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::Field, className, fieldName, reason); +} -bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName) const +bool TypeDatabase::isArgumentTypeRejected(const QString& className, const QString& typeName, + QString *reason) const { - for (const TypeRejection &r : m_rejections) { - if (r.field_name == fieldName && - (r.class_name == className || r.class_name == QLatin1String("*"))) - return true; - } - return false; + return findRejection(m_rejections, TypeRejection::ArgumentType, className, typeName, reason); +} + +bool TypeDatabase::isReturnTypeRejected(const QString& className, const QString& typeName, + QString *reason) const +{ + return findRejection(m_rejections, TypeRejection::ReturnType, className, typeName, reason); } FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const diff --git a/ApiExtractor/typedatabase.h b/ApiExtractor/typedatabase.h index 870002b..86f9334 100644 --- a/ApiExtractor/typedatabase.h +++ b/ApiExtractor/typedatabase.h @@ -100,12 +100,18 @@ public: ContainerTypeEntryList containerTypes() const; - void addRejection(const QString& className, const QString& functionName, - const QString& fieldName, const QString& enumName); - bool isClassRejected(const QString& className) const; - bool isFunctionRejected(const QString& className, const QString& functionName) const; - bool isFieldRejected(const QString& className, const QString& fieldName) const; - bool isEnumRejected(const QString& className, const QString& enumName) const; + void addRejection(const TypeRejection &); + bool isClassRejected(const QString& className, QString *reason = nullptr) const; + bool isFunctionRejected(const QString& className, const QString& functionName, + QString *reason = nullptr) const; + bool isFieldRejected(const QString& className, const QString& fieldName, + QString *reason = nullptr) const; + bool isEnumRejected(const QString& className, const QString& enumName, + QString *reason = nullptr) const; + bool isArgumentTypeRejected(const QString& className, const QString& typeName, + QString *reason = nullptr) const; + bool isReturnTypeRejected(const QString& className, const QString& typeName, + QString *reason = nullptr) const; void addType(TypeEntry* e); diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index 33bd790..3ec82c5 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -48,9 +48,82 @@ static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote- static inline QString nameAttribute() { return QStringLiteral("name"); } static inline QString sinceAttribute() { return QStringLiteral("since"); } static inline QString flagsAttribute() { return QStringLiteral("flags"); } +static inline QString classAttribute() { return QStringLiteral("class"); } +static inline QString functionNameAttribute() { return QStringLiteral("function-name"); } +static inline QString fieldNameAttribute() { return QStringLiteral("field-name"); } +static inline QString enumNameAttribute() { return QStringLiteral("enum-name"); } +static inline QString argumentTypeAttribute() { return QStringLiteral("argument-type"); } +static inline QString returnTypeAttribute() { return QStringLiteral("return-type"); } static QVector<CustomConversion *> customConversionsForReview; +// Set a regular expression for rejection from text. By legacy, those are fixed +// strings, except for '*' meaning 'match all'. Enclosing in "^..$" +// indicates regular expression. +static bool setRejectionRegularExpression(const QString &patternIn, + QRegularExpression *re, + QString *errorMessage) +{ + QString pattern; + if (patternIn.startsWith(QLatin1Char('^')) && patternIn.endsWith(QLatin1Char('$'))) + pattern = patternIn; + else if (patternIn == QLatin1String("*")) + pattern = QStringLiteral("^.*$"); + else + pattern = QLatin1Char('^') + QRegularExpression::escape(patternIn) + QLatin1Char('$'); + re->setPattern(pattern); + if (!re->isValid()) { + *errorMessage = QLatin1String("Invalid pattern \"") + patternIn + + QLatin1String("\": ") + re->errorString(); + return false; + } + return true; +} + +static bool addRejection(TypeDatabase *database, const QHash<QString, QString> &attributes, + QString *errorMessage) +{ + typedef QPair<QString, TypeRejection::MatchType> AttributeMatchTypePair; + + TypeRejection rejection; + + const QString className = attributes.value(classAttribute()); + if (!setRejectionRegularExpression(className, &rejection.className, errorMessage)) + return false; + + static const AttributeMatchTypePair attributeMatchTypeMapping[] = + {{functionNameAttribute(), TypeRejection::Function}, + {fieldNameAttribute(), TypeRejection::Field}, + {enumNameAttribute(), TypeRejection::Enum}, + {argumentTypeAttribute(), TypeRejection::ArgumentType}, + {returnTypeAttribute(), TypeRejection::ReturnType} + }; + + // Search for non-empty attribute (function, field, enum) + const auto aend = attributes.cend(); + for (const AttributeMatchTypePair &mapping : attributeMatchTypeMapping) { + const auto it = attributes.constFind(mapping.first); + if (it != aend && !it.value().isEmpty()) { + if (!setRejectionRegularExpression(it.value(), &rejection.pattern, errorMessage)) + return false; + rejection.matchType = mapping.second; + database->addRejection(rejection); + return true; + } + } + + // Special case: When all fields except class are empty, completely exclude class + if (className == QLatin1String("*")) { + *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'" + " nor 'field' specified"); + return false; + } + rejection.matchType = TypeRejection::ExcludeClass; + database->addRejection(rejection); + return true; +} + + Handler::Handler(TypeDatabase* database, bool generate) : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) { @@ -1182,10 +1255,12 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts attributes.insert(QLatin1String("to"), QString()); break; case StackElement::Rejection: - attributes.insert(QLatin1String("class"), QLatin1String("*")); - attributes.insert(QLatin1String("function-name"), QLatin1String("*")); - attributes.insert(QLatin1String("field-name"), QLatin1String("*")); - attributes.insert(QLatin1String("enum-name"), QLatin1String("*")); + attributes.insert(classAttribute(), QString()); + attributes.insert(functionNameAttribute(), QString()); + attributes.insert(fieldNameAttribute(), QString()); + attributes.insert(enumNameAttribute(), QString()); + attributes.insert(argumentTypeAttribute(), QString()); + attributes.insert(returnTypeAttribute(), QString()); break; case StackElement::Removal: attributes.insert(QLatin1String("class"), QLatin1String("all")); @@ -1935,18 +2010,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts } } break; - case StackElement::Rejection: { - QString cls = attributes[QLatin1String("class")]; - QString function = attributes[QLatin1String("function-name")]; - QString field = attributes[QLatin1String("field-name")]; - QString enum_ = attributes[QLatin1String("enum-name")]; - if (cls == QLatin1String("*") && function == QLatin1String("*") && field == QLatin1String("*") && enum_ == QLatin1String("*")) { - m_error = QLatin1String("bad reject entry, neither 'class', 'function-name' nor " - "'field' specified"); + case StackElement::Rejection: + if (!addRejection(m_database, attributes, &m_error)) return false; - } - m_database->addRejection(cls, function, field, enum_); - } break; case StackElement::Template: element->value.templateEntry = new TemplateEntry(attributes[nameAttribute()], since); diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index 480ca95..ac0b40f 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -35,6 +35,7 @@ #include <QtCore/QHash> #include <QtCore/qobjectdefs.h> +#include <QtCore/QRegularExpression> #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QMap> @@ -48,6 +49,7 @@ class Indentor; class AbstractMetaType; QT_BEGIN_NAMESPACE +class QDebug; class QTextStream; QT_END_NAMESPACE @@ -1893,12 +1895,25 @@ private: struct TypeRejection { - QString class_name; - QString function_name; - QString field_name; - QString enum_name; + enum MatchType + { + ExcludeClass, // Match className only + Function, // Match className and function name + Field, // Match className and field name + Enum, // Match className and enum name + ArgumentType, // Match className and argument type + ReturnType // Match className and return type + }; + + QRegularExpression className; + QRegularExpression pattern; + MatchType matchType; }; +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeRejection &r); +#endif + QString fixCppTypeName(const QString &name); class CustomConversion diff --git a/CMakeLists.txt b/CMakeLists.txt index 7695df5..ddba62d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,11 +27,30 @@ else() find_package(PythonLibs 2.6) endif() -set(CLANG_DIR $ENV{CLANG_INSTALL_DIR}) +set(CLANG_DIR "") +set(CLANG_DIR_SOURCE "") + +if (DEFINED ENV{LLVM_INSTALL_DIR}) + set(CLANG_DIR $ENV{LLVM_INSTALL_DIR}) + set(CLANG_DIR_SOURCE "LLVM_INSTALL_DIR") +elseif (DEFINED ENV{CLANG_INSTALL_DIR}) + set(CLANG_DIR $ENV{CLANG_INSTALL_DIR}) + set(CLANG_DIR_SOURCE "CLANG_INSTALL_DIR") +else () + EXEC_PROGRAM("llvm-config" ARGS "--prefix" OUTPUT_VARIABLE CLANG_DIR) + set(CLANG_DIR_SOURCE "llvm-config") + if (NOT "${CLANG_DIR}" STREQUAL "") + EXEC_PROGRAM("llvm-config" ARGS "--version" OUTPUT_VARIABLE CLANG_VERSION) + if (CLANG_VERSION VERSION_LESS 3.9) + message(FATAL_ERROR "LLVM version 3.9 is required (llvm-config detected ${CLANG_VERSION} at ${CLANG_DIR}).") + endif() + endif() +endif() -if (NOT IS_DIRECTORY ${CLANG_DIR}) - message(FATAL_ERROR "CLANG_INSTALL_DIR is not set or does not point to a valid directory.") -else() +if ("${CLANG_DIR}" STREQUAL "") + message(FATAL_ERROR "Unable to detect CLANG location by checking LLVM_INSTALL_DIR, CLANG_INSTALL_DIR or running llvm-config.") +elseif (NOT IS_DIRECTORY ${CLANG_DIR}) + message(FATAL_ERROR "${CLANG_DIR} detected by ${CLANG_DIR_SOURCE} does not exist.") endif() set(CLANG_LIB_NAME "clang") @@ -44,7 +63,7 @@ if (NOT EXISTS ${CLANG_LIBRARY}) message(FATAL_ERROR "Unable to find Clang library ${CLANG_LIB_NAME} in ${CLANG_DIR}.") endif() -message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY}") +message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY} detected by ${CLANG_DIR_SOURCE}") set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include) set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY}) diff --git a/generator/shiboken2/cppgenerator.cpp b/generator/shiboken2/cppgenerator.cpp index cb432fe..6aa2c83 100644 --- a/generator/shiboken2/cppgenerator.cpp +++ b/generator/shiboken2/cppgenerator.cpp @@ -710,7 +710,11 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun if (defaultReturnExpr.isEmpty()) defaultReturnExpr = minimalConstructor(func->type()); if (defaultReturnExpr.isEmpty()) { - QString errorMsg = QString::fromLatin1(MIN_CTOR_ERROR_MSG).arg(func->type()->cppSignature()); + QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": "); + if (const AbstractMetaClass *c = func->implementingClass()) + errorMsg += c->qualifiedCppName() + QLatin1String("::"); + errorMsg += func->signature(); + errorMsg = ShibokenGenerator::msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature()); qCWarning(lcShiboken).noquote().nospace() << errorMsg; s << endl << INDENT << "#error " << errorMsg << endl; } diff --git a/generator/shiboken2/shibokengenerator.cpp b/generator/shiboken2/shibokengenerator.cpp index 2dd8f06..4768ddc 100644 --- a/generator/shiboken2/shibokengenerator.cpp +++ b/generator/shiboken2/shibokengenerator.cpp @@ -2680,9 +2680,13 @@ void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const if (defaultCtor.isEmpty() && isCppPrimitive(type)) return; QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; - if (ctor.isEmpty()) - qFatal(qPrintable(QString::fromLatin1(MIN_CTOR_ERROR_MSG).arg(type->cppSignature())), NULL); - s << " = " << ctor; + if (ctor.isEmpty()) { + 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) @@ -2690,9 +2694,14 @@ void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const if (defaultCtor.isEmpty() && isCppPrimitive(type)) return; QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; - if (ctor.isEmpty()) - qFatal(qPrintable(QString::fromLatin1(MIN_CTOR_ERROR_MSG).arg(type->qualifiedCppName())), NULL); - s << " = " << ctor; + + if (ctor.isEmpty()) { + const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName()); + qCWarning(lcShiboken()).noquote() << message; + s << ";\n#error " << message << endl; + } else { + s << " = " << ctor; + } } bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type) @@ -2711,3 +2720,9 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type) { return isCppIntegralPrimitive(type->typeEntry()); } + +QString ShibokenGenerator::msgCouldNotFindMinimalConstructor(const QString &where, const QString &type) +{ + return where + QLatin1String(": Could not find a minimal constructor for type '") + type + + QLatin1String("'. This will result in a compilation error."); +} diff --git a/generator/shiboken2/shibokengenerator.h b/generator/shiboken2/shibokengenerator.h index cf2af04..1be56ed 100644 --- a/generator/shiboken2/shibokengenerator.h +++ b/generator/shiboken2/shibokengenerator.h @@ -43,8 +43,6 @@ #define THREAD_STATE_SAVER_VAR "threadStateSaver" #define BEGIN_ALLOW_THREADS "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS" #define END_ALLOW_THREADS "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS" -#define MIN_CTOR_ERROR_MSG "Could not find a minimal constructor for type '%1'. "\ - "This will result in a compilation error." #define PYTHON_TO_CPP_VAR "pythonToCpp" #define SMART_POINTER_GETTER "kSmartPointerGetter" @@ -537,6 +535,8 @@ protected: }; void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code); + static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type); + private: bool m_useCtorHeuristic; bool m_userReturnValueHeuristic; |