summaryrefslogtreecommitdiffstats
path: root/src/tools/moc/moc.cpp
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-02-23 11:12:58 +1000
committerQt by Nokia <qt-info@nokia.com>2012-02-27 00:18:53 +0100
commit5bb1408927b4eb5a03e8ab9f7cbc68f80d8a3962 (patch)
tree827b626deccbbf6e71668e6549ef4761ae7a22e8 /src/tools/moc/moc.cpp
parent4550f0db210258338c8d6261640d9f192c0d3db6 (diff)
Allow moc to handle symbols that have been redefined.
Allow moc to produce the desired identifiers when used with C++ symbol names that have been redefined, for example by -Dfoo=bar. Two changes are required: firstly, when encoding a type name, the components of the name must be checked for substitutions that have been defined for that token (note that this is not done here by correct pre-processing, but only by processing the resultant table of definitions). Secondly, the arguments to the SIGNAL, SLOT and METHOD macros must be allowed to be substituted during macro expansion rather than stringized directly. This is a temporary change to prevent breaking existing projects that depend on the declarative module. After clients have had an opportunity to update their code to the use the new interfaces, it can be removed. Task-number: QTBUG-23737 Change-Id: I39e6844cebf6ca7984af6028160b8a3797ac44a5 Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/tools/moc/moc.cpp')
-rw-r--r--src/tools/moc/moc.cpp110
1 files changed, 108 insertions, 2 deletions
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 7b358c1ae8..4189c29de1 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -304,7 +304,9 @@ void Moc::parseFunctionArguments(FunctionDef *def)
arg.rightType += lexem();
}
arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType));
+ arg.normalizedType = getTypeSubstitution(arg.normalizedType);
arg.typeNameForCast = normalizeType(QByteArray(noRef(arg.type.name) + "(*)" + arg.rightType));
+ arg.typeNameForCast = getTypeSubstitution(arg.typeNameForCast);
if (test(EQ))
arg.isDefault = true;
def->arguments += arg;
@@ -414,6 +416,7 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
}
def->normalizedType = normalizeType(def->type.name);
+ def->normalizedType = getTypeSubstitution(def->normalizedType);
if (!test(RPAREN)) {
parseFunctionArguments(def);
@@ -512,6 +515,7 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
}
def->normalizedType = normalizeType(def->type.name);
+ def->normalizedType = getTypeSubstitution(def->normalizedType);
if (!test(RPAREN)) {
parseFunctionArguments(def);
@@ -968,6 +972,7 @@ void Moc::createPropertyDef(PropertyDef &propDef)
QVariant.
*/
type = normalizeType(type);
+ type = getTypeSubstitution(type);
if (type == "QMap")
type = "QMap<QString,QVariant>";
else if (type == "QValueList")
@@ -1081,7 +1086,6 @@ void Moc::parseProperty(ClassDef *def)
createPropertyDef(propDef);
next(RPAREN);
-
if(!propDef.notify.isEmpty())
def->notifyableProperties++;
if (propDef.revision > 0)
@@ -1244,7 +1248,8 @@ void Moc::parseInterfaces(ClassDef *def)
}
// resolve from classnames to interface ids
for (int i = 0; i < iface.count(); ++i) {
- const QByteArray iid = interface2IdMap.value(iface.at(i).className);
+ QByteArray className = getTypeSubstitution(iface.at(i).className);
+ QByteArray iid = interface2IdMap.value(className);
if (iid.isEmpty())
error("Undefined interface");
@@ -1502,6 +1507,107 @@ void Moc::checkProperties(ClassDef *cdef)
}
}
+QByteArray Moc::getSubstitution(const QByteArray &token) const
+{
+ Macros::ConstIterator it = preprocessor.macros.find(token);
+ if (it != preprocessor.macros.end() && it->symbols.count() == 1) {
+ // We can only handle substitutions that result in a single symbol
+ return it->symbols.at(0).lexem();
+ }
+
+ return QByteArray();
+}
+
+QByteArray Moc::getTokenSubstitution(const QByteArray &token) const
+{
+ QByteArray result = token;
+
+ QSet<QByteArray> used;
+
+ // Process substitution chain until no replacement exists
+ QByteArray substitution = getSubstitution(result);
+ while (!substitution.isEmpty()) {
+ used.insert(result);
+ result = substitution;
+
+ if (used.contains(result)) {
+ break;
+ }
+
+ substitution = getSubstitution(result);
+ }
+
+ return result;
+}
+
+QByteArray Moc::getWordSubstitution(const QByteArray &word) const
+{
+ QByteArray result;
+
+ // A word can contain multiple components separated by '*'
+ int startIndex = 0;
+ do {
+ int index = word.indexOf('*', startIndex);
+ if (index == -1) {
+ result.append(getTokenSubstitution(word.mid(startIndex)));
+ } else {
+ result.append(getTokenSubstitution(word.mid(startIndex, (index - startIndex))));
+ result.append('*');
+ }
+
+ startIndex = index + 1;
+ } while (startIndex != 0);
+
+ return result;
+}
+
+QByteArray Moc::getNameSubstitution(const QByteArray &name) const
+{
+ QByteArray result;
+
+ // Parse multiple tokens in this name independently
+ int startIndex = 0;
+ do {
+ int index = name.indexOf(' ', startIndex);
+ if (index == -1) {
+ result.append(getWordSubstitution(name.mid(startIndex)));
+ } else {
+ result.append(getWordSubstitution(name.mid(startIndex, (index - startIndex))));
+ result.append(' ');
+ }
+
+ startIndex = index + 1;
+ } while (startIndex != 0);
+
+ return result;
+}
+
+QByteArray Moc::getTypeSubstitution(const QByteArray &typeName) const
+{
+ int index = typeName.indexOf('<');
+ if (index != -1) {
+ QByteArray templateName = typeName.left(index);
+
+ int lastIndex = typeName.lastIndexOf('>');
+ if (lastIndex > index) {
+ QByteArray result = getNameSubstitution(templateName);
+
+ // Parse the interior type independently
+ QByteArray parameter = typeName.mid(index + 1, (lastIndex - index - 1));
+ QByteArray interior = getTypeSubstitution(parameter);
+ if (interior.endsWith('>')) {
+ interior.append(' ');
+ }
+ result.append('<').append(interior).append(typeName.mid(lastIndex));
+ return result;
+ } else {
+ // Something is broken; return the input unmodified
+ return typeName;
+ }
+ }
+
+ return getNameSubstitution(typeName);
+}
QT_END_NAMESPACE