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.cpp645
1 files changed, 512 insertions, 133 deletions
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index 869904d43..4a8d3063d 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -32,6 +32,9 @@
#include "reporthandler.h"
#include <QtCore/QDir>
#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QSet>
#include <QtCore/QXmlStreamAttributes>
#include <QtCore/QXmlStreamReader>
@@ -44,11 +47,86 @@ 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 inline QString xPathAttribute() { return QStringLiteral("xpath"); }
+
+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)
@@ -101,18 +179,26 @@ Handler::Handler(TypeDatabase* database, bool generate)
tagNames.insert(QLatin1String("no-null-pointer"), StackElement::NoNullPointers);
tagNames.insert(QLatin1String("reference-count"), StackElement::ReferenceCount);
tagNames.insert(QLatin1String("parent"), StackElement::ParentOwner);
+ tagNames.insert(QLatin1String("array"), StackElement::Array);
tagNames.insert(QLatin1String("inject-documentation"), StackElement::InjectDocumentation);
tagNames.insert(QLatin1String("modify-documentation"), StackElement::ModifyDocumentation);
tagNames.insert(QLatin1String("add-function"), StackElement::AddFunction);
}
+static QString readerFileName(const QXmlStreamReader &reader)
+{
+ const QFile *file = qobject_cast<const QFile *>(reader.device());
+ return file != nullptr ? file->fileName() : QString();
+}
+
static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
{
QString message;
QTextStream str(&message);
str << "Error: ";
- if (const QFile *file = qobject_cast<const QFile *>(reader.device()))
- str << "file=" << QDir::toNativeSeparators(file->fileName()) << ", ";
+ const QString fileName = readerFileName(reader);
+ if (!fileName.isEmpty())
+ str << "file=" << QDir::toNativeSeparators(fileName) << ", ";
str << "line=" << reader.lineNumber() << ", column=" << reader.columnNumber()
<< ", message=" << what;
return message;
@@ -126,6 +212,11 @@ static QString msgReaderError(const QXmlStreamReader &reader)
bool Handler::parse(QXmlStreamReader &reader)
{
m_error.clear();
+ m_currentPath.clear();
+ const QString fileName = readerFileName(reader);
+ if (!fileName.isEmpty())
+ m_currentPath = QFileInfo(fileName).absolutePath();
+
while (!reader.atEnd()) {
switch (reader.readNext()) {
case QXmlStreamReader::NoToken:
@@ -209,8 +300,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()));
}
}
@@ -281,6 +373,7 @@ bool Handler::endElement(const QStringRef &localName)
m_current->parent->entry->setCodeSnips(snips);
break;
}
+ Q_FALLTHROUGH();
case StackElement::NativeToTarget:
case StackElement::AddConversion:
m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance);
@@ -493,7 +586,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, "
@@ -521,11 +615,10 @@ void Handler::addFlags(const QString &name, QString flagName,
if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != m_currentEnum->targetLangQualifier()) {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("enum %1 and flags %2 differ in qualifiers")
- // avoid constFirst to stay Qt 5.5 compatible
- .arg(m_currentEnum->targetLangQualifier(), lst.first());
+ .arg(m_currentEnum->targetLangQualifier(), lst.constFirst());
}
- ftype->setFlagsName(lst.last());
+ ftype->setFlagsName(lst.constLast());
m_currentEnum->setFlags(ftype);
m_database->addFlagsType(ftype);
@@ -663,20 +756,20 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
break;
case StackElement::ValueTypeEntry:
attributes.insert(QLatin1String("default-constructor"), QString());
- // fall throooough
+ Q_FALLTHROUGH();
case StackElement::ObjectTypeEntry:
attributes.insert(QLatin1String("force-abstract"), QLatin1String("no"));
attributes.insert(QLatin1String("deprecated"), QLatin1String("no"));
attributes.insert(QLatin1String("hash-function"), QString());
attributes.insert(QLatin1String("stream"), QLatin1String("no"));
- // fall throooough
+ Q_FALLTHROUGH();
case StackElement::InterfaceTypeEntry:
attributes[QLatin1String("default-superclass")] = m_defaultSuperclass;
attributes.insert(QLatin1String("polymorphic-id-expression"), QString());
attributes.insert(QLatin1String("delete-in-main-thread"), QLatin1String("no"));
attributes.insert(QLatin1String("held-type"), QString());
attributes.insert(QLatin1String("copyable"), QString());
- // fall through
+ Q_FALLTHROUGH();
case StackElement::NamespaceTypeEntry:
attributes.insert(QLatin1String("target-lang-name"), QString());
attributes[QLatin1String("package")] = m_defaultPackage;
@@ -725,14 +818,16 @@ 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;
}
- FunctionModification mod(since);
- mod.signature = signature;
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
mod.renamedToName = attributes[QLatin1String("rename")];
mod.modifiers |= Modification::Rename;
m_contextStack.top()->functionMods << mod;
@@ -837,7 +932,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
else
m_currentEnum =
new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join(colonColon()),
- names.last(), since);
+ names.constLast(), since);
m_currentEnum->setAnonymous(!attributes[QLatin1String("identified-by-value")].isEmpty());
element->entry = m_currentEnum;
m_currentEnum->setCodeGeneration(m_generate);
@@ -850,7 +945,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);
}
}
@@ -872,7 +968,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
itype->setOrigin(otype);
element->entry = otype;
}
- // fall through
+ Q_FALLTHROUGH();
case StackElement::ValueTypeEntry: {
if (!element->entry) {
ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since);
@@ -882,12 +978,12 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
element->entry = typeEntry;
}
- // fall through
+ Q_FALLTHROUGH();
case StackElement::NamespaceTypeEntry:
if (!element->entry)
element->entry = new NamespaceTypeEntry(name, since);
- // fall through
+ Q_FALLTHROUGH();
case StackElement::ObjectTypeEntry:
if (!element->entry)
element->entry = new ObjectTypeEntry(name, since);
@@ -908,16 +1004,6 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
if (!targetLangName.isEmpty())
ctype->setTargetLangName(targetLangName);
- // The expense policy
- QString limit = attributes[QLatin1String("expense-limit")];
- if (!limit.isEmpty() && limit != QLatin1String("none")) {
- ExpensePolicy ep;
- ep.limit = limit.toInt();
- ep.cost = attributes[QLatin1String("expense-cost")];
- ctype->setExpensePolicy(ep);
- }
-
-
ctype->setIsPolymorphicBase(convertBoolean(attributes[QLatin1String("polymorphic-base")], QLatin1String("polymorphic-base"), false));
ctype->setPolymorphicIdValue(attributes[QLatin1String("polymorphic-id-expression")]);
//Copyable
@@ -1001,7 +1087,6 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
attributes.insert(sinceAttribute(), QLatin1String("0"));
fetchAttributeValues(tagName, atts, &attributes);
- double since = attributes[sinceAttribute()].toDouble();
const int validParent = StackElement::TypeEntryMask
| StackElement::ModifyFunction
@@ -1034,8 +1119,8 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
QString signature = m_current->type & StackElement::TypeEntryMask ? QString() : m_currentSignature;
- DocModification mod(mode, signature, since);
- mod.format = lang;
+ DocModification mod(mode, signature);
+ mod.setFormat(lang);
m_contextStack.top()->docModifications << mod;
} else {
m_error = QLatin1String("inject-documentation must be inside modify-function, "
@@ -1045,17 +1130,17 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
} else if (element->type == StackElement::ModifyDocumentation) {
// check the XML tag attributes
QHash<QString, QString> attributes;
- attributes.insert(QLatin1String("xpath"), QString());
+ attributes.insert(xPathAttribute(), QString());
attributes.insert(sinceAttribute(), QLatin1String("0"));
fetchAttributeValues(tagName, atts, &attributes);
- double since = attributes[sinceAttribute()].toDouble();
const int validParent = StackElement::TypeEntryMask
| StackElement::ModifyFunction
| StackElement::ModifyField;
if (m_current->parent && m_current->parent->type & validParent) {
QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
- m_contextStack.top()->docModifications << DocModification(attributes[QLatin1String("xpath")], signature, since);
+ m_contextStack.top()->docModifications
+ << DocModification(attributes.value(xPathAttribute()), signature);
} else {
m_error = QLatin1String("modify-documentation must be inside modify-function, "
"modify-field or other tags that creates a type");
@@ -1095,7 +1180,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 +1262,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"));
@@ -1202,6 +1289,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
case StackElement::ParentOwner:
attributes.insert(QLatin1String("index"), QString());
attributes.insert(QLatin1String("action"), QString());
+ break;
+ case StackElement::Array:
+ break;
default:
{ };
};
@@ -1238,19 +1328,18 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
return false;
}
bool generateChild = (convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true) && (m_generate == TypeEntry::GenerateAll));
- if (!m_database->parseFile(name, generateChild)) {
+ if (!m_database->parseFile(name, m_currentPath, generateChild)) {
m_error = QStringLiteral("Failed to parse: '%1'").arg(name);
return false;
}
}
break;
- case StackElement::RejectEnumValue: {
+ case StackElement::RejectEnumValue:
if (!m_currentEnum) {
m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
return false;
}
- QString name = attributes[nameAttribute()];
- } break;
+ break;
case StackElement::ReplaceType: {
if (topElement.type != StackElement::ModifyArgument) {
m_error = QLatin1String("Type replacement can only be specified for argument modifications");
@@ -1290,7 +1379,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
return false;
}
- CodeSnip snip(since);
+ CodeSnip snip;
snip.language = lang;
m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
} else {
@@ -1332,7 +1421,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules.");
return false;
}
- m_contextStack.top()->codeSnips << CodeSnip(0);
+ m_contextStack.top()->codeSnips << CodeSnip();
}
break;
case StackElement::TargetToNative: {
@@ -1356,7 +1445,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
QString typeCheck = attributes[QLatin1String("check")];
static_cast<TypeEntry*>(m_current->entry)->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
- m_contextStack.top()->codeSnips << CodeSnip(0);
+ m_contextStack.top()->codeSnips << CodeSnip();
}
break;
case StackElement::ModifyArgument: {
@@ -1388,7 +1477,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
return false;
}
- ArgumentModification argumentModification = ArgumentModification(idx, since);
+ ArgumentModification argumentModification = ArgumentModification(idx);
argumentModification.replace_value = replace_value;
argumentModification.resetAfterUse = convertBoolean(attributes[QLatin1String("invalidate-after-use")], QLatin1String("invalidate-after-use"), false);
m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
@@ -1444,11 +1533,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)) {
@@ -1632,8 +1725,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
m_contextStack.top()->addedFunctions << func;
- FunctionModification mod(since);
- mod.signature = m_currentSignature;
+ FunctionModification mod;
+ if (!mod.setSignature(m_currentSignature, &m_error))
+ return false;
m_contextStack.top()->functionMods << mod;
}
break;
@@ -1657,8 +1751,10 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
return false;
}
- FunctionModification mod(since);
- m_currentSignature = mod.signature = signature;
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ m_currentSignature = signature;
QString access = attributes[QLatin1String("access")].toLower();
if (!access.isEmpty()) {
@@ -1746,8 +1842,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);
@@ -1790,8 +1886,13 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
}
break;
-
-
+ case StackElement::Array:
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("array must be child of modify-argument");
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().array = true;
+ break;
case StackElement::InjectCode: {
if (!(topElement.type & StackElement::ComplexTypeEntryMask)
&& (topElement.type != StackElement::AddFunction)
@@ -1837,7 +1938,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
return false;
}
- CodeSnip snip(since);
+ CodeSnip snip;
snip.language = languageNames[className];
snip.position = positionNames[position];
bool in_file = false;
@@ -1848,8 +1949,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
if (m_generate != TypeEntry::GenerateForSubclass &&
m_generate != TypeEntry::GenerateNothing &&
!file_name.isEmpty()) {
- if (QFile::exists(file_name)) {
- QFile codeFile(file_name);
+ const QString resolved = m_database->modifiedTypesystemFilepath(file_name, m_currentPath);
+ if (QFile::exists(resolved)) {
+ QFile codeFile(resolved);
if (codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
QString content = QLatin1String("// ========================================================================\n"
"// START of custom code block [file: ");
@@ -1875,7 +1977,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
if (topElement.type == StackElement::ModifyFunction || topElement.type == StackElement::AddFunction) {
- FunctionModification mod = m_contextStack.top()->functionMods.last();
+ FunctionModification mod = m_contextStack.top()->functionMods.constLast();
if (snip.language == TypeSystem::ShellDeclaration) {
m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
return false;
@@ -1930,21 +2032,12 @@ 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);
+ element->value.templateEntry = new TemplateEntry(attributes.value(nameAttribute()));
break;
case StackElement::TemplateInstanceEnum:
if (!(topElement.type & StackElement::CodeSnipMask) &&
@@ -1958,7 +2051,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
"custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
return false;
}
- element->value.templateInstance = new TemplateInstance(attributes[nameAttribute()], since);
+ element->value.templateInstance = new TemplateInstance(attributes.value(nameAttribute()));
break;
case StackElement::Replace:
if (topElement.type != StackElement::TemplateInstanceEnum) {
@@ -1976,6 +2069,23 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
return true;
}
+PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &name, double vr) :
+ TypeEntry(name, PrimitiveType, vr),
+ m_preferredConversion(true),
+ m_preferredTargetLangType(true)
+{
+}
+
+QString PrimitiveTypeEntry::targetLangName() const
+{
+ return m_targetLangName;
+}
+
+QString PrimitiveTypeEntry::targetLangApiName() const
+{
+ return m_targetLangApiName;
+}
+
PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const
{
if (!m_referencedTypeEntry)
@@ -1988,6 +2098,16 @@ PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const
return m_referencedTypeEntry;
}
+bool PrimitiveTypeEntry::preferredConversion() const
+{
+ return m_preferredConversion;
+}
+
+void PrimitiveTypeEntry::setPreferredConversion(bool b)
+{
+ m_preferredConversion = b;
+}
+
typedef QHash<const PrimitiveTypeEntry*, QString> PrimitiveTypeEntryTargetLangPackageMap;
Q_GLOBAL_STATIC(PrimitiveTypeEntryTargetLangPackageMap, primitiveTypeEntryTargetLangPackages);
@@ -2021,7 +2141,7 @@ FunctionModificationList ComplexTypeEntry::functionModifications(const QString &
FunctionModificationList lst;
for (int i = 0; i < m_functionMods.count(); ++i) {
const FunctionModification &mod = m_functionMods.at(i);
- if (mod.signature == signature)
+ if (mod.matches(signature))
lst << mod;
}
return lst;
@@ -2038,6 +2158,17 @@ FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
return mod;
}
+QString ComplexTypeEntry::targetLangPackage() const
+{
+ return m_package;
+}
+
+QString ComplexTypeEntry::targetLangName() const
+{
+ return m_targetLangName.isEmpty() ?
+ TypeEntry::targetLangName() : m_targetLangName;
+}
+
// The things we do not to break the ABI...
typedef QHash<const ComplexTypeEntry*, QString> ComplexTypeEntryDefaultConstructorMap;
Q_GLOBAL_STATIC(ComplexTypeEntryDefaultConstructorMap, complexTypeEntryDefaultConstructors);
@@ -2102,16 +2233,46 @@ QString EnumTypeEntry::targetLangQualifier() const
return m_qualifier;
}
+QString EnumTypeEntry::qualifiedTargetLangName() const
+{
+ QString qualifiedName;
+ QString pkg = targetLangPackage();
+ QString qualifier = targetLangQualifier();
+
+ if (!pkg.isEmpty())
+ qualifiedName += pkg + QLatin1Char('.');
+ if (!qualifier.isEmpty())
+ qualifiedName += qualifier + QLatin1Char('.');
+ qualifiedName += targetLangName();
+
+ return qualifiedName;
+}
+
QString EnumTypeEntry::targetLangApiName() const
{
return QLatin1String("jint");
}
+bool EnumTypeEntry::preferredConversion() const
+{
+ return false;
+}
+
QString FlagsTypeEntry::targetLangApiName() const
{
return QLatin1String("jint");
}
+bool FlagsTypeEntry::preferredConversion() const
+{
+ return false;
+}
+
+QString FlagsTypeEntry::targetLangPackage() const
+{
+ return m_enum->targetLangPackage();
+}
+
void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue)
{
m_enumRedirections << EnumValueRedirection(rejected, usedValue);
@@ -2131,6 +2292,11 @@ QString FlagsTypeEntry::qualifiedTargetLangName() const
+ QLatin1Char('.') + targetLangName();
}
+QString FlagsTypeEntry::targetLangName() const
+{
+ return m_targetLangName;
+}
+
/*!
* The Visual Studio 2002 compiler doesn't support these symbols,
* which our typedefs unforntuatly expand to.
@@ -2172,7 +2338,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;
@@ -2186,9 +2352,26 @@ QString CodeSnipFragment::code() const
return m_code;
}
+bool FunctionModification::setSignature(const QString &s, QString *errorMessage)
+{
+ if (s.startsWith(QLatin1Char('^'))) {
+ m_signaturePattern.setPattern(s);
+ if (!m_signaturePattern.isValid()) {
+ if (errorMessage) {
+ *errorMessage = QLatin1String("Invalid signature pattern: \"")
+ + s + QLatin1String("\": ") + m_signaturePattern.errorString();
+ }
+ return false;
+ }
+ } else {
+ m_signature = s;
+ }
+ return true;
+}
+
QString FunctionModification::toString() const
{
- QString str = signature + QLatin1String("->");
+ QString str = signature() + QLatin1String("->");
if (modifiers & AccessModifierMask) {
switch (modifiers & AccessModifierMask) {
case Private: str += QLatin1String("private"); break;
@@ -2205,7 +2388,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();
}
@@ -2220,41 +2403,11 @@ QString FunctionModification::toString() const
return str;
}
-bool FunctionModification::operator!=(const FunctionModification& other) const
-{
- return !(*this == other);
-}
-
-bool FunctionModification::operator==(const FunctionModification& other) const
-{
- if (signature != other.signature)
- return false;
-
- if (association != other.association)
- return false;
-
- if (modifiers != other.modifiers)
- return false;
-
- if (removal != other.removal)
- return false;
-
- if (m_thread != other.m_thread)
- return false;
-
- if (m_allowThread != other.m_allowThread)
- return false;
-
- if (m_version != other.m_version)
- return false;
-
- return true;
-}
-
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) {
@@ -2318,7 +2471,9 @@ static AddedFunction::TypeInfo parseType(const QString& signature, int startPos
return result;
}
-AddedFunction::AddedFunction(QString signature, QString returnType, double vr) : m_access(Public), m_version(vr)
+AddedFunction::AddedFunction(QString signature, QString returnType, double vr) :
+ m_version(vr),
+ m_access(Public)
{
Q_ASSERT(!returnType.isEmpty());
m_returnType = parseType(returnType);
@@ -2339,7 +2494,7 @@ AddedFunction::AddedFunction(QString signature, QString returnType, double vr) :
break;
}
// is const?
- m_isConst = signature.right(signatureLength - endPos).contains(QLatin1String("const"));
+ m_isConst = signature.rightRef(signatureLength - endPos).contains(QLatin1String("const"));
}
}
@@ -2385,6 +2540,25 @@ AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& si
return parseType(signature);
}
+ComplexTypeEntry::ComplexTypeEntry(const QString &name, TypeEntry::Type t, double vr) :
+ TypeEntry(QString(name).replace(QLatin1String(".*::"), QString()), t, vr),
+ m_qualifiedCppName(name),
+ m_qobject(false),
+ m_polymorphicBase(false),
+ m_genericClass(false)
+{
+}
+
+bool ComplexTypeEntry::isComplex() const
+{
+ return true;
+}
+
+QString ComplexTypeEntry::lookupName() const
+{
+ return m_lookupName.isEmpty() ? targetLangName() : m_lookupName;
+}
+
QString ComplexTypeEntry::targetLangApiName() const
{
return strings_jobject;
@@ -2401,6 +2575,18 @@ QString StringTypeEntry::targetLangPackage() const
{
return QString();
}
+
+bool StringTypeEntry::isNativeIdBased() const
+{
+ return false;
+}
+
+CharTypeEntry::CharTypeEntry(const QString &name, double vr) :
+ ValueTypeEntry(name, CharType, vr)
+{
+ setCodeGeneration(GenerateNothing);
+}
+
QString CharTypeEntry::targetLangApiName() const
{
return strings_jchar;
@@ -2409,6 +2595,22 @@ QString CharTypeEntry::targetLangName() const
{
return strings_char;
}
+
+QString CharTypeEntry::targetLangPackage() const
+{
+ return QString();
+}
+
+bool CharTypeEntry::isNativeIdBased() const
+{
+ return false;
+}
+
+VariantTypeEntry::VariantTypeEntry(const QString &name, double vr) :
+ ValueTypeEntry(name, VariantType, vr)
+{
+}
+
QString VariantTypeEntry::targetLangApiName() const
{
return strings_jobject;
@@ -2422,6 +2624,11 @@ QString VariantTypeEntry::targetLangPackage() const
return QString();
}
+bool VariantTypeEntry::isNativeIdBased() const
+{
+ return false;
+}
+
QString ContainerTypeEntry::typeName() const
{
switch(m_type) {
@@ -2455,9 +2662,19 @@ QString ContainerTypeEntry::typeName() const
}
}
-static bool strLess(const char* a, const char* b)
+static const QSet<QString> &primitiveCppTypes()
{
- return ::strcmp(a, b) < 0;
+ static QSet<QString> result;
+ if (result.isEmpty()) {
+ static const char *cppTypes[] = {
+ "bool", "char", "double", "float", "int",
+ "long", "long long", "short",
+ "wchar_t"
+ };
+ for (const char *cppType : cppTypes)
+ result.insert(QLatin1String(cppType));
+ }
+ return result;
}
bool TypeEntry::isCppPrimitive() const
@@ -2465,25 +2682,26 @@ bool TypeEntry::isCppPrimitive() const
if (!isPrimitive())
return false;
- const PrimitiveTypeEntry *referencedType =
- static_cast<const PrimitiveTypeEntry *>(this)->basicReferencedTypeEntry();
- QByteArray typeName = (referencedType ? referencedType->name() : m_name).toUtf8();
-
- if (typeName.contains(' ') || m_type == VoidType)
+ if (m_type == VoidType)
return true;
- // Keep this sorted!!
- static const char* cppTypes[] = { "bool", "char", "double", "float", "int", "long", "long long", "short", "wchar_t" };
- const int N = sizeof(cppTypes)/sizeof(char*);
-
- const char** res = qBinaryFind(&cppTypes[0], &cppTypes[N], typeName.constData(), strLess);
- return res != &cppTypes[N];
+ const PrimitiveTypeEntry *referencedType =
+ static_cast<const PrimitiveTypeEntry *>(this)->basicReferencedTypeEntry();
+ const QString &typeName = referencedType ? referencedType->name() : m_name;
+ return typeName.contains(QLatin1Char(' ')) || primitiveCppTypes().contains(typeName);
}
// Again, stuff to avoid ABI breakage.
typedef QHash<const TypeEntry*, CustomConversion*> TypeEntryCustomConversionMap;
Q_GLOBAL_STATIC(TypeEntryCustomConversionMap, typeEntryCustomConversionMap);
+TypeEntry::TypeEntry(const QString &name, TypeEntry::Type t, double vr) :
+ m_name(name),
+ m_type(t),
+ m_version(vr)
+{
+}
+
TypeEntry::~TypeEntry()
{
if (typeEntryCustomConversionMap()->contains(this)) {
@@ -2511,6 +2729,131 @@ CustomConversion* TypeEntry::customConversion() const
return 0;
}
+TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &name, double vr) :
+ TypeEntry(name, TypeSystemType, vr)
+{
+}
+
+VoidTypeEntry::VoidTypeEntry() :
+ TypeEntry(QLatin1String("void"), VoidType, 0)
+{
+}
+
+VarargsTypeEntry::VarargsTypeEntry() :
+ TypeEntry(QLatin1String("..."), VarargsType, 0)
+{
+}
+
+TemplateArgumentEntry::TemplateArgumentEntry(const QString &name, double vr) :
+ TypeEntry(name, TemplateArgumentType, vr)
+{
+}
+
+ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, double vr) :
+ TypeEntry(QLatin1String("Array"), ArrayType, vr),
+ m_nestedType(nested_type)
+{
+ Q_ASSERT(m_nestedType);
+}
+
+QString ArrayTypeEntry::targetLangName() const
+{
+ return m_nestedType->targetLangName() + QLatin1String("[]");
+}
+
+QString ArrayTypeEntry::targetLangApiName() const
+{
+ if (m_nestedType->isPrimitive())
+ return m_nestedType->targetLangApiName() + QLatin1String("Array");
+ else
+ return QLatin1String("jobjectArray");
+}
+
+EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName, double vr) :
+ TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName,
+ EnumType, vr),
+ m_qualifier(nspace),
+ m_targetLangName(enumName)
+{
+}
+
+QString EnumTypeEntry::targetLangPackage() const
+{
+ return m_packageName;
+}
+
+void EnumTypeEntry::setTargetLangPackage(const QString &package)
+{
+ m_packageName = package;
+}
+
+QString EnumTypeEntry::targetLangName() const
+{
+ return m_targetLangName;
+}
+
+EnumValueTypeEntry::EnumValueTypeEntry(const QString& name, const QString& value, const EnumTypeEntry* enclosingEnum, double vr) :
+ TypeEntry(name, TypeEntry::EnumValue, vr),
+ m_value(value),
+ m_enclosingEnum(enclosingEnum)
+{
+}
+
+FlagsTypeEntry::FlagsTypeEntry(const QString &name, double vr) :
+ TypeEntry(name, FlagsType, vr)
+{
+}
+
+ContainerTypeEntry::ContainerTypeEntry(const QString &name, Type type, double vr) :
+ ComplexTypeEntry(name, ContainerType, vr),
+ m_type(type)
+{
+ setCodeGeneration(GenerateForSubclass);
+}
+
+SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &name,
+ const QString &getterName,
+ const QString &smartPointerType,
+ const QString &refCountMethodName,
+ double vr) :
+ ComplexTypeEntry(name, SmartPointerType, vr),
+ m_getterName(getterName),
+ m_smartPointerType(smartPointerType),
+ m_refCountMethodName(refCountMethodName)
+{
+}
+
+NamespaceTypeEntry::NamespaceTypeEntry(const QString &name, double vr) :
+ ComplexTypeEntry(name, NamespaceType, vr)
+{
+}
+
+ValueTypeEntry::ValueTypeEntry(const QString &name, double vr) :
+ ComplexTypeEntry(name, BasicValueType, vr)
+{
+}
+
+bool ValueTypeEntry::isValue() const
+{
+ return true;
+}
+
+bool ValueTypeEntry::isNativeIdBased() const
+{
+ return true;
+}
+
+ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, double vr) :
+ ComplexTypeEntry(name, t, vr)
+{
+}
+
+StringTypeEntry::StringTypeEntry(const QString &name, double vr) :
+ ValueTypeEntry(name, StringType, vr)
+{
+ setCodeGeneration(GenerateNothing);
+}
+
/*
static void injectCode(ComplexTypeEntry *e,
const char *signature,
@@ -2563,9 +2906,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;
}
@@ -2665,3 +3006,41 @@ void CustomConversion::TargetToNativeConversion::setConversion(const QString& co
{
m_d->conversion = conversion;
}
+
+InterfaceTypeEntry::InterfaceTypeEntry(const QString &name, double vr) :
+ ComplexTypeEntry(name, InterfaceType, vr)
+{
+}
+
+bool InterfaceTypeEntry::isNativeIdBased() const
+{
+ return true;
+}
+
+QString InterfaceTypeEntry::qualifiedCppName() const
+{
+ const int len = ComplexTypeEntry::qualifiedCppName().length() - interfaceName(QString()).length();
+ return ComplexTypeEntry::qualifiedCppName().left(len);
+}
+
+FunctionTypeEntry::FunctionTypeEntry(const QString &name, const QString &signature,
+ double vr) :
+ TypeEntry(name, FunctionType, vr)
+{
+ addSignature(signature);
+}
+
+ObjectTypeEntry::ObjectTypeEntry(const QString &name, double vr)
+ : ComplexTypeEntry(name, ObjectType, vr)
+{
+}
+
+InterfaceTypeEntry *ObjectTypeEntry::designatedInterface() const
+{
+ return m_interface;
+}
+
+bool ObjectTypeEntry::isNativeIdBased() const
+{
+ return true;
+}