diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/typesystem.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.cpp | 145 |
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; } |