aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2017-05-18 16:32:17 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2017-05-18 16:32:18 +0200
commitb68f2b96866c0422c2c02c9ca93874c0081d857b (patch)
tree6e4ff89b5f20001a4ef2c1d5499a85cf0164744f
parentb7567daf8c73aff0decfdf8f16794334a23f5184 (diff)
parentba47a265cc4ea881f758704058ac5bbbb547c4ec (diff)
Merge remote-tracking branch 'origin/5.9' into devHEADdev
-rw-r--r--ApiExtractor/abstractmetabuilder.cpp95
-rw-r--r--ApiExtractor/typedatabase.cpp103
-rw-r--r--ApiExtractor/typedatabase.h18
-rw-r--r--ApiExtractor/typesystem.cpp96
-rw-r--r--ApiExtractor/typesystem.h23
-rw-r--r--CMakeLists.txt29
-rw-r--r--generator/shiboken2/cppgenerator.cpp6
-rw-r--r--generator/shiboken2/shibokengenerator.cpp27
-rw-r--r--generator/shiboken2/shibokengenerator.h4
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;