aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2017-05-12 16:14:41 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2017-05-18 11:11:12 +0000
commitf6bc1cb55603728a0b15fd9482cccc2af86539eb (patch)
tree03819d3d4082a530cf79cfdb6b5e18562743612b
parent467095ad1ac08faf225e1bc8932bec791ce27ef6 (diff)
TypeRejection: Use QRegularExpression
Refactor TypeRejection to use one regular expression for the class name and one for the various strings to be matched depending on the match type enumeration instead of 4 fixed string fields. Task-number: PYSIDE-516 Change-Id: Ifb945e3be39fbedfd802c4d32de7de443cf53f49 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
-rw-r--r--ApiExtractor/abstractmetabuilder.cpp19
-rw-r--r--ApiExtractor/typedatabase.cpp88
-rw-r--r--ApiExtractor/typedatabase.h14
-rw-r--r--ApiExtractor/typesystem.cpp89
-rw-r--r--ApiExtractor/typesystem.h21
5 files changed, 168 insertions, 63 deletions
diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp
index ef6a480..13e1461 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;
}
@@ -2091,13 +2093,14 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
const QString originalQualifiedSignatureWithReturn =
qualifiedFunctionSignatureWithType(functionItem, className);
- if (TypeDatabase::instance()->isFunctionRejected(className, functionName)) {
- m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::GenerationDisabled);
+ 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))) {
- m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::GenerationDisabled);
+ functionSignature(functionItem), &rejectReason)) {
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
return 0;
}
diff --git a/ApiExtractor/typedatabase.cpp b/ApiExtractor/typedatabase.cpp
index 8530d15..b397f19 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,92 @@ 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;
+ }
+ 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) const
+bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName,
+ 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::Field, className, fieldName, reason);
}
FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const
diff --git a/ApiExtractor/typedatabase.h b/ApiExtractor/typedatabase.h
index 870002b..a4f8adc 100644
--- a/ApiExtractor/typedatabase.h
+++ b/ApiExtractor/typedatabase.h
@@ -100,12 +100,14 @@ 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;
void addType(TypeEntry* e);
diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp
index 33bd790..ed68161 100644
--- a/ApiExtractor/typesystem.cpp
+++ b/ApiExtractor/typesystem.cpp
@@ -48,9 +48,77 @@ 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 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}};
+
+ // 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 +1250,10 @@ 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());
break;
case StackElement::Removal:
attributes.insert(QLatin1String("class"), QLatin1String("all"));
@@ -1935,18 +2003,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..cc51250 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,23 @@ 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
+ };
+
+ 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