tools/linguist/lupdate/cpp.cpp
changeset 22 79de32ba3296
parent 19 fcece45ef507
child 33 3e2da88830cd
equal deleted inserted replaced
19:fcece45ef507 22:79de32ba3296
    63 
    63 
    64 //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this
    64 //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this
    65 
    65 
    66 class HashString {
    66 class HashString {
    67 public:
    67 public:
    68     HashString() : m_hashed(false) {}
    68     HashString() : m_hash(0x80000000) {}
    69     explicit HashString(const QString &str) : m_str(str), m_hashed(false) {}
    69     explicit HashString(const QString &str) : m_str(str), m_hash(0x80000000) {}
    70     void setValue(const QString &str) { m_str = str; m_hashed = false; }
    70     void setValue(const QString &str) { m_str = str; m_hash = 0x80000000; }
    71     const QString &value() const { return m_str; }
    71     const QString &value() const { return m_str; }
    72     bool operator==(const HashString &other) const { return m_str == other.m_str; }
    72     bool operator==(const HashString &other) const { return m_str == other.m_str; }
    73 private:
    73 private:
    74     QString m_str;
    74     QString m_str;
       
    75     // qHash() of a QString is only 28 bits wide, so we can use
       
    76     // the highest bit(s) as the "hash valid" flag.
    75     mutable uint m_hash;
    77     mutable uint m_hash;
    76     mutable bool m_hashed;
       
    77     friend uint qHash(const HashString &str);
    78     friend uint qHash(const HashString &str);
    78 };
    79 };
    79 
    80 
    80 uint qHash(const HashString &str)
    81 uint qHash(const HashString &str)
    81 {
    82 {
    82     if (!str.m_hashed) {
    83     if (str.m_hash & 0x80000000)
    83         str.m_hashed = true;
       
    84         str.m_hash = qHash(str.m_str);
    84         str.m_hash = qHash(str.m_str);
    85     }
       
    86     return str.m_hash;
    85     return str.m_hash;
    87 }
    86 }
    88 
    87 
    89 class HashStringList {
    88 class HashStringList {
    90 public:
    89 public:
    91     explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hashed(false) {}
    90     explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hash(0x80000000) {}
    92     const QList<HashString> &value() const { return m_list; }
    91     const QList<HashString> &value() const { return m_list; }
    93     bool operator==(const HashStringList &other) const { return m_list == other.m_list; }
    92     bool operator==(const HashStringList &other) const { return m_list == other.m_list; }
    94 private:
    93 private:
    95     QList<HashString> m_list;
    94     QList<HashString> m_list;
    96     mutable uint m_hash;
    95     mutable uint m_hash;
    97     mutable bool m_hashed;
       
    98     friend uint qHash(const HashStringList &list);
    96     friend uint qHash(const HashStringList &list);
    99 };
    97 };
   100 
    98 
   101 uint qHash(const HashStringList &list)
    99 uint qHash(const HashStringList &list)
   102 {
   100 {
   103     if (!list.m_hashed) {
   101     if (list.m_hash & 0x80000000) {
   104         list.m_hashed = true;
       
   105         uint hash = 0;
   102         uint hash = 0;
   106         foreach (const HashString &qs, list.m_list) {
   103         foreach (const HashString &qs, list.m_list) {
   107             hash ^= qHash(qs) ^ 0xa09df22f;
   104             hash ^= qHash(qs) ^ 0x0ad9f526;
   108             hash = (hash << 13) | (hash >> 19);
   105             hash = ((hash << 13) & 0x0fffffff) | (hash >> 15);
   109         }
   106         }
   110         list.m_hash = hash;
   107         list.m_hash = hash;
   111     }
   108     }
   112     return list.m_hash;
   109     return list.m_hash;
   113 }
   110 }
   213     };
   210     };
   214 
   211 
   215 private:
   212 private:
   216     struct IfdefState {
   213     struct IfdefState {
   217         IfdefState() {}
   214         IfdefState() {}
   218         IfdefState(int _braceDepth, int _parenDepth) :
   215         IfdefState(int _bracketDepth, int _braceDepth, int _parenDepth) :
       
   216             bracketDepth(_bracketDepth),
   219             braceDepth(_braceDepth),
   217             braceDepth(_braceDepth),
   220             parenDepth(_parenDepth),
   218             parenDepth(_parenDepth),
   221             elseLine(-1)
   219             elseLine(-1)
   222         {}
   220         {}
   223 
   221 
   224         SavedState state;
   222         SavedState state;
       
   223         int bracketDepth, bracketDepth1st;
   225         int braceDepth, braceDepth1st;
   224         int braceDepth, braceDepth1st;
   226         int parenDepth, parenDepth1st;
   225         int parenDepth, parenDepth1st;
   227         int elseLine;
   226         int elseLine;
   228     };
   227     };
   229 
   228 
   278     void truncateNamespaces(NamespaceList *namespaces, int lenght);
   277     void truncateNamespaces(NamespaceList *namespaces, int lenght);
   279     Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true);
   278     Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true);
   280 
   279 
   281     enum {
   280     enum {
   282         Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return,
   281         Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return,
   283         Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid,
   282         Tok_tr, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid,
   284         Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS,
   283         Tok_Q_OBJECT, Tok_Q_DECLARE_TR_FUNCTIONS,
   285         Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon,
   284         Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon,
   286         Tok_Equals,
   285         Tok_Equals, Tok_LeftBracket, Tok_RightBracket,
   287         Tok_LeftBrace = 30, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon,
   286         Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon,
   288         Tok_Null = 40, Tok_Integer,
   287         Tok_Null, Tok_Integer,
   289         Tok_QuotedInclude = 50, Tok_AngledInclude,
   288         Tok_QuotedInclude, Tok_AngledInclude,
   290         Tok_Other = 99
   289         Tok_Other
   291     };
   290     };
   292 
   291 
   293     // Tokenizer state
   292     // Tokenizer state
   294     QString yyFileName;
   293     QString yyFileName;
   295     int yyCh;
   294     int yyCh;
   297     bool yyCodecIsUtf8;
   296     bool yyCodecIsUtf8;
   298     bool yyForceUtf8;
   297     bool yyForceUtf8;
   299     QString yyWord;
   298     QString yyWord;
   300     qlonglong yyInteger;
   299     qlonglong yyInteger;
   301     QStack<IfdefState> yyIfdefStack;
   300     QStack<IfdefState> yyIfdefStack;
       
   301     int yyBracketDepth;
   302     int yyBraceDepth;
   302     int yyBraceDepth;
   303     int yyParenDepth;
   303     int yyParenDepth;
   304     int yyLineNo;
   304     int yyLineNo;
   305     int yyCurLineNo;
   305     int yyCurLineNo;
       
   306     int yyBracketLineNo;
   306     int yyBraceLineNo;
   307     int yyBraceLineNo;
   307     int yyParenLineNo;
   308     int yyParenLineNo;
   308 
   309 
   309     // the string to read from and current position in the string
   310     // the string to read from and current position in the string
   310     QTextCodec *yySourceCodec;
   311     QTextCodec *yySourceCodec;
   337         directInclude = true;
   338         directInclude = true;
   338     } else {
   339     } else {
   339         results = new ParseResults;
   340         results = new ParseResults;
   340         directInclude = false;
   341         directInclude = false;
   341     }
   342     }
       
   343     yyBracketDepth = 0;
   342     yyBraceDepth = 0;
   344     yyBraceDepth = 0;
   343     yyParenDepth = 0;
   345     yyParenDepth = 0;
   344     yyCurLineNo = 1;
   346     yyCurLineNo = 1;
       
   347     yyBracketLineNo = 1;
   345     yyBraceLineNo = 1;
   348     yyBraceLineNo = 1;
   346     yyParenLineNo = 1;
   349     yyParenLineNo = 1;
   347     yyAtNewline = true;
   350     yyAtNewline = true;
   348     yyMinBraceDepth = 0;
   351     yyMinBraceDepth = 0;
   349     inDefine = false;
   352     inDefine = false;
   566                 goto restart;
   569                 goto restart;
   567             case 'i':
   570             case 'i':
   568                 yyCh = getChar();
   571                 yyCh = getChar();
   569                 if (yyCh == 'f') {
   572                 if (yyCh == 'f') {
   570                     // if, ifdef, ifndef
   573                     // if, ifdef, ifndef
   571                     yyIfdefStack.push(IfdefState(yyBraceDepth, yyParenDepth));
   574                     yyIfdefStack.push(IfdefState(yyBracketDepth, yyBraceDepth, yyParenDepth));
   572                     yyCh = getChar();
   575                     yyCh = getChar();
   573                 } else if (yyCh == 'n') {
   576                 } else if (yyCh == 'n') {
   574                     // include
   577                     // include
   575                     do {
   578                     do {
   576                         yyCh = getChar();
   579                         yyCh = getChar();
   605                 if (yyCh == 'l') {
   608                 if (yyCh == 'l') {
   606                     // elif, else
   609                     // elif, else
   607                     if (!yyIfdefStack.isEmpty()) {
   610                     if (!yyIfdefStack.isEmpty()) {
   608                         IfdefState &is = yyIfdefStack.top();
   611                         IfdefState &is = yyIfdefStack.top();
   609                         if (is.elseLine != -1) {
   612                         if (is.elseLine != -1) {
   610                             if (yyBraceDepth != is.braceDepth1st || yyParenDepth != is.parenDepth1st)
   613                             if (yyBracketDepth != is.bracketDepth1st
   611                                 qWarning("%s:%d: Parenthesis/brace mismatch between "
   614                                 || yyBraceDepth != is.braceDepth1st
       
   615                                 || yyParenDepth != is.parenDepth1st)
       
   616                                 qWarning("%s:%d: Parenthesis/bracket/brace mismatch between "
   612                                          "#if and #else branches; using #if branch\n",
   617                                          "#if and #else branches; using #if branch\n",
   613                                          qPrintable(yyFileName), is.elseLine);
   618                                          qPrintable(yyFileName), is.elseLine);
   614                         } else {
   619                         } else {
       
   620                             is.bracketDepth1st = yyBracketDepth;
   615                             is.braceDepth1st = yyBraceDepth;
   621                             is.braceDepth1st = yyBraceDepth;
   616                             is.parenDepth1st = yyParenDepth;
   622                             is.parenDepth1st = yyParenDepth;
   617                             saveState(&is.state);
   623                             saveState(&is.state);
   618                         }
   624                         }
   619                         is.elseLine = yyLineNo;
   625                         is.elseLine = yyLineNo;
       
   626                         yyBracketDepth = is.bracketDepth;
   620                         yyBraceDepth = is.braceDepth;
   627                         yyBraceDepth = is.braceDepth;
   621                         yyParenDepth = is.parenDepth;
   628                         yyParenDepth = is.parenDepth;
   622                     }
   629                     }
   623                     yyCh = getChar();
   630                     yyCh = getChar();
   624                 } else if (yyCh == 'n') {
   631                 } else if (yyCh == 'n') {
   625                     // endif
   632                     // endif
   626                     if (!yyIfdefStack.isEmpty()) {
   633                     if (!yyIfdefStack.isEmpty()) {
   627                         IfdefState is = yyIfdefStack.pop();
   634                         IfdefState is = yyIfdefStack.pop();
   628                         if (is.elseLine != -1) {
   635                         if (is.elseLine != -1) {
   629                             if (yyBraceDepth != is.braceDepth1st || yyParenDepth != is.parenDepth1st)
   636                             if (yyBracketDepth != is.bracketDepth1st
       
   637                                 || yyBraceDepth != is.braceDepth1st
       
   638                                 || yyParenDepth != is.parenDepth1st)
   630                                 qWarning("%s:%d: Parenthesis/brace mismatch between "
   639                                 qWarning("%s:%d: Parenthesis/brace mismatch between "
   631                                          "#if and #else branches; using #if branch\n",
   640                                          "#if and #else branches; using #if branch\n",
   632                                          qPrintable(yyFileName), is.elseLine);
   641                                          qPrintable(yyFileName), is.elseLine);
       
   642                             yyBracketDepth = is.bracketDepth1st;
   633                             yyBraceDepth = is.braceDepth1st;
   643                             yyBraceDepth = is.braceDepth1st;
   634                             yyParenDepth = is.parenDepth1st;
   644                             yyParenDepth = is.parenDepth1st;
   635                             loadState(&is.state);
   645                             loadState(&is.state);
   636                         }
   646                         }
   637                     }
   647                     }
   900                              qPrintable(yyFileName), yyCurLineNo);
   910                              qPrintable(yyFileName), yyCurLineNo);
   901                 else
   911                 else
   902                     yyParenDepth--;
   912                     yyParenDepth--;
   903                 yyCh = getChar();
   913                 yyCh = getChar();
   904                 return Tok_RightParen;
   914                 return Tok_RightParen;
       
   915             case '[':
       
   916                 if (yyBracketDepth == 0)
       
   917                     yyBracketLineNo = yyCurLineNo;
       
   918                 yyBracketDepth++;
       
   919                 yyCh = getChar();
       
   920                 return Tok_LeftBracket;
       
   921             case ']':
       
   922                 if (yyBracketDepth == 0)
       
   923                     qWarning("%s:%d: Excess closing bracket in C++ code"
       
   924                              " (or abuse of the C++ preprocessor)\n",
       
   925                              qPrintable(yyFileName), yyCurLineNo);
       
   926                 else
       
   927                     yyBracketDepth--;
       
   928                 yyCh = getChar();
       
   929                 return Tok_RightBracket;
   905             case ',':
   930             case ',':
   906                 yyCh = getChar();
   931                 yyCh = getChar();
   907                 return Tok_Comma;
   932                 return Tok_Comma;
   908             case ';':
   933             case ';':
   909                 yyCh = getChar();
   934                 yyCh = getChar();
  1535     yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking.
  1560     yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking.
  1536     yyInPtr = (const ushort *)yyInStr.unicode();
  1561     yyInPtr = (const ushort *)yyInStr.unicode();
  1537     yyCh = getChar();
  1562     yyCh = getChar();
  1538     yyTok = getToken();
  1563     yyTok = getToken();
  1539     while (yyTok != Tok_Eof) {
  1564     while (yyTok != Tok_Eof) {
       
  1565         // these are array indexing operations. we ignore them entirely
       
  1566         // so they don't confuse our scoping of static initializers.
       
  1567         // we enter the loop by either reading a left bracket or by an
       
  1568         // #else popping the state.
       
  1569         while (yyBracketDepth)
       
  1570             yyTok = getToken();
  1540         //qDebug() << "TOKEN: " << yyTok;
  1571         //qDebug() << "TOKEN: " << yyTok;
  1541         switch (yyTok) {
  1572         switch (yyTok) {
  1542         case Tok_QuotedInclude: {
  1573         case Tok_QuotedInclude: {
  1543             text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord);
  1574             text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord);
  1544             text.detach();
  1575             text.detach();
  2002                     if (k == -1) {
  2033                     if (k == -1) {
  2003                         context = comment;
  2034                         context = comment;
  2004                     } else {
  2035                     } else {
  2005                         context = comment.left(k);
  2036                         context = comment.left(k);
  2006                         comment.remove(0, k + 1);
  2037                         comment.remove(0, k + 1);
  2007                         recordMessage(yyLineNo, context, QString(), comment, extracomment,
  2038                         TranslatorMessage msg(
  2008                                       QString(), TranslatorMessage::ExtraData(), false, false);
  2039                                 transcode(context, false), QString(),
       
  2040                                 transcode(comment, false), QString(),
       
  2041                                 yyFileName, yyLineNo, QStringList(),
       
  2042                                 TranslatorMessage::Finished, false);
       
  2043                         msg.setExtraComment(transcode(extracomment.simplified(), false));
  2009                         extracomment.clear();
  2044                         extracomment.clear();
       
  2045                         tor->append(msg);
  2010                         tor->setExtras(extra);
  2046                         tor->setExtras(extra);
  2011                         extra.clear();
  2047                         extra.clear();
  2012                     }
  2048                     }
  2013                 }
  2049                 }
  2014             }
  2050             }
  2075             yyTok = getToken();
  2111             yyTok = getToken();
  2076             break;
  2112             break;
  2077         default:
  2113         default:
  2078             if (!yyParenDepth)
  2114             if (!yyParenDepth)
  2079                 prospectiveContext.clear();
  2115                 prospectiveContext.clear();
       
  2116             // fallthrough
       
  2117         case Tok_Equals: // for static initializers; other cases make no difference
       
  2118         case Tok_RightBracket: // ignoring indexing; same reason
  2080         case_default:
  2119         case_default:
  2081             yyTok = getToken();
  2120             yyTok = getToken();
  2082             break;
  2121             break;
  2083         }
  2122         }
  2084     }
  2123     }
  2089                   qPrintable(yyFileName), yyBraceLineNo);
  2128                   qPrintable(yyFileName), yyBraceLineNo);
  2090     else if (yyParenDepth != 0)
  2129     else if (yyParenDepth != 0)
  2091         qWarning("%s:%d: Unbalanced opening parenthesis in C++ code"
  2130         qWarning("%s:%d: Unbalanced opening parenthesis in C++ code"
  2092                  " (or abuse of the C++ preprocessor)\n",
  2131                  " (or abuse of the C++ preprocessor)\n",
  2093                  qPrintable(yyFileName), yyParenLineNo);
  2132                  qPrintable(yyFileName), yyParenLineNo);
       
  2133     else if (yyBracketDepth != 0)
       
  2134         qWarning("%s:%d: Unbalanced opening bracket in C++ code"
       
  2135                  " (or abuse of the C++ preprocessor)\n",
       
  2136                  qPrintable(yyFileName), yyBracketLineNo);
  2094 }
  2137 }
  2095 
  2138 
  2096 const ParseResults *CppParser::recordResults(bool isHeader)
  2139 const ParseResults *CppParser::recordResults(bool isHeader)
  2097 {
  2140 {
  2098     if (tor) {
  2141     if (tor) {