48 #include <QtCore/QFileInfo> |
48 #include <QtCore/QFileInfo> |
49 #include <QtCore/QStack> |
49 #include <QtCore/QStack> |
50 #include <QtCore/QString> |
50 #include <QtCore/QString> |
51 #include <QtCore/QTextCodec> |
51 #include <QtCore/QTextCodec> |
52 #include <QtCore/QTextStream> |
52 #include <QtCore/QTextStream> |
|
53 #include <QtCore/QCoreApplication> |
53 |
54 |
54 #include <iostream> |
55 #include <iostream> |
55 |
56 |
56 #include <ctype.h> // for isXXX() |
57 #include <ctype.h> // for isXXX() |
57 |
58 |
58 QT_BEGIN_NAMESPACE |
59 QT_BEGIN_NAMESPACE |
|
60 |
|
61 class LU { |
|
62 Q_DECLARE_TR_FUNCTIONS(LUpdate) |
|
63 }; |
59 |
64 |
60 /* qmake ignore Q_OBJECT */ |
65 /* qmake ignore Q_OBJECT */ |
61 |
66 |
62 static QString MagicComment(QLatin1String("TRANSLATOR")); |
67 static QString MagicComment(QLatin1String("TRANSLATOR")); |
63 |
68 |
622 if (is.elseLine != -1) { |
627 if (is.elseLine != -1) { |
623 if (yyBracketDepth != is.bracketDepth1st |
628 if (yyBracketDepth != is.bracketDepth1st |
624 || yyBraceDepth != is.braceDepth1st |
629 || yyBraceDepth != is.braceDepth1st |
625 || yyParenDepth != is.parenDepth1st) |
630 || yyParenDepth != is.parenDepth1st) |
626 yyMsg(is.elseLine) |
631 yyMsg(is.elseLine) |
627 << "Parenthesis/bracket/brace mismatch between " |
632 << qPrintable(LU::tr("Parenthesis/bracket/brace mismatch between " |
628 "#if and #else branches; using #if branch\n"; |
633 "#if and #else branches; using #if branch\n")); |
629 } else { |
634 } else { |
630 is.bracketDepth1st = yyBracketDepth; |
635 is.bracketDepth1st = yyBracketDepth; |
631 is.braceDepth1st = yyBraceDepth; |
636 is.braceDepth1st = yyBraceDepth; |
632 is.parenDepth1st = yyParenDepth; |
637 is.parenDepth1st = yyParenDepth; |
633 saveState(&is.state); |
638 saveState(&is.state); |
645 if (is.elseLine != -1) { |
650 if (is.elseLine != -1) { |
646 if (yyBracketDepth != is.bracketDepth1st |
651 if (yyBracketDepth != is.bracketDepth1st |
647 || yyBraceDepth != is.braceDepth1st |
652 || yyBraceDepth != is.braceDepth1st |
648 || yyParenDepth != is.parenDepth1st) |
653 || yyParenDepth != is.parenDepth1st) |
649 yyMsg(is.elseLine) |
654 yyMsg(is.elseLine) |
650 << "Parenthesis/brace mismatch between " |
655 << qPrintable(LU::tr("Parenthesis/brace mismatch between " |
651 "#if and #else branches; using #if branch\n"; |
656 "#if and #else branches; using #if branch\n")); |
652 yyBracketDepth = is.bracketDepth1st; |
657 yyBracketDepth = is.bracketDepth1st; |
653 yyBraceDepth = is.braceDepth1st; |
658 yyBraceDepth = is.braceDepth1st; |
654 yyParenDepth = is.parenDepth1st; |
659 yyParenDepth = is.parenDepth1st; |
655 loadState(&is.state); |
660 loadState(&is.state); |
656 } |
661 } |
892 return Tok_LeftBrace; |
897 return Tok_LeftBrace; |
893 case '}': |
898 case '}': |
894 if (yyBraceDepth == yyMinBraceDepth) { |
899 if (yyBraceDepth == yyMinBraceDepth) { |
895 if (!inDefine) |
900 if (!inDefine) |
896 yyMsg(yyCurLineNo) |
901 yyMsg(yyCurLineNo) |
897 << "Excess closing brace in C++ code" |
902 << qPrintable(LU::tr("Excess closing brace in C++ code" |
898 " (or abuse of the C++ preprocessor)\n"; |
903 " (or abuse of the C++ preprocessor)\n")); |
899 // Avoid things getting messed up even more |
904 // Avoid things getting messed up even more |
900 yyCh = getChar(); |
905 yyCh = getChar(); |
901 return Tok_Semicolon; |
906 return Tok_Semicolon; |
902 } |
907 } |
903 yyBraceDepth--; |
908 yyBraceDepth--; |
910 yyCh = getChar(); |
915 yyCh = getChar(); |
911 return Tok_LeftParen; |
916 return Tok_LeftParen; |
912 case ')': |
917 case ')': |
913 if (yyParenDepth == 0) |
918 if (yyParenDepth == 0) |
914 yyMsg(yyCurLineNo) |
919 yyMsg(yyCurLineNo) |
915 << "Excess closing parenthesis in C++ code" |
920 << qPrintable(LU::tr("Excess closing parenthesis in C++ code" |
916 " (or abuse of the C++ preprocessor)\n"; |
921 " (or abuse of the C++ preprocessor)\n")); |
917 else |
922 else |
918 yyParenDepth--; |
923 yyParenDepth--; |
919 yyCh = getChar(); |
924 yyCh = getChar(); |
920 return Tok_RightParen; |
925 return Tok_RightParen; |
921 case '[': |
926 case '[': |
925 yyCh = getChar(); |
930 yyCh = getChar(); |
926 return Tok_LeftBracket; |
931 return Tok_LeftBracket; |
927 case ']': |
932 case ']': |
928 if (yyBracketDepth == 0) |
933 if (yyBracketDepth == 0) |
929 yyMsg(yyCurLineNo) |
934 yyMsg(yyCurLineNo) |
930 << "Excess closing bracket in C++ code" |
935 << qPrintable(LU::tr("Excess closing bracket in C++ code" |
931 " (or abuse of the C++ preprocessor)\n"; |
936 " (or abuse of the C++ preprocessor)\n")); |
932 else |
937 else |
933 yyBracketDepth--; |
938 yyBracketDepth--; |
934 yyCh = getChar(); |
939 yyCh = getChar(); |
935 return Tok_RightBracket; |
940 return Tok_RightBracket; |
936 case ',': |
941 case ',': |
1294 QSet<QString> &inclusions) |
1299 QSet<QString> &inclusions) |
1295 { |
1300 { |
1296 QString cleanFile = QDir::cleanPath(file); |
1301 QString cleanFile = QDir::cleanPath(file); |
1297 |
1302 |
1298 if (inclusions.contains(cleanFile)) { |
1303 if (inclusions.contains(cleanFile)) { |
1299 yyMsg() << "circular inclusion of " << qPrintable(cleanFile) << std::endl; |
1304 yyMsg() << qPrintable(LU::tr("circular inclusion of %1\n").arg(cleanFile)); |
1300 return; |
1305 return; |
1301 } |
1306 } |
1302 |
1307 |
1303 // If the #include is in any kind of namespace, has been blacklisted previously, |
1308 // If the #include is in any kind of namespace, has been blacklisted previously, |
1304 // or is not a header file (stdc++ extensionless or *.h*), then really include |
1309 // or is not a header file (stdc++ extensionless or *.h*), then really include |
1785 } |
1788 } |
1786 if (!pendingContext.isEmpty() && !prefix.startsWith(strColons)) { |
1789 if (!pendingContext.isEmpty() && !prefix.startsWith(strColons)) { |
1787 QStringList unresolved; |
1790 QStringList unresolved; |
1788 if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { |
1791 if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { |
1789 functionContextUnresolved = unresolved.join(strColons); |
1792 functionContextUnresolved = unresolved.join(strColons); |
1790 yyMsg() << "Qualifying with unknown namespace/class " |
1793 yyMsg() << qPrintable(LU::tr("Qualifying with unknown namespace/class %1::%2\n") |
1791 << qPrintable(stringifyNamespace(functionContext)) << "::" |
1794 .arg(stringifyNamespace(functionContext)).arg(unresolved.first())); |
1792 << qPrintable(unresolved.first()) << std::endl; |
|
1793 } |
1795 } |
1794 pendingContext.clear(); |
1796 pendingContext.clear(); |
1795 } |
1797 } |
1796 if (prefix.isEmpty()) { |
1798 if (prefix.isEmpty()) { |
1797 if (functionContextUnresolved.isEmpty()) { |
1799 if (functionContextUnresolved.isEmpty()) { |
1798 int idx = functionContext.length(); |
1800 int idx = functionContext.length(); |
1799 if (idx < 2) { |
1801 if (idx < 2) { |
1800 yyMsg() << "tr() cannot be called without context\n"; |
1802 yyMsg() << qPrintable(LU::tr("tr() cannot be called without context\n")); |
1801 break; |
1803 break; |
1802 } |
1804 } |
1803 Namespace *fctx; |
1805 Namespace *fctx; |
1804 while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { |
1806 while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { |
1805 if (idx == 1) { |
1807 if (idx == 1) { |
1806 context = stringifyNamespace(functionContext); |
1808 context = stringifyNamespace(functionContext); |
1807 fctx = findNamespace(functionContext)->classDef; |
1809 fctx = findNamespace(functionContext)->classDef; |
1808 if (!fctx->complained) { |
1810 if (!fctx->complained) { |
1809 yyMsg() << "Class '" << qPrintable(context) |
1811 yyMsg() << qPrintable(LU::tr("Class '%1' lacks Q_OBJECT macro\n") |
1810 << "' lacks Q_OBJECT macro\n"; |
1812 .arg(context)); |
1811 fctx->complained = true; |
1813 fctx->complained = true; |
1812 } |
1814 } |
1813 goto gotctx; |
1815 goto gotctx; |
1814 } |
1816 } |
1815 --idx; |
1817 --idx; |
1833 } else { |
1835 } else { |
1834 #ifdef DIAGNOSE_RETRANSLATABILITY |
1836 #ifdef DIAGNOSE_RETRANSLATABILITY |
1835 int last = prefix.lastIndexOf(strColons); |
1837 int last = prefix.lastIndexOf(strColons); |
1836 QString className = prefix.mid(last == -1 ? 0 : last + 2); |
1838 QString className = prefix.mid(last == -1 ? 0 : last + 2); |
1837 if (!className.isEmpty() && className == functionName) { |
1839 if (!className.isEmpty() && className == functionName) { |
1838 yyMsg() << "It is not recommended to call tr() from within a constructor '" |
1840 yyMsg() << qPrintable(LU::tr("It is not recommended to call tr() from within a constructor '%1::%2'\n") |
1839 << qPrintable(className) << "::" << qPrintable(functionName) << "'\n"; |
1841 .arg(className).arg(functionName)); |
1840 } |
1842 } |
1841 #endif |
1843 #endif |
1842 prefix.chop(2); |
1844 prefix.chop(2); |
1843 NamespaceList nsl; |
1845 NamespaceList nsl; |
1844 QStringList unresolved; |
1846 QStringList unresolved; |
1849 fctx->trQualification = context; |
1851 fctx->trQualification = context; |
1850 } else { |
1852 } else { |
1851 context = fctx->trQualification; |
1853 context = fctx->trQualification; |
1852 } |
1854 } |
1853 if (!fctx->hasTrFunctions && !fctx->complained) { |
1855 if (!fctx->hasTrFunctions && !fctx->complained) { |
1854 yyMsg() << "Class '" << qPrintable(context) << "' lacks Q_OBJECT macro\n"; |
1856 yyMsg() << qPrintable(LU::tr("Class '%1' lacks Q_OBJECT macro\n").arg(context)); |
1855 fctx->complained = true; |
1857 fctx->complained = true; |
1856 } |
1858 } |
1857 } else { |
1859 } else { |
1858 context = (stringListifyNamespace(nsl) + unresolved).join(strColons); |
1860 context = (stringListifyNamespace(nsl) + unresolved).join(strColons); |
1859 } |
1861 } |
1871 case Tok_translateUtf8: |
1873 case Tok_translateUtf8: |
1872 case Tok_translate: |
1874 case Tok_translate: |
1873 if (!tor) |
1875 if (!tor) |
1874 goto case_default; |
1876 goto case_default; |
1875 if (!sourcetext.isEmpty()) |
1877 if (!sourcetext.isEmpty()) |
1876 yyMsg() << "//% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n"; |
1878 yyMsg() << qPrintable(LU::tr("//% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n")); |
1877 utf8 = (yyTok == Tok_translateUtf8); |
1879 utf8 = (yyTok == Tok_translateUtf8); |
1878 line = yyLineNo; |
1880 line = yyLineNo; |
1879 yyTok = getToken(); |
1881 yyTok = getToken(); |
1880 if (match(Tok_LeftParen) |
1882 if (match(Tok_LeftParen) |
1881 && matchString(&context) |
1883 && matchString(&context) |
1926 break; |
1928 break; |
1927 case Tok_trid: |
1929 case Tok_trid: |
1928 if (!tor) |
1930 if (!tor) |
1929 goto case_default; |
1931 goto case_default; |
1930 if (!msgid.isEmpty()) |
1932 if (!msgid.isEmpty()) |
1931 yyMsg() << "//= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n"; |
1933 yyMsg() << qPrintable(LU::tr("//= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n")); |
1932 //utf8 = false; // Maybe use //%% or something like that |
1934 //utf8 = false; // Maybe use //%% or something like that |
1933 line = yyLineNo; |
1935 line = yyLineNo; |
1934 yyTok = getToken(); |
1936 yyTok = getToken(); |
1935 if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { |
1937 if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { |
1936 bool plural = match(Tok_Comma); |
1938 bool plural = match(Tok_Comma); |
1993 break; |
1995 break; |
1994 c = yyWord.unicode()[p++].unicode(); |
1996 c = yyWord.unicode()[p++].unicode(); |
1995 if (isspace(c)) |
1997 if (isspace(c)) |
1996 continue; |
1998 continue; |
1997 if (c != '"') { |
1999 if (c != '"') { |
1998 yyMsg() << "Unexpected character in meta string\n"; |
2000 yyMsg() << qPrintable(LU::tr("Unexpected character in meta string\n")); |
1999 break; |
2001 break; |
2000 } |
2002 } |
2001 forever { |
2003 forever { |
2002 if (p >= yyWord.length()) { |
2004 if (p >= yyWord.length()) { |
2003 whoops: |
2005 whoops: |
2004 yyMsg() << "Unterminated meta string\n"; |
2006 yyMsg() << qPrintable(LU::tr("Unterminated meta string\n")); |
2005 break; |
2007 break; |
2006 } |
2008 } |
2007 c = yyWord.unicode()[p++].unicode(); |
2009 c = yyWord.unicode()[p++].unicode(); |
2008 if (c == '"') |
2010 if (c == '"') |
2009 break; |
2011 break; |
2052 break; |
2054 break; |
2053 } |
2055 } |
2054 case Tok_Arrow: |
2056 case Tok_Arrow: |
2055 yyTok = getToken(); |
2057 yyTok = getToken(); |
2056 if (yyTok == Tok_tr || yyTok == Tok_trUtf8) |
2058 if (yyTok == Tok_tr || yyTok == Tok_trUtf8) |
2057 yyMsg() << "Cannot invoke tr() like this\n"; |
2059 yyMsg() << qPrintable(LU::tr("Cannot invoke tr() like this\n")); |
2058 break; |
2060 break; |
2059 case Tok_ColonColon: |
2061 case Tok_ColonColon: |
2060 if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0 && !yyTokColonSeen) |
2062 if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0 && !yyTokColonSeen) |
2061 prospectiveContext = prefix; |
2063 prospectiveContext = prefix; |
2062 prefix += strColons; |
2064 prefix += strColons; |
2125 } |
2127 } |
2126 } |
2128 } |
2127 |
2129 |
2128 if (yyBraceDepth != 0) |
2130 if (yyBraceDepth != 0) |
2129 yyMsg(yyBraceLineNo) |
2131 yyMsg(yyBraceLineNo) |
2130 << "Unbalanced opening brace in C++ code" |
2132 << qPrintable(LU::tr("Unbalanced opening brace in C++ code" |
2131 " (or abuse of the C++ preprocessor)\n"; |
2133 " (or abuse of the C++ preprocessor)\n")); |
2132 else if (yyParenDepth != 0) |
2134 else if (yyParenDepth != 0) |
2133 yyMsg(yyParenLineNo) |
2135 yyMsg(yyParenLineNo) |
2134 << "Unbalanced opening parenthesis in C++ code" |
2136 << qPrintable(LU::tr("Unbalanced opening parenthesis in C++ code" |
2135 " (or abuse of the C++ preprocessor)\n"; |
2137 " (or abuse of the C++ preprocessor)\n")); |
2136 else if (yyBracketDepth != 0) |
2138 else if (yyBracketDepth != 0) |
2137 yyMsg(yyBracketLineNo) |
2139 yyMsg(yyBracketLineNo) |
2138 << "Unbalanced opening bracket in C++ code" |
2140 << qPrintable(LU::tr("Unbalanced opening bracket in C++ code" |
2139 " (or abuse of the C++ preprocessor)\n"; |
2141 " (or abuse of the C++ preprocessor)\n")); |
2140 } |
2142 } |
2141 |
2143 |
2142 const ParseResults *CppParser::recordResults(bool isHeader) |
2144 const ParseResults *CppParser::recordResults(bool isHeader) |
2143 { |
2145 { |
2144 if (tor) { |
2146 if (tor) { |
2195 if (CppFiles::getResults(filename) || CppFiles::isBlacklisted(filename)) |
2197 if (CppFiles::getResults(filename) || CppFiles::isBlacklisted(filename)) |
2196 continue; |
2198 continue; |
2197 |
2199 |
2198 QFile file(filename); |
2200 QFile file(filename); |
2199 if (!file.open(QIODevice::ReadOnly)) { |
2201 if (!file.open(QIODevice::ReadOnly)) { |
2200 cd.appendError(QString::fromLatin1("Cannot open %1: %2") |
2202 cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString())); |
2201 .arg(filename, file.errorString())); |
|
2202 continue; |
2203 continue; |
2203 } |
2204 } |
2204 |
2205 |
2205 CppParser parser; |
2206 CppParser parser; |
2206 QTextStream ts(&file); |
2207 QTextStream ts(&file); |