aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/ApiExtractor/typesystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/ApiExtractor/typesystem.cpp')
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp145
1 files changed, 110 insertions, 35 deletions
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index 869904d43..9adc5107b 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -32,6 +32,7 @@
#include "reporthandler.h"
#include <QtCore/QDir>
#include <QtCore/QFile>
+#include <QtCore/QRegularExpression>
#include <QtCore/QXmlStreamAttributes>
#include <QtCore/QXmlStreamReader>
@@ -44,11 +45,85 @@ static QString strings_jobject = QLatin1String("jobject");
static inline QString colonColon() { return QStringLiteral("::"); }
static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
+static inline QString textAttribute() { return QStringLiteral("text"); }
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;
+}
-static QList<CustomConversion*> customConversionsForReview = QList<CustomConversion*>();
Handler::Handler(TypeDatabase* database, bool generate)
: m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
@@ -209,8 +284,9 @@ bool Handler::endElement(const QStringRef &localName)
if (m_generate == TypeEntry::GenerateAll) {
TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions);
TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods);
- foreach (CustomConversion* customConversion, customConversionsForReview) {
- foreach (CustomConversion::TargetToNativeConversion* toNative, customConversion->targetToNativeConversions())
+ for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) {
+ const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions();
+ for (CustomConversion::TargetToNativeConversion *toNative : toNatives)
toNative->setSourceType(m_database->findType(toNative->sourceTypeName()));
}
}
@@ -493,7 +569,8 @@ static QString getNamePrefix(StackElement* element)
static QString checkSignatureError(const QString& signature, const QString& tag)
{
QString funcName = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
- static QRegExp whiteSpace(QLatin1String("\\s"));
+ static const QRegularExpression whiteSpace(QStringLiteral("\\s"));
+ Q_ASSERT(whiteSpace.isValid());
if (!funcName.startsWith(QLatin1String("operator ")) && funcName.contains(whiteSpace)) {
return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n"
"White spaces aren't allowed in function names, "
@@ -725,8 +802,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
QString rename = attributes[QLatin1String("rename")];
if (!rename.isEmpty()) {
- static QRegExp functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
- if (!functionNameRegExp.exactMatch(rename)) {
+ static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+ Q_ASSERT(functionNameRegExp.isValid());
+ if (!functionNameRegExp.match(rename).hasMatch()) {
m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
+ rename + QLatin1String("' is not a valid function name");
return false;
@@ -850,7 +928,8 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
// put in the flags parallel...
const QString flagNames = attributes.value(flagsAttribute());
if (!flagNames.isEmpty()) {
- foreach (const QString &flagName, flagNames.split(QLatin1Char(',')))
+ const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
+ for (const QString &flagName : flagNameList)
addFlags(name, flagName.trimmed(), attributes, since);
}
}
@@ -1095,7 +1174,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
attributes.insert(QLatin1String("default-value"), QString());
break;
case StackElement::SuppressedWarning:
- attributes.insert(QLatin1String("text"), QString());
+ attributes.insert(textAttribute(), QString());
break;
case StackElement::ReplaceDefaultExpression:
attributes.insert(QLatin1String("with"), QString());
@@ -1177,10 +1256,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"));
@@ -1444,11 +1525,15 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
}
break;
- case StackElement::SuppressedWarning:
- if (attributes[QLatin1String("text")].isEmpty())
+ case StackElement::SuppressedWarning: {
+ const QString suppressedWarning = attributes.value(textAttribute());
+ if (suppressedWarning.isEmpty()) {
qCWarning(lcShiboken) << "Suppressed warning with no text specified";
- else
- m_database->addSuppressedWarning(attributes[QLatin1String("text")]);
+ } else {
+ if (!m_database->addSuppressedWarning(suppressedWarning, &m_error))
+ return false;
+ }
+ }
break;
case StackElement::ArgumentMap: {
if (!(topElement.type & StackElement::CodeSnipMask)) {
@@ -1746,8 +1831,8 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
if (rc.action == ReferenceCount::Invalid) {
m_error = QLatin1String("unrecognized value for action attribute. supported actions:");
- foreach (const QString &action, actions.keys())
- m_error += QLatin1Char(' ') + action;
+ for (QHash<QString, ReferenceCount::Action>::const_iterator it = actions.cbegin(), end = actions.cend(); it != end; ++it)
+ m_error += QLatin1Char(' ') + it.key();
}
m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
@@ -1930,18 +2015,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);
@@ -2172,7 +2248,7 @@ QString TemplateInstance::expandCode() const
QString CodeSnipAbstract::code() const
{
QString res;
- foreach (const CodeSnipFragment &codeFrag, codeList)
+ for (const CodeSnipFragment &codeFrag : codeList)
res.append(codeFrag.code());
return res;
@@ -2205,7 +2281,7 @@ QString FunctionModification::toString() const
if (modifiers & Writable) str += QLatin1String("writable");
if (modifiers & CodeInjection) {
- foreach (const CodeSnip &s, snips) {
+ for (const CodeSnip &s : snips) {
str += QLatin1String("\n//code injection:\n");
str += s.code();
}
@@ -2254,7 +2330,8 @@ bool FunctionModification::operator==(const FunctionModification& other) const
static AddedFunction::TypeInfo parseType(const QString& signature, int startPos = 0, int* endPos = 0)
{
AddedFunction::TypeInfo result;
- QRegExp regex(QLatin1String("\\w"));
+ static const QRegularExpression regex(QLatin1String("\\w"));
+ Q_ASSERT(regex.isValid());
int length = signature.length();
int start = signature.indexOf(regex, startPos);
if (start == -1) {
@@ -2563,9 +2640,7 @@ CustomConversion::CustomConversion(TypeEntry* ownerType)
CustomConversion::~CustomConversion()
{
- foreach (TargetToNativeConversion* targetToNativeConversion, m_d->targetToNativeConversions)
- delete targetToNativeConversion;
- m_d->targetToNativeConversions.clear();
+ qDeleteAll(m_d->targetToNativeConversions);
delete m_d;
}