From 1c4dc6be0c5b6a730e5ae910afa8c4da986e37ee Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Sep 2009 12:47:45 +0200 Subject: drastically improve lupdate's scalability do not import all data from included files into the current file (which turned out to be extremely expensive for 3rdparty/webkit), but do hierarchical lookups on demand. this makes the lookups as such much slower, of course, but it still pays off. --- tools/linguist/lupdate/cpp.cpp | 477 ++++++++++++++++++++++++----------------- 1 file changed, 280 insertions(+), 197 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index d5d2e10..c9b25f3 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -43,6 +43,7 @@ #include +#include #include #include #include @@ -62,53 +63,110 @@ static QString MagicComment(QLatin1String("TRANSLATOR")); //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this -uint qHash(const QStringList &qsl) +class HashString { +public: + HashString() : m_hashed(false) {} + explicit HashString(const QString &str) : m_str(str), m_hashed(false) {} + void setValue(const QString &str) { m_str = str; m_hashed = false; } + const QString &value() const { return m_str; } + bool operator==(const HashString &other) const { return m_str == other.m_str; } +private: + QString m_str; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashString &str); +}; + +uint qHash(const HashString &str) +{ + if (!str.m_hashed) { + str.m_hashed = true; + str.m_hash = qHash(str.m_str); + } + return str.m_hash; +} + +class HashStringList { +public: + explicit HashStringList(const QList &list) : m_list(list), m_hashed(false) {} + const QList &value() const { return m_list; } + bool operator==(const HashStringList &other) const { return m_list == other.m_list; } +private: + QList m_list; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashStringList &list); +}; + +uint qHash(const HashStringList &list) { - uint hash = 0; - foreach (const QString &qs, qsl) { - hash ^= qHash(qs) ^ 0xa09df22f; - hash = (hash << 13) | (hash >> 19); + if (!list.m_hashed) { + list.m_hashed = true; + uint hash = 0; + foreach (const HashString &qs, list.m_list) { + hash ^= qHash(qs) ^ 0xa09df22f; + hash = (hash << 13) | (hash >> 19); + } + list.m_hash = hash; } - return hash; + return list.m_hash; } +typedef QList NamespaceList; + struct Namespace { Namespace() : - isClass(false), + classDef(0), hasTrFunctions(false), complained(false) {} - QString name; - QMap children; - QMap aliases; - QSet usings; - - int fileId; + QHash children; + QHash aliases; + QList usings; - bool isClass; + // Class declarations set no flags and create no namespaces, so they are ignored. + // Class definitions may appear multiple times - but only because we are trying to + // "compile" all sources irrespective of build configuration. + // Nested classes may be forward-declared inside a definition, and defined in another file. + // The latter will detach the class' child list, so clones need a backlink to the original + // definition (either one in case of multiple definitions). + Namespace *classDef; bool hasTrFunctions; bool complained; // ... that tr functions are missing. }; -typedef QList NamespaceList; +static int nextFileId; + +class VisitRecorder { +public: + VisitRecorder() + { + m_ba.resize(nextFileId); + } + bool tryVisit(int fileId) + { + if (m_ba.at(fileId)) + return false; + m_ba[fileId] = true; + return true; + } +private: + QBitArray m_ba; +}; struct ParseResults { ParseResults() { - static int nextFileId; - rootNamespace.fileId = nextFileId++; tor = 0; } - bool detachNamespace(Namespace **that); - Namespace *include(Namespace *that, const Namespace *other); - void unite(const ParseResults *other); + int fileId; Namespace rootNamespace; Translator *tor; - QSet allIncludes; + QSet includes; }; typedef QHash ParseResultHash; @@ -117,7 +175,7 @@ class CppFiles { public: static const ParseResults *getResults(const QString &cleanFile); - static void setResults(const QString &cleanFile, const ParseResults *results); + static void setResults(const QString &cleanFile, ParseResults *results); static bool isBlacklisted(const QString &cleanFile); static void setBlacklisted(const QString &cleanFile); @@ -135,13 +193,13 @@ public: void setTranslator(Translator *tor) { results->tor = tor; } void parse(const QString &initialContext, ConversionData &cd, QSet &inclusions); void parseInternal(ConversionData &cd, QSet &inclusions); - const ParseResults *getResults() const { return results; } + ParseResults *getResults() const { return results; } void deleteResults() { delete results; } struct SavedState { - QStringList namespaces; + NamespaceList namespaces; QStack namespaceDepths; - QStringList functionContext; + NamespaceList functionContext; QString functionContextUnresolved; QString pendingContext; }; @@ -183,15 +241,28 @@ private: static QString stringifyNamespace(const NamespaceList &namespaces); static QStringList stringListifyNamespace(const NamespaceList &namespaces); - void modifyNamespace(NamespaceList *namespaces); - NamespaceList resolveNamespaces(const QStringList &segments); - bool qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved); - bool fullyQualify(const NamespaceList &namespaces, const QStringList &segments, + typedef bool (CppParser::*VisitNamespaceCallback)(const Namespace *ns, void *context) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const; + static QStringList stringListifySegments(const QList &namespaces); + bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; + bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; + bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QList &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved); - void enterNamespace(NamespaceList *namespaces, const QString &name); + NamespaceList *resolved, QStringList *unresolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QString &segments, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const; + bool findNamespaceCallback(const Namespace *ns, void *context) const; + const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; + void enterNamespace(NamespaceList *namespaces, const HashString &name, bool isClass); void truncateNamespaces(NamespaceList *namespaces, int lenght); + Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true); enum { Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, @@ -837,85 +908,40 @@ uint CppParser::getToken() void CppParser::saveState(SavedState *state) { - state->namespaces = stringListifyNamespace(namespaces); + state->namespaces = namespaces; state->namespaceDepths = namespaceDepths; - state->functionContext = stringListifyNamespace(functionContext); + state->functionContext = functionContext; state->functionContextUnresolved = functionContextUnresolved; state->pendingContext = pendingContext; } void CppParser::loadState(const SavedState *state) { - namespaces = resolveNamespaces(state->namespaces); + namespaces = state->namespaces; namespaceDepths = state->namespaceDepths; - functionContext = resolveNamespaces(state->functionContext); + functionContext = state->functionContext; functionContextUnresolved = state->functionContextUnresolved; pendingContext = state->pendingContext; } -bool ParseResults::detachNamespace(Namespace **that) -{ - if ((*that)->fileId != rootNamespace.fileId) { - Namespace *newThat = new Namespace; - *newThat = **that; - newThat->fileId = rootNamespace.fileId; - *that = newThat; - return true; - } - return false; -} - -Namespace *ParseResults::include(Namespace *that, const Namespace *other) +Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) { - Namespace *origThat = that; - foreach (Namespace *otherSub, other->children) { - if (Namespace *thisSub = that->children.value(otherSub->name)) { - // Don't make these cause a detach - it's best - // (though not necessary) if they are shared - thisSub->isClass |= otherSub->isClass; - thisSub->hasTrFunctions |= otherSub->hasTrFunctions; - thisSub->complained |= otherSub->complained; - - if (Namespace *newSub = include(thisSub, otherSub)) { - thisSub = newSub; - detachNamespace(&that); - that->children[thisSub->name] = thisSub; - } - } else { - detachNamespace(&that); - that->children[otherSub->name] = otherSub; - } - } - if ((that->aliases != other->aliases && !other->aliases.isEmpty()) - || (that->usings != other->usings && !other->usings.isEmpty())) { - detachNamespace(&that); - that->aliases.unite(other->aliases); - that->usings.unite(other->usings); - } - return (that != origThat) ? that : 0; -} - -void ParseResults::unite(const ParseResults *other) -{ - allIncludes.unite(other->allIncludes); - include(&rootNamespace, &other->rootNamespace); -} - -void CppParser::modifyNamespace(NamespaceList *namespaces) -{ - Namespace *pns = 0; - int i = namespaces->count(); - forever { - --i; - Namespace *ns = namespaces->at(i); - bool detached = results->detachNamespace(&ns); - if (pns) - ns->children[pns->name] = pns; - if (!detached) // Known to be true for root namespace - return; + Namespace *pns, *ns = &results->rootNamespace; + for (int i = 1; i < namespaces->count(); ++i) { pns = ns; - namespaces->replace(i, ns); + if (!(ns = pns->children.value(namespaces->at(i)))) { + do { + ns = new Namespace; + if (tryOrigin) + if (const Namespace *ons = findNamespace(*namespaces, i + 1)) + ns->classDef = ons->classDef; + pns->children.insert(namespaces->at(i), ns); + pns = ns; + } while (++i < namespaces->count()); + break; + } } + return ns; } QString CppParser::stringifyNamespace(const NamespaceList &namespaces) @@ -924,7 +950,7 @@ QString CppParser::stringifyNamespace(const NamespaceList &namespaces) for (int i = 1; i < namespaces.count(); ++i) { if (i > 1) ret += QLatin1String("::"); - ret += namespaces.at(i)->name; + ret += namespaces.at(i).value(); } return ret; } @@ -933,58 +959,102 @@ QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) { QStringList ret; for (int i = 1; i < namespaces.count(); ++i) - ret << namespaces.at(i)->name; + ret << namespaces.at(i).value(); return ret; } -// This function is called only with known-existing namespaces -NamespaceList CppParser::resolveNamespaces(const QStringList &segments) +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const { - NamespaceList ret; - Namespace *ns = &results->rootNamespace; - ret << ns; - foreach (const QString &seg, segments) { - ns = ns->children.value(seg); - ret << ns; - } + const Namespace *ns = &rslt->rootNamespace; + for (int i = 1; i < nsCount; ++i) + if (!(ns = ns->children.value(namespaces.at(i)))) + goto supers; + if ((this->*callback)(ns, context)) + return true; +supers: + foreach (const ParseResults *sup, rslt->includes) + if (vr.tryVisit(sup->fileId) + && visitNamespace(namespaces, nsCount, callback, context, vr, sup)) + return true; + return false; +} + +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const +{ + VisitRecorder vr; + return visitNamespace(namespaces, nsCount, callback, context, vr, results); +} + +QStringList CppParser::stringListifySegments(const QList &segments) +{ + QStringList ret; + for (int i = 0; i < segments.count(); ++i) + ret << segments.at(i).value(); return ret; } -bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved) +struct QualifyOneData { + const NamespaceList &namespaces; + int nsCount; + const HashString &segment; + NamespaceList *resolved; + QSet visitedUsings; +}; + +bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const { - const Namespace *ns = namespaces.at(nsIdx); - QMap::ConstIterator cnsi = ns->children.constFind(segment); - if (cnsi != ns->children.constEnd()) { - *resolved = namespaces.mid(0, nsIdx + 1); - *resolved << *cnsi; + QualifyOneData *data = (QualifyOneData *)context; + if (ns->children.contains(data->segment)) { + *data->resolved = data->namespaces.mid(0, data->nsCount); + *data->resolved << data->segment; return true; } - QMap::ConstIterator nsai = ns->aliases.constFind(segment); + QHash::ConstIterator nsai = ns->aliases.constFind(data->segment); if (nsai != ns->aliases.constEnd()) { - *resolved = resolveNamespaces(*nsai); + *data->resolved = *nsai; return true; } - foreach (const QStringList &use, ns->usings) { - NamespaceList usedNs = resolveNamespaces(use); - if (qualifyOne(usedNs, usedNs.count() - 1, segment, resolved)) - return true; - } return false; } -bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList &segments, +bool CppParser::qualifyOneCallbackUsing(const Namespace *ns, void *context) const +{ + QualifyOneData *data = (QualifyOneData *)context; + foreach (const HashStringList &use, ns->usings) + if (!data->visitedUsings.contains(use)) { + data->visitedUsings.insert(use); + if (qualifyOne(use.value(), use.value().count(), data->segment, data->resolved)) + return true; + } + return false; +} + +bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const +{ + QualifyOneData data = { namespaces, nsCnt, segment, resolved, QSet() }; + + if (visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackOwn, &data)) + return true; + + return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data); +} + +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) + NamespaceList *resolved, QStringList *unresolved) const { int nsIdx; int initSegIdx; - if (segments.first().isEmpty()) { + if (segments.first().value().isEmpty()) { // fully qualified if (segments.count() == 1) { resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); return true; } initSegIdx = 1; @@ -995,12 +1065,12 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } do { - if (qualifyOne(namespaces, nsIdx, segments[initSegIdx], resolved)) { + if (qualifyOne(namespaces, nsIdx + 1, segments[initSegIdx], resolved)) { int segIdx = initSegIdx; while (++segIdx < segments.count()) { - if (!qualifyOne(*resolved, resolved->count() - 1, segments[segIdx], resolved)) { + if (!qualifyOne(*resolved, resolved->count(), segments[segIdx], resolved)) { if (unresolved) - *unresolved = segments.mid(segIdx); + *unresolved = stringListifySegments(segments.mid(segIdx)); return false; } } @@ -1008,23 +1078,47 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } } while (!isDeclaration && --nsIdx >= 0); resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); if (unresolved) - *unresolved = segments.mid(initSegIdx); + *unresolved = stringListifySegments(segments.mid(initSegIdx)); return false; } -void CppParser::enterNamespace(NamespaceList *namespaces, const QString &name) +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const +{ + static QString strColons(QLatin1String("::")); + + QList segments; + foreach (const QString &str, quali.split(strColons)) // XXX slow, but needs to be fast(?) + segments << HashString(str); + return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved); +} + +bool CppParser::findNamespaceCallback(const Namespace *ns, void *context) const { - Namespace *ns = namespaces->last()->children.value(name); - if (!ns) { - ns = new Namespace; - ns->fileId = results->rootNamespace.fileId; - ns->name = name; - modifyNamespace(namespaces); - namespaces->last()->children[name] = ns; + *((const Namespace **)context) = ns; + return true; +} + +const Namespace *CppParser::findNamespace(const NamespaceList &namespaces, int nsCount) const +{ + const Namespace *ns = 0; + if (nsCount == -1) + nsCount = namespaces.count(); + visitNamespace(namespaces, nsCount, &CppParser::findNamespaceCallback, &ns); + return ns; +} + +void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name, bool isClass) +{ + *namespaces << name; + if (!findNamespace(*namespaces)) { + Namespace *ns = modifyNamespace(namespaces, false); + if (isClass) + ns->classDef = ns; } - *namespaces << ns; } void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) @@ -1056,8 +1150,9 @@ const ParseResults *CppFiles::getResults(const QString &cleanFile) return parsedFiles().value(cleanFile); } -void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) +void CppFiles::setResults(const QString &cleanFile, ParseResults *results) { + results->fileId = nextFileId++; parsedFiles().insert(cleanFile, results); } @@ -1093,12 +1188,8 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, QString fileExt = QFileInfo(cleanFile).suffix(); if (fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive)) { - if (results->allIncludes.contains(cleanFile)) - return; - results->allIncludes.insert(cleanFile); - if (const ParseResults *res = CppFiles::getResults(cleanFile)) { - results->unite(res); + results->includes.insert(res); return; } @@ -1128,8 +1219,8 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, } parser.setInput(ts, cleanFile); parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(cleanFile, parser.getResults()); - results->unite(parser.results); + CppFiles::setResults(cleanFile, parser.results); + results->includes.insert(parser.results); } else { CppParser parser(results); parser.namespaces = namespaces; @@ -1138,12 +1229,6 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, parser.pendingContext = pendingContext; parser.setInput(ts, cleanFile); parser.parseInternal(cd, inclusions); - // Don't wreak havoc if not enough braces were found. - truncateNamespaces(&parser.namespaces, namespaces.count()); - truncateNamespaces(&parser.functionContext, functionContext.count()); - // Copy them back - the pointers might have changed. - namespaces = parser.namespaces; - functionContext = parser.functionContext; // Avoid that messages obtained by direct scanning are used CppFiles::setBlacklisted(cleanFile); } @@ -1330,7 +1415,7 @@ void CppParser::parse(const QString &initialContext, ConversionData &cd, if (results->tor) yyCodecIsUtf8 = (results->tor->codecName() == "UTF-8"); - namespaces << &results->rootNamespace; + namespaces << HashString(); functionContext = namespaces; functionContextUnresolved = initialContext; @@ -1405,8 +1490,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) */ yyTok = getToken(); if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { - QStringList quali; - QString fct; + QList quali; + HashString fct; do { /* This code should execute only once, but we play @@ -1414,8 +1499,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) 'class Q_EXPORT QMessageBox', in which case 'QMessageBox' is the class name, not 'Q_EXPORT'. */ - fct = yyWord; - fct.detach(); + text = yyWord; + text.detach(); + fct.setValue(text); yyTok = getToken(); } while (yyTok == Tok_Ident); while (yyTok == Tok_ColonColon) { @@ -1423,8 +1509,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) if (yyTok != Tok_Ident) break; // Oops ... quali << fct; - fct = yyWord; - fct.detach(); + text = yyWord; + text.detach(); + fct.setValue(text); yyTok = getToken(); } while (yyTok == Tok_Comment) @@ -1456,8 +1543,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } else { namespaceDepths.push(namespaces.count()); } - enterNamespace(&namespaces, fct); - namespaces.last()->isClass = true; + enterNamespace(&namespaces, fct, true); functionContext = namespaces; functionContextUnresolved.clear(); // Pointless @@ -1469,34 +1555,33 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) yyTokColonSeen = false; yyTok = getToken(); if (yyTok == Tok_Ident) { - QString ns = yyWord; - ns.detach(); + text = yyWord; + text.detach(); + HashString ns = HashString(text); yyTok = getToken(); if (yyTok == Tok_LeftBrace) { namespaceDepths.push(namespaces.count()); - enterNamespace(&namespaces, ns); + enterNamespace(&namespaces, ns, false); yyTok = getToken(); } else if (yyTok == Tok_Equals) { // e.g. namespace Is = OuterSpace::InnerSpace; - QStringList fullName; + QList fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(ns, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->aliases[ns] = nsl; } } else if (yyTok == Tok_LeftBrace) { // Anonymous namespace @@ -1506,43 +1591,40 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; case Tok_using: yyTok = getToken(); + // XXX this should affect only the current scope, not the entire current namespace if (yyTok == Tok_namespace) { - QStringList fullName; + QList fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->usings.insert(stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->usings << HashStringList(nsl); } else { - QStringList fullName; + QList fullName; if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(nsl.last()->name, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, true)->aliases[nsl.last()] = nsl; } break; case Tok_tr: @@ -1570,8 +1652,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } if (!pendingContext.isEmpty()) { QStringList unresolved; - if (!fullyQualify(namespaces, pendingContext.split(strColons), true, - &functionContext, &unresolved)) { + if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { functionContextUnresolved = unresolved.join(strColons); qWarning("%s:%d: Qualifying with unknown namespace/class %s::%s\n", qPrintable(yyFileName), yyLineNo, @@ -1588,14 +1669,15 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) qPrintable(yyFileName), yyLineNo); break; } - while (!functionContext.at(idx - 1)->hasTrFunctions) { - if (idx == 1 || !functionContext.at(idx - 2)->isClass) { + while (!findNamespace(functionContext, idx)->classDef->hasTrFunctions) { + if (idx == 1 || !findNamespace(functionContext, idx - 1)->classDef) { context = stringifyNamespace(functionContext); - if (!functionContext.last()->complained) { + Namespace *fctx = findNamespace(functionContext)->classDef; + if (!fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, qPrintable(context)); - functionContext.last()->complained = true; + fctx->complained = true; } goto gotctx; } @@ -1603,7 +1685,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } context.clear(); for (int i = 1;;) { - context += functionContext.at(i)->name; + context += functionContext.at(i).value(); if (++i == idx) break; context += strColons; @@ -1625,13 +1707,14 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) prefix.chop(2); NamespaceList nsl; QStringList unresolved; - if (fullyQualify(functionContext, prefix.split(strColons), false, &nsl, &unresolved)) { + if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { context = stringifyNamespace(nsl); - if (!nsl.last()->hasTrFunctions && !nsl.last()->complained) { + Namespace *fctx = findNamespace(nsl)->classDef; + if (!fctx->hasTrFunctions && !fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, qPrintable(context)); - nsl.last()->complained = true; + fctx->complained = true; } } else { context = (stringListifyNamespace(nsl) + unresolved).join(strColons); @@ -1727,7 +1810,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; case Tok_Q_DECLARE_TR_FUNCTIONS: case Tok_Q_OBJECT: - namespaces.last()->hasTrFunctions = true; + modifyNamespace(&namespaces, true)->hasTrFunctions = true; yyTok = getToken(); break; case Tok_Ident: -- cgit v0.12