diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-01-10 18:31:41 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-01-10 18:31:41 +0100 |
commit | 0378cdb823631234f5d91ac8e0150dfb738aa1c9 (patch) | |
tree | c2d2dcb603c20772b6b6ad6c105834e13d2767ca /src | |
parent | 8895a66805e1a13bc909af30a545d78da65080d3 (diff) | |
parent | 372392cf6e14ececbaff8aa54d2a7230ad17ba5f (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I0ddb08a2fff6bd0da01e14726f2789741b509e76
Diffstat (limited to 'src')
-rw-r--r-- | src/linguist/lupdate/cpp.cpp | 618 | ||||
-rw-r--r-- | src/linguist/lupdate/java.cpp | 4 | ||||
-rw-r--r-- | src/linguist/lupdate/lupdate.h | 16 | ||||
-rw-r--r-- | src/linguist/lupdate/main.cpp | 54 | ||||
-rw-r--r-- | src/qdbus/qdbusviewer/logviewer.cpp | 59 | ||||
-rw-r--r-- | src/qdbus/qdbusviewer/logviewer.h | 57 | ||||
-rw-r--r-- | src/qdbus/qdbusviewer/main.cpp | 3 | ||||
-rw-r--r-- | src/qdbus/qdbusviewer/qdbusviewer.cpp | 5 | ||||
-rw-r--r-- | src/qdbus/qdbusviewer/qdbusviewer.pro | 4 |
9 files changed, 453 insertions, 367 deletions
diff --git a/src/linguist/lupdate/cpp.cpp b/src/linguist/lupdate/cpp.cpp index b282e8f57..b644d0c88 100644 --- a/src/linguist/lupdate/cpp.cpp +++ b/src/linguist/lupdate/cpp.cpp @@ -207,7 +207,7 @@ public: void setInput(const QString &in); void setInput(QTextStream &ts, const QString &fileName); void setTranslator(Translator *_tor) { tor = _tor; } - void parse(const QString &initialContext, ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions); + void parse(ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions); void parseInternal(ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions); const ParseResults *recordResults(bool isHeader); void deleteResults() { delete results; } @@ -237,15 +237,25 @@ private: int elseLine; }; + enum TokenType { + Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, + Tok_Q_OBJECT, Tok_Access, Tok_Cancel, + Tok_Ident, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, + Tok_Equals, Tok_LeftBracket, Tok_RightBracket, + Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, + Tok_Null, Tok_Integer, + Tok_QuotedInclude, Tok_AngledInclude, + Tok_Other + }; + std::ostream &yyMsg(int line = 0); int getChar(); - uint getToken(); - bool getMacroArgs(); + TokenType getToken(); void processComment(); - bool match(uint t); + bool match(TokenType t); bool matchString(QString *s); bool matchEncoding(); bool matchStringOrNull(QString *s); @@ -257,21 +267,27 @@ private: const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, bool plural); + void handleTr(QString &prefix); + void handleTranslate(); + void handleTrId(); + void handleDeclareTrFunctions(); + void processInclude(const QString &file, ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions); void saveState(SavedState *state); void loadState(const SavedState *state); - static QString stringifyNamespace(const NamespaceList &namespaces); - static QStringList stringListifyNamespace(const NamespaceList &namespaces); + static QString stringifyNamespace(int start, const NamespaceList &namespaces); + static QString stringifyNamespace(const NamespaceList &namespaces) + { return stringifyNamespace(1, namespaces); } + static QString joinNamespaces(const QString &one, const QString &two); 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<HashString> &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, @@ -279,32 +295,20 @@ private: bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, NamespaceList *resolved) const; bool fullyQualify(const NamespaceList &namespaces, int nsCnt, - const QList<HashString> &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) const; + const NamespaceList &segments, bool isDeclaration, + NamespaceList *resolved, NamespaceList *unresolved) const; bool fullyQualify(const NamespaceList &namespaces, - const QList<HashString> &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) const; + const NamespaceList &segments, bool isDeclaration, + NamespaceList *resolved, NamespaceList *unresolved) const; bool fullyQualify(const NamespaceList &namespaces, const QString &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) const; + NamespaceList *resolved, NamespaceList *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); void truncateNamespaces(NamespaceList *namespaces, int lenght); Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true); - enum TokenType { - Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, - Tok_tr, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, - Tok_Q_OBJECT, Tok_Q_DECLARE_TR_FUNCTIONS, Tok_Access, Tok_Cancel, - Tok_Ident, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, - Tok_Equals, Tok_LeftBracket, Tok_RightBracket, - Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, - Tok_Null, Tok_Integer, - Tok_QuotedInclude, Tok_AngledInclude, - Tok_Other - }; - // Tokenizer state QString yyFileName; int yyCh; @@ -327,7 +331,7 @@ private: const ushort *yyInPtr; // Parser state - uint yyTok; + TokenType yyTok; bool metaExpected; QString context; @@ -459,34 +463,6 @@ int CppParser::getChar() } } -// This ignores commas, parens and comments. -// IOW, it understands only a single, simple argument. -bool CppParser::getMacroArgs() -{ - // Failing this assertion would mean losing the preallocated buffer. - Q_ASSERT(yyWord.isDetached()); - yyWord.resize(0); - - while (isspace(yyCh)) - yyCh = getChar(); - if (yyCh != '(') - return false; - do { - yyCh = getChar(); - } while (isspace(yyCh)); - ushort *ptr = (ushort *)yyWord.unicode(); - while (yyCh != ')') { - if (yyCh == EOF) - return false; - *ptr++ = yyCh; - yyCh = getChar(); - } - yyCh = getChar(); - for (; ptr != (ushort *)yyWord.unicode() && isspace(*(ptr - 1)); --ptr) ; - yyWord.resize(ptr - (ushort *)yyWord.unicode()); - return true; -} - STRING(Q_OBJECT); STRING(class); STRING(friend); @@ -503,12 +479,11 @@ STRING(signals); STRING(Q_SLOTS); STRING(Q_SIGNALS); -uint CppParser::getToken() +CppParser::TokenType CppParser::getToken() { restart: // Failing this assertion would mean losing the preallocated buffer. Q_ASSERT(yyWord.isDetached()); - yyWord.resize(0); while (yyCh != EOF) { yyLineNo = yyCurLineNo; @@ -766,30 +741,6 @@ uint CppParser::getToken() break; } - static const TokenType trFunctionTokens[] = { - Tok_Q_DECLARE_TR_FUNCTIONS, // Q_DECLARE_TR_FUNCTIONS - Tok_tr, // QT_TR_NOOP - Tok_trid, // QT_TRID_NOOP - Tok_translate, // QT_TRANSLATE_NOOP - Tok_translate, // QT_TRANSLATE_NOOP3 - Tok_trUtf8, // QT_TR_NOOP_UTF8 - Tok_translateUtf8, // QT_TRANSLATE_NOOP_UTF8 - Tok_translateUtf8, // QT_TRANSLATE_NOOP3_UTF8 - Tok_translate, // findMessage - Tok_trid, // qtTrId - Tok_tr, // tr - Tok_trUtf8, // trUtf8 - Tok_translate, // translate - Tok_Ident, // qsTr (QML only) - Tok_Ident, // qsTrId (QML only) - Tok_Ident, // qsTranslate (QML only) - }; - Q_STATIC_ASSERT((sizeof trFunctionTokens / sizeof *trFunctionTokens == TrFunctionAliasManager::NumTrFunctions)); - - const int trFunction = trFunctionAliasManager.trFunctionByName(yyWord); - if (trFunction >= 0) - return trFunctionTokens[trFunction]; - return Tok_Ident; } else { switch (yyCh) { @@ -1038,23 +989,24 @@ Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool haveLast) return ns; } -QString CppParser::stringifyNamespace(const NamespaceList &namespaces) +QString CppParser::stringifyNamespace(int start, const NamespaceList &namespaces) { QString ret; - for (int i = 1; i < namespaces.count(); ++i) { - if (i > 1) + int l = 0; + for (int j = start; j < namespaces.count(); ++j) + l += namespaces.at(j).value().length(); + ret.reserve(l + qMax(0, (namespaces.count() - start - 1)) * 2); + for (int i = start; i < namespaces.count(); ++i) { + if (i > start) ret += QLatin1String("::"); ret += namespaces.at(i).value(); } return ret; } -QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) +QString CppParser::joinNamespaces(const QString &one, const QString &two) { - QStringList ret; - for (int i = 1; i < namespaces.count(); ++i) - ret << namespaces.at(i).value(); - return ret; + return two.isEmpty() ? one : one.isEmpty() ? two : one + QStringLiteral("::") + two; } bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, @@ -1082,14 +1034,6 @@ bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, return visitNamespace(namespaces, nsCount, callback, context, vr, results); } -QStringList CppParser::stringListifySegments(const QList<HashString> &segments) -{ - QStringList ret; - for (int i = 0; i < segments.count(); ++i) - ret << segments.at(i).value(); - return ret; -} - struct QualifyOneData { QualifyOneData(const NamespaceList &ns, int nsc, const HashString &seg, NamespaceList *rslvd, QSet<HashStringList> *visited) @@ -1163,8 +1107,8 @@ bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const Has } bool CppParser::fullyQualify(const NamespaceList &namespaces, int nsCnt, - const QList<HashString> &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) const + const NamespaceList &segments, bool isDeclaration, + NamespaceList *resolved, NamespaceList *unresolved) const { int nsIdx; int initSegIdx; @@ -1189,7 +1133,7 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, int nsCnt, while (++segIdx < segments.count()) { if (!qualifyOne(*resolved, resolved->count(), segments[segIdx], resolved)) { if (unresolved) - *unresolved = stringListifySegments(segments.mid(segIdx)); + *unresolved = segments.mid(segIdx); return false; } } @@ -1199,13 +1143,13 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, int nsCnt, resolved->clear(); *resolved << HashString(QString()); if (unresolved) - *unresolved = stringListifySegments(segments.mid(initSegIdx)); + *unresolved = segments.mid(initSegIdx); return false; } bool CppParser::fullyQualify(const NamespaceList &namespaces, - const QList<HashString> &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) const + const NamespaceList &segments, bool isDeclaration, + NamespaceList *resolved, NamespaceList *unresolved) const { return fullyQualify(namespaces, namespaces.count(), segments, isDeclaration, resolved, unresolved); @@ -1213,11 +1157,11 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) const + NamespaceList *resolved, NamespaceList *unresolved) const { static QString strColons(QLatin1String("::")); - QList<HashString> segments; + NamespaceList 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); @@ -1404,7 +1348,7 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, const QS parser.setInput(ts, cleanFile); QStringList stack = includeStack; stack << cleanFile; - parser.parse(cd.m_defaultContext, cd, stack, inclusions); + parser.parse(cd, stack, inclusions); results->includes.insert(parser.recordResults(true)); } else { CppParser parser(results); @@ -1435,7 +1379,7 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, const QS appears within a function defined outside the class definition. */ -bool CppParser::match(uint t) +bool CppParser::match(TokenType t) { bool matches = (yyTok == t); if (matches) @@ -1588,12 +1532,210 @@ void CppParser::recordMessage(int line, const QString &context, const QString &t tor->append(msg); } -void CppParser::parse(const QString &initialContext, ConversionData &cd, const QStringList &includeStack, +void CppParser::handleTr(QString &prefix) +{ + if (!sourcetext.isEmpty()) + yyMsg() << qPrintable(LU::tr("//% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n")); + int line = yyLineNo; + yyTok = getToken(); + if (matchString(&text) && !text.isEmpty()) { + comment.clear(); + bool plural = false; + + if (yyTok == Tok_RightParen) { + // no comment + } else if (match(Tok_Comma) && matchStringOrNull(&comment)) { //comment + if (yyTok == Tok_RightParen) { + // ok, + } else if (match(Tok_Comma)) { + plural = true; + } + } + if (!pendingContext.isEmpty() && !prefix.startsWith(QLatin1String("::"))) { + NamespaceList unresolved; + if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { + functionContextUnresolved = stringifyNamespace(0, unresolved); + yyMsg() << qPrintable(LU::tr("Qualifying with unknown namespace/class %1::%2\n") + .arg(stringifyNamespace(functionContext)).arg(unresolved.first().value())); + } + pendingContext.clear(); + } + if (prefix.isEmpty()) { + if (functionContextUnresolved.isEmpty()) { + int idx = functionContext.length(); + if (idx < 2) { + yyMsg() << qPrintable(LU::tr("tr() cannot be called without context\n")); + return; + } + Namespace *fctx; + while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { + if (idx == 1) { + context = stringifyNamespace(functionContext); + fctx = findNamespace(functionContext)->classDef; + if (!fctx->complained) { + yyMsg() << qPrintable(LU::tr("Class '%1' lacks Q_OBJECT macro\n") + .arg(context)); + fctx->complained = true; + } + goto gotctx; + } + --idx; + } + if (fctx->trQualification.isEmpty()) { + context.clear(); + for (int i = 1;;) { + context += functionContext.at(i).value(); + if (++i == idx) + break; + context += QLatin1String("::"); + } + fctx->trQualification = context; + } else { + context = fctx->trQualification; + } + } else { + context = joinNamespaces(stringifyNamespace(functionContext), functionContextUnresolved); + } + } else { +#ifdef DIAGNOSE_RETRANSLATABILITY + int last = prefix.lastIndexOf(QLatin1String("::")); + QString className = prefix.mid(last == -1 ? 0 : last + 2); + if (!className.isEmpty() && className == functionName) { + yyMsg() << qPrintable(LU::tr("It is not recommended to call tr() from within a constructor '%1::%2'\n") + .arg(className).arg(functionName)); + } +#endif + prefix.chop(2); + NamespaceList nsl; + NamespaceList unresolved; + if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { + Namespace *fctx = findNamespace(nsl)->classDef; + if (fctx->trQualification.isEmpty()) { + context = stringifyNamespace(nsl); + fctx->trQualification = context; + } else { + context = fctx->trQualification; + } + if (!fctx->hasTrFunctions && !fctx->complained) { + yyMsg() << qPrintable(LU::tr("Class '%1' lacks Q_OBJECT macro\n").arg(context)); + fctx->complained = true; + } + } else { + context = joinNamespaces(stringifyNamespace(nsl), stringifyNamespace(0, unresolved)); + } + prefix.clear(); + } + + gotctx: + recordMessage(line, context, text, comment, extracomment, msgid, extra, plural); + } + sourcetext.clear(); // Will have warned about that already + extracomment.clear(); + msgid.clear(); + extra.clear(); + metaExpected = false; +} + +void CppParser::handleTranslate() +{ + if (!sourcetext.isEmpty()) + yyMsg() << qPrintable(LU::tr("//% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n")); + int line = yyLineNo; + yyTok = getToken(); + if (matchString(&context) + && match(Tok_Comma) + && matchString(&text) && !text.isEmpty()) + { + comment.clear(); + bool plural = false; + if (yyTok != Tok_RightParen) { + // look for comment + if (match(Tok_Comma) && matchStringOrNull(&comment)) { + if (yyTok != Tok_RightParen) { + // look for encoding + if (match(Tok_Comma)) { + if (matchEncoding()) { + if (yyTok != Tok_RightParen) { + // look for the plural quantifier, + // this can be a number, an identifier or + // a function call, + // so for simplicity we mark it as plural if + // we know we have a comma instead of an + // right parentheses. + plural = match(Tok_Comma); + } + } else { + // This can be a QTranslator::translate("context", + // "source", "comment", n) plural translation + if (matchExpression() && yyTok == Tok_RightParen) { + plural = true; + } else { + return; + } + } + } else { + return; + } + } + } else { + return; + } + } + recordMessage(line, context, text, comment, extracomment, msgid, extra, plural); + } + sourcetext.clear(); // Will have warned about that already + extracomment.clear(); + msgid.clear(); + extra.clear(); + metaExpected = false; +} + +void CppParser::handleTrId() +{ + if (!msgid.isEmpty()) + yyMsg() << qPrintable(LU::tr("//= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n")); + int line = yyLineNo; + yyTok = getToken(); + if (matchString(&msgid) && !msgid.isEmpty()) { + bool plural = match(Tok_Comma); + recordMessage(line, QString(), sourcetext, QString(), extracomment, + msgid, extra, plural); + } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); + metaExpected = false; +} + +void CppParser::handleDeclareTrFunctions() +{ + QString name; + forever { + yyTok = getToken(); + if (yyTok != Tok_Ident) + return; + name += yyWord; + name.detach(); + yyTok = getToken(); + if (yyTok == Tok_RightParen) + break; + if (yyTok != Tok_ColonColon) + return; + name += QLatin1String("::"); + } + Namespace *ns = modifyNamespace(&namespaces); + ns->hasTrFunctions = true; + ns->trQualification = name; + ns->trQualification.detach(); +} + +void CppParser::parse(ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions) { namespaces << HashString(); functionContext = namespaces; - functionContextUnresolved = initialContext; + functionContextUnresolved.clear(); parseInternal(cd, includeStack, inclusions); } @@ -1606,7 +1748,6 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac #ifdef DIAGNOSE_RETRANSLATABILITY QString functionName; #endif - int line; bool yyTokColonSeen = false; // Start of c'tor's initializer list metaExpected = true; @@ -1669,7 +1810,7 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac */ yyTok = getToken(); if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { - QList<HashString> quali; + NamespaceList quali; HashString fct; do { /* @@ -1753,7 +1894,7 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac yyTok = getToken(); } else if (yyTok == Tok_Equals) { // e.g. namespace Is = OuterSpace::InnerSpace; - QList<HashString> fullName; + NamespaceList fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) fullName.append(HashString(QString())); @@ -1781,7 +1922,7 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac yyTok = getToken(); // XXX this should affect only the current scope, not the entire current namespace if (yyTok == Tok_namespace) { - QList<HashString> fullName; + NamespaceList fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) fullName.append(HashString(QString())); @@ -1797,7 +1938,7 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac if (fullyQualify(namespaces, fullName, false, &nsl, 0)) modifyNamespace(&namespaces)->usings << HashStringList(nsl); } else { - QList<HashString> fullName; + NamespaceList fullName; if (yyTok == Tok_ColonColon) fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { @@ -1814,211 +1955,54 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac // fullName is already the resolved name we actually want. // As we do no resolution here, we'll collect useless usings of data // members and methods as well. This is no big deal. - HashString &ns = fullName.last(); fullName.append(HashString(QString())); // Mark as unresolved + const HashString &ns = *(fullName.constEnd() - 2); modifyNamespace(&namespaces)->aliases[ns] = fullName; } break; - case Tok_tr: - case Tok_trUtf8: - if (!tor) - goto case_default; - if (!sourcetext.isEmpty()) - yyMsg() << qPrintable(LU::tr("//% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n")); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) && matchString(&text) && !text.isEmpty()) { - comment.clear(); - bool plural = false; - - if (yyTok == Tok_RightParen) { - // no comment - } else if (match(Tok_Comma) && matchStringOrNull(&comment)) { //comment - if (yyTok == Tok_RightParen) { - // ok, - } else if (match(Tok_Comma)) { - plural = true; - } - } - if (!pendingContext.isEmpty() && !prefix.startsWith(strColons)) { - QStringList unresolved; - if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { - functionContextUnresolved = unresolved.join(strColons); - yyMsg() << qPrintable(LU::tr("Qualifying with unknown namespace/class %1::%2\n") - .arg(stringifyNamespace(functionContext)).arg(unresolved.first())); - } - pendingContext.clear(); - } - if (prefix.isEmpty()) { - if (functionContextUnresolved.isEmpty()) { - int idx = functionContext.length(); - if (idx < 2) { - yyMsg() << qPrintable(LU::tr("tr() cannot be called without context\n")); - goto case_default; - } - Namespace *fctx; - while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { - if (idx == 1) { - context = stringifyNamespace(functionContext); - fctx = findNamespace(functionContext)->classDef; - if (!fctx->complained) { - yyMsg() << qPrintable(LU::tr("Class '%1' lacks Q_OBJECT macro\n") - .arg(context)); - fctx->complained = true; - } - goto gotctx; - } - --idx; - } - if (fctx->trQualification.isEmpty()) { - context.clear(); - for (int i = 1;;) { - context += functionContext.at(i).value(); - if (++i == idx) - break; - context += strColons; - } - fctx->trQualification = context; - } else { - context = fctx->trQualification; - } - } else { - context = (stringListifyNamespace(functionContext) - << functionContextUnresolved).join(strColons); - } - } else { -#ifdef DIAGNOSE_RETRANSLATABILITY - int last = prefix.lastIndexOf(strColons); - QString className = prefix.mid(last == -1 ? 0 : last + 2); - if (!className.isEmpty() && className == functionName) { - yyMsg() << qPrintable(LU::tr("It is not recommended to call tr() from within a constructor '%1::%2'\n") - .arg(className).arg(functionName)); - } -#endif - prefix.chop(2); - NamespaceList nsl; - QStringList unresolved; - if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { - Namespace *fctx = findNamespace(nsl)->classDef; - if (fctx->trQualification.isEmpty()) { - context = stringifyNamespace(nsl); - fctx->trQualification = context; - } else { - context = fctx->trQualification; - } - if (!fctx->hasTrFunctions && !fctx->complained) { - yyMsg() << qPrintable(LU::tr("Class '%1' lacks Q_OBJECT macro\n").arg(context)); - fctx->complained = true; - } - } else { - context = (stringListifyNamespace(nsl) + unresolved).join(strColons); - } - prefix.clear(); - } - - gotctx: - recordMessage(line, context, text, comment, extracomment, msgid, extra, plural); - } - sourcetext.clear(); // Will have warned about that already - extracomment.clear(); - msgid.clear(); - extra.clear(); - metaExpected = false; - yyTok = getToken(); - break; - case Tok_translateUtf8: - case Tok_translate: - if (!tor) - goto case_default; - if (!sourcetext.isEmpty()) - yyMsg() << qPrintable(LU::tr("//% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n")); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) - && matchString(&context) - && match(Tok_Comma) - && matchString(&text) && !text.isEmpty()) - { - comment.clear(); - bool plural = false; - if (yyTok != Tok_RightParen) { - // look for comment - if (match(Tok_Comma) && matchStringOrNull(&comment)) { - if (yyTok != Tok_RightParen) { - // look for encoding - if (match(Tok_Comma)) { - if (matchEncoding()) { - if (yyTok != Tok_RightParen) { - // look for the plural quantifier, - // this can be a number, an identifier or - // a function call, - // so for simplicity we mark it as plural if - // we know we have a comma instead of an - // right parentheses. - plural = match(Tok_Comma); - } - } else { - // This can be a QTranslator::translate("context", - // "source", "comment", n) plural translation - if (matchExpression() && yyTok == Tok_RightParen) { - plural = true; - } else { - goto case_default; - } - } - } else { - goto case_default; - } - } - } else { - goto case_default; - } - } - recordMessage(line, context, text, comment, extracomment, msgid, extra, plural); - } - sourcetext.clear(); // Will have warned about that already - extracomment.clear(); - msgid.clear(); - extra.clear(); - metaExpected = false; - yyTok = getToken(); - break; - case Tok_trid: - if (!tor) - goto case_default; - if (!msgid.isEmpty()) - yyMsg() << qPrintable(LU::tr("//= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n")); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { - bool plural = match(Tok_Comma); - recordMessage(line, QString(), sourcetext, QString(), extracomment, - msgid, extra, plural); - } - sourcetext.clear(); - extracomment.clear(); - msgid.clear(); - extra.clear(); - metaExpected = false; - break; - case Tok_Q_DECLARE_TR_FUNCTIONS: - if (getMacroArgs()) { - Namespace *ns = modifyNamespace(&namespaces); - ns->hasTrFunctions = true; - ns->trQualification = yyWord; - ns->trQualification.detach(); - } - yyTok = getToken(); - break; case Tok_Q_OBJECT: modifyNamespace(&namespaces)->hasTrFunctions = true; yyTok = getToken(); break; case Tok_Ident: - prefix += yyWord; - prefix.detach(); yyTok = getToken(); - if (yyTok != Tok_ColonColon) { + if (yyTok == Tok_LeftParen) { + switch (trFunctionAliasManager.trFunctionByName(yyWord)) { + case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS: + handleDeclareTrFunctions(); + break; + case TrFunctionAliasManager::Function_tr: + case TrFunctionAliasManager::Function_trUtf8: + case TrFunctionAliasManager::Function_QT_TR_NOOP: + case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8: + if (tor) + handleTr(prefix); + break; + case TrFunctionAliasManager::Function_translate: + case TrFunctionAliasManager::Function_findMessage: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8: + if (tor) + handleTranslate(); + break; + case TrFunctionAliasManager::Function_qtTrId: + case TrFunctionAliasManager::Function_QT_TRID_NOOP: + if (tor) + handleTrId(); + break; + default: + goto notrfunc; + } + yyTok = getToken(); + break; + } + if (yyTok == Tok_ColonColon) { + prefix += yyWord; + prefix.detach(); + } else { + notrfunc: prefix.clear(); if (yyTok == Tok_Ident && !yyParenDepth) prospectiveContext.clear(); @@ -2027,8 +2011,14 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac break; case Tok_Arrow: yyTok = getToken(); - if (yyTok == Tok_tr || yyTok == Tok_trUtf8) - yyMsg() << qPrintable(LU::tr("Cannot invoke tr() like this\n")); + if (yyTok == Tok_Ident) { + switch (trFunctionAliasManager.trFunctionByName(yyWord)) { + case TrFunctionAliasManager::Function_tr: + case TrFunctionAliasManager::Function_trUtf8: + yyMsg() << qPrintable(LU::tr("Cannot invoke tr() like this\n")); + break; + } + } break; case Tok_ColonColon: if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0 && !yyTokColonSeen) @@ -2047,13 +2037,11 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac truncateNamespaces(&namespaces, namespaceDepths.pop()); if (yyBraceDepth == namespaceDepths.count()) { // function, class or namespace - if (!yyBraceDepth && !directInclude) { + if (!yyBraceDepth && !directInclude) truncateNamespaces(&functionContext, 1); - functionContextUnresolved = cd.m_defaultContext; - } else { + else functionContext = namespaces; - functionContextUnresolved.clear(); - } + functionContextUnresolved.clear(); pendingContext.clear(); } // fallthrough @@ -2275,7 +2263,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat Translator *tor = new Translator; parser.setTranslator(tor); QSet<QString> inclusions; - parser.parse(cd.m_defaultContext, cd, QStringList(), inclusions); + parser.parse(cd, QStringList(), inclusions); parser.recordResults(isHeader(filename)); } diff --git a/src/linguist/lupdate/java.cpp b/src/linguist/lupdate/java.cpp index f64de80e3..aad608e82 100644 --- a/src/linguist/lupdate/java.cpp +++ b/src/linguist/lupdate/java.cpp @@ -112,7 +112,6 @@ static int yyInPos; // The parser maintains the following global variables. static QString yyPackage; static QStack<Scope*> yyScope; -static QString yyDefaultContext; std::ostream &yyMsg(int line = 0) { @@ -446,7 +445,7 @@ static const QString context() innerClass = true; } } - return context.isEmpty() ? yyDefaultContext : context; + return context; } static void recordMessage( @@ -606,7 +605,6 @@ bool loadJava(Translator &translator, const QString &filename, ConversionData &c return false; } - yyDefaultContext = cd.m_defaultContext; yyInPos = -1; yyFileName = filename; yyPackage.clear(); diff --git a/src/linguist/lupdate/lupdate.h b/src/linguist/lupdate/lupdate.h index bc1fa421d..5428306a7 100644 --- a/src/linguist/lupdate/lupdate.h +++ b/src/linguist/lupdate/lupdate.h @@ -44,9 +44,9 @@ #include "qglobal.h" -#include <QByteArray> #include <QList> #include <QString> +#include <QStringList> #include <QHash> QT_BEGIN_NAMESPACE @@ -124,16 +124,12 @@ public: enum Operation { AddAlias, SetAlias }; - int trFunctionByName(const QByteArray &trFunctionByName) const; - int trFunctionByName(const QString &trFunctionName) const - { return trFunctionByName(trFunctionName.toLatin1()); } + int trFunctionByName(const QString &trFunctionName) const; - void modifyAlias(int trFunction, const QByteArray &alias, Operation op); + void modifyAlias(int trFunction, const QString &alias, Operation op); - bool isAliasFor(const QByteArray &identifier, TrFunction trFunction) const - { return m_trFunctionAliases[trFunction].contains(identifier); } bool isAliasFor(const QString &identifier, TrFunction trFunction) const - { return isAliasFor(identifier.toLatin1(), trFunction); } + { return m_trFunctionAliases[trFunction].contains(identifier); } QStringList availableFunctionsWithAliases() const; @@ -141,8 +137,8 @@ private: void ensureTrFunctionHashUpdated() const; private: - QList<QByteArray> m_trFunctionAliases[NumTrFunctions]; - mutable QHash<QByteArray,TrFunction> m_nameToTrFunctionMap; + QStringList m_trFunctionAliases[NumTrFunctions]; + mutable QHash<QString,TrFunction> m_nameToTrFunctionMap; }; QT_END_NAMESPACE diff --git a/src/linguist/lupdate/main.cpp b/src/linguist/lupdate/main.cpp index 41eb7fbdf..bf3a601eb 100644 --- a/src/linguist/lupdate/main.cpp +++ b/src/linguist/lupdate/main.cpp @@ -60,23 +60,23 @@ #include <iostream> -// Can't have an array of QStaticByteArrayData<N> for different N, so -// use QByteArray, which requires constructor calls. Doesn't matter +// Can't have an array of QStaticStringData<N> for different N, so +// use QString, which requires constructor calls. Doesn't matter // much, since this is in an app, not a lib: -static const QByteArray defaultTrFunctionNames[] = { -// MSVC can't handle the lambda in this array if QByteArrayLiteral expands -// to a lambda. In that case, use a QByteArray instead. +static const QString defaultTrFunctionNames[] = { +// MSVC can't handle the lambda in this array if QStringLiteral expands +// to a lambda. In that case, use a QString instead. #if defined(Q_CC_MSVC) && defined(Q_COMPILER_LAMBDA) -#define BYTEARRAYLITERAL(F) QByteArray(#F), +#define STRINGLITERAL(F) QLatin1String(#F), #else -#define BYTEARRAYLITERAL(F) QByteArrayLiteral(#F), +#define STRINGLITERAL(F) QStringLiteral(#F), #endif - LUPDATE_FOR_EACH_TR_FUNCTION(BYTEARRAYLITERAL) -#undef BYTEARRAYLITERAL + LUPDATE_FOR_EACH_TR_FUNCTION(STRINGLITERAL) +#undef STRINGLITERAL }; Q_STATIC_ASSERT((TrFunctionAliasManager::NumTrFunctions == sizeof defaultTrFunctionNames / sizeof *defaultTrFunctionNames)); -static int trFunctionByDefaultName(const QByteArray &trFunctionName) +static int trFunctionByDefaultName(const QString &trFunctionName) { for (int i = 0; i < TrFunctionAliasManager::NumTrFunctions; ++i) if (trFunctionName == defaultTrFunctionNames[i]) @@ -84,11 +84,6 @@ static int trFunctionByDefaultName(const QByteArray &trFunctionName) return -1; } -static int trFunctionByDefaultName(const QString &trFunctionName) -{ - return trFunctionByDefaultName(trFunctionName.toLatin1()); -} - TrFunctionAliasManager::TrFunctionAliasManager() : m_trFunctionAliases() { @@ -98,18 +93,18 @@ TrFunctionAliasManager::TrFunctionAliasManager() TrFunctionAliasManager::~TrFunctionAliasManager() {} -int TrFunctionAliasManager::trFunctionByName(const QByteArray &trFunctionName) const +int TrFunctionAliasManager::trFunctionByName(const QString &trFunctionName) const { ensureTrFunctionHashUpdated(); // this function needs to be fast - const QHash<QByteArray, TrFunction>::const_iterator it + const QHash<QString, TrFunction>::const_iterator it = m_nameToTrFunctionMap.find(trFunctionName); return it == m_nameToTrFunctionMap.end() ? -1 : *it; } -void TrFunctionAliasManager::modifyAlias(int trFunction, const QByteArray &alias, Operation op) +void TrFunctionAliasManager::modifyAlias(int trFunction, const QString &alias, Operation op) { - QList<QByteArray> &list = m_trFunctionAliases[trFunction]; + QList<QString> &list = m_trFunctionAliases[trFunction]; if (op == SetAlias) list.clear(); list.push_back(alias); @@ -121,9 +116,9 @@ void TrFunctionAliasManager::ensureTrFunctionHashUpdated() const if (!m_nameToTrFunctionMap.empty()) return; - QHash<QByteArray, TrFunction> nameToTrFunctionMap; + QHash<QString, TrFunction> nameToTrFunctionMap; for (int i = 0; i < NumTrFunctions; ++i) - foreach (const QByteArray &alias, m_trFunctionAliases[i]) + foreach (const QString &alias, m_trFunctionAliases[i]) nameToTrFunctionMap[alias] = TrFunction(i); // commit: m_nameToTrFunctionMap.swap(nameToTrFunctionMap); @@ -134,16 +129,7 @@ static QStringList availableFunctions() QStringList result; result.reserve(TrFunctionAliasManager::NumTrFunctions); for (int i = 0; i < TrFunctionAliasManager::NumTrFunctions; ++i) - result.push_back(QString::fromLatin1(defaultTrFunctionNames[i])); - return result; -} - -static QStringList byteArrayToStringList(const QList<QByteArray> &in) -{ - QStringList result; - result.reserve(in.size()); - foreach (const QByteArray &function, in) - result.push_back(QString::fromLatin1(function)); + result.push_back(defaultTrFunctionNames[i]); return result; } @@ -152,9 +138,9 @@ QStringList TrFunctionAliasManager::availableFunctionsWithAliases() const QStringList result; result.reserve(NumTrFunctions); for (int i = 0; i < NumTrFunctions; ++i) - result.push_back(QString::fromLatin1(defaultTrFunctionNames[i]) + + result.push_back(defaultTrFunctionNames[i] + QLatin1String(" (=") + - byteArrayToStringList(m_trFunctionAliases[i]).join(QLatin1Char('=')) + + m_trFunctionAliases[i].join(QLatin1Char('=')) + QLatin1Char(')')); return result; } @@ -280,7 +266,7 @@ static bool handleTrFunctionAliases(const QString &arg) .arg(trFunctionName)); return false; } - trFunctionAliasManager.modifyAlias(trFunction, alias.toLatin1(), + trFunctionAliasManager.modifyAlias(trFunction, alias, plusEqual ? TrFunctionAliasManager::AddAlias : TrFunctionAliasManager::SetAlias); } return true; diff --git a/src/qdbus/qdbusviewer/logviewer.cpp b/src/qdbus/qdbusviewer/logviewer.cpp new file mode 100644 index 000000000..a230eb65f --- /dev/null +++ b/src/qdbus/qdbusviewer/logviewer.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Tasuku Suzuki <stasuku@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "logviewer.h" + +#include <QtGui/QContextMenuEvent> +#include <QtWidgets/QMenu> + +LogViewer::LogViewer(QWidget *parent) + : QTextBrowser(parent) +{ +} + +void LogViewer::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu *menu = createStandardContextMenu(); + QAction *action = menu->addAction(tr("Clear")); + connect(action, SIGNAL(triggered()), this, SLOT(clear())); + menu->exec(event->globalPos()); + delete menu; +} diff --git a/src/qdbus/qdbusviewer/logviewer.h b/src/qdbus/qdbusviewer/logviewer.h new file mode 100644 index 000000000..d8dec0ecd --- /dev/null +++ b/src/qdbus/qdbusviewer/logviewer.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Tasuku Suzuki <stasuku@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LOGVIEWER_H +#define LOGVIEWER_H + +#include <QtWidgets/QTextBrowser> + +class LogViewer : public QTextBrowser +{ + Q_OBJECT +public: + explicit LogViewer(QWidget *parent = 0); + +protected: + virtual void contextMenuEvent(QContextMenuEvent *event); +}; + +#endif // LOGVIEWER_H diff --git a/src/qdbus/qdbusviewer/main.cpp b/src/qdbus/qdbusviewer/main.cpp index 5499192c8..f539230be 100644 --- a/src/qdbus/qdbusviewer/main.cpp +++ b/src/qdbus/qdbusviewer/main.cpp @@ -82,7 +82,8 @@ int main(int argc, char *argv[]) QMenu *fileMenu = mw.menuBar()->addMenu(QObject::tr("&File")); QAction *quitAction = fileMenu->addAction(QObject::tr("&Quit"), &mw, SLOT(close())); - Q_UNUSED(quitAction); + quitAction->setShortcut(QKeySequence::Quit); + quitAction->setMenuRole(QAction::QuitRole); QMenu *helpMenu = mw.menuBar()->addMenu(QObject::tr("&Help")); QAction *aboutAction = helpMenu->addAction(QObject::tr("&About")); diff --git a/src/qdbus/qdbusviewer/qdbusviewer.cpp b/src/qdbus/qdbusviewer/qdbusviewer.cpp index 403e954d7..ac0c141b4 100644 --- a/src/qdbus/qdbusviewer/qdbusviewer.cpp +++ b/src/qdbus/qdbusviewer/qdbusviewer.cpp @@ -42,7 +42,7 @@ #include "qdbusviewer.h" #include "qdbusmodel.h" #include "propertydialog.h" - +#include "logviewer.h" #include <QtWidgets/QTreeWidget> #include <QtCore/QStringListModel> @@ -50,7 +50,6 @@ #include <QtCore/QMetaProperty> #include <QtWidgets/QLineEdit> #include <QtWidgets/QListView> -#include <QtWidgets/QTextBrowser> #include <QtWidgets/QAction> #include <QtWidgets/QShortcut> #include <QtWidgets/QVBoxLayout> @@ -115,7 +114,7 @@ QDBusViewer::QDBusViewer(const QDBusConnection &connection, QWidget *parent) : QSplitter *topSplitter = new QSplitter(Qt::Vertical, this); layout->addWidget(topSplitter); - log = new QTextBrowser; + log = new LogViewer; connect(log, SIGNAL(anchorClicked(QUrl)), this, SLOT(anchorClicked(QUrl))); QSplitter *splitter = new QSplitter(topSplitter); diff --git a/src/qdbus/qdbusviewer/qdbusviewer.pro b/src/qdbus/qdbusviewer/qdbusviewer.pro index 23c6ba027..1cd2f8f4d 100644 --- a/src/qdbus/qdbusviewer/qdbusviewer.pro +++ b/src/qdbus/qdbusviewer/qdbusviewer.pro @@ -1,10 +1,12 @@ HEADERS = qdbusviewer.h \ qdbusmodel.h \ - propertydialog.h + propertydialog.h \ + logviewer.h SOURCES = qdbusviewer.cpp \ qdbusmodel.cpp \ propertydialog.cpp \ + logviewer.cpp \ main.cpp RESOURCES += qdbusviewer.qrc |