diff --git a/src/plugins/debugger/name_demangler.cpp b/src/plugins/debugger/name_demangler.cpp index eada59ec637d1d1e6e40e9d18238aae0392bcea8..3f82cc938d03daac4d3940914d3d6f957332c4a3 100644 --- a/src/plugins/debugger/name_demangler.cpp +++ b/src/plugins/debugger/name_demangler.cpp @@ -46,7 +46,7 @@ //#define DO_TRACE #ifdef DO_TRACE #define FUNC_START() \ - qDebug("Function %s has started, input is at position %d.", Q_FUNC_INFO, pos) + qDebug("Function %s has started, input is at position %d.", Q_FUNC_INFO, m_pos) #define FUNC_END(result) \ qDebug("Function %s has finished, result is '%s'.", Q_FUNC_INFO, qPrintable(result)) #else @@ -291,6 +291,7 @@ private: QString m_demangledName; QList<QByteArray> m_substitutions; QList<QByteArray> m_templateParams; + bool m_isConversionOperator; }; @@ -319,6 +320,7 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName) try { m_mangledName = mangledName.toAscii(); m_pos = 0; + m_isConversionOperator = false; m_demangledName.clear(); m_substitutions.clear(); m_templateParams.clear(); @@ -330,9 +332,9 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName) if (m_pos != m_mangledName.size()) throw ParseException(QLatin1String("Unconsumed input")); #ifdef DO_TRACE - qDebug("%d", substitutions.size()); - foreach (const QByteArray &s, substitutions) - qDebug(qPrintable(s)); + qDebug("%d", m_substitutions.size()); + foreach (const QByteArray &s, m_substitutions) + qDebug("%s", s.constData()); #endif return true; } catch (const ParseException &p) { @@ -395,10 +397,9 @@ const QByteArray NameDemanglerPrivate::parseEncoding() * Instantiations of function templates encode their return type, * normal functions do not. Also, constructors, destructors * and conversion operators never encode their return type. - * TODO: The latter are probably not handled yet. */ int start; - if (encoding.endsWith('>')) { // Template instantiation. + if (!m_isConversionOperator && encoding.endsWith('>')) { // Template instantiation. start = 1; encoding.prepend(signature.first() + ' '); } else { // Normal function. @@ -419,6 +420,7 @@ const QByteArray NameDemanglerPrivate::parseEncoding() addSubstitution(encoding); } m_templateParams.clear(); + m_isConversionOperator = false; } else if (firstSetSpecialName.contains(next)) { encoding = parseSpecialName(); } else { @@ -657,7 +659,15 @@ const QByteArray NameDemanglerPrivate::parseTemplateParam() index = parseNonNegativeNumber() + 1; if (advance() != '_') throw ParseException(QString::fromLatin1("Invalid template-param")); - param = m_templateParams.at(index); + if (index >= m_templateParams.count()) { + if (!m_isConversionOperator) { + throw ParseException(QString::fromLocal8Bit("Invalid template parameter index %1") + .arg(index)); + } + param = QByteArray::number(index); + } else { + param = m_templateParams.at(index); + } FUNC_END(param); return param; @@ -746,17 +756,17 @@ double NameDemanglerPrivate::parseFloat() * <template-arg> ::= <type> # type or template * ::= X <expression> E # expression * ::= <expr-primary> # simple expressions - * ::= I <template-arg>* E # argument pack + * ::= J <template-arg>* E # argument pack * ::= sp <expression> # pack expansion of (C++0x) */ const QByteArray NameDemanglerPrivate::parseTemplateArg() { FUNC_START(); - Q_ASSERT(!firstSetType.contains('X') && !firstSetType.contains('I') + Q_ASSERT(!firstSetType.contains('X') && !firstSetType.contains('J') /* && !firstSetType.contains('s') */); Q_ASSERT((firstSetType & firstSetExprPrimary).isEmpty()); Q_ASSERT(!firstSetExprPrimary.contains('X') - && !firstSetExprPrimary.contains('I') + && !firstSetExprPrimary.contains('J') && !firstSetExprPrimary.contains('s')); Q_ASSERT(!firstSetTemplateArg.contains('E')); @@ -774,7 +784,7 @@ const QByteArray NameDemanglerPrivate::parseTemplateArg() arg = parseExpression(); if (advance() != 'E') throw ParseException(QString::fromLatin1("Invalid template-arg")); - } else if (next == 'I') { + } else if (next == 'J') { advance(); while (firstSetTemplateArg.contains(peek())) { if (!arg.isEmpty()) @@ -838,7 +848,7 @@ const QByteArray NameDemanglerPrivate::parseExpression() /* * Some of the terminals in the productions of <expression> - * also appear in the productions of operator-name. We assume the direct + * also appear in the productions of <operator-name>. We assume the direct * productions to have higher precedence and check them first to prevent * them being parsed by parseOperatorName(). */ @@ -1091,11 +1101,21 @@ const QByteArray NameDemanglerPrivate::parseType() type = parsePointerToMemberType(); } else if (firstSetTemplateParam.contains(next)) { type = parseTemplateParam(); + const int typeLen = type.count(); + bool ok; + const int index = type.toInt(&ok); addSubstitution(type); if (firstSetTemplateArgs.contains(peek())) { type += parseTemplateArgs(); addSubstitution(type); } + if (ok) { + if (index >= m_templateParams.count()) { + throw ParseException(QString::fromLocal8Bit("Invalid tenplate parameter " + "index %1 in forwarding").arg(index)); + } + type.replace(0, typeLen, m_templateParams.at(index)); + } } else if (firstSetSubstitution.contains(next)) { type = parseSubstitution(); if (firstSetTemplateArgs.contains(peek())) { @@ -1290,7 +1310,7 @@ const QList<QByteArray> NameDemanglerPrivate::parseBareFunctionType() signature.append(parseType()); while (firstSetType.contains(peek())); - FUNC_END(signature.join(':')); + FUNC_END(QString::number(signature.count())); return signature; } @@ -1404,8 +1424,9 @@ const NameDemanglerPrivate::Operator &NameDemanglerPrivate::parseOperatorName() advance(2); if (id == "cv") { static UnaryOperator castOp("cv", ""); + m_isConversionOperator = true; QByteArray type = parseType(); - castOp.repr = '(' + type + ')'; + castOp.repr = ' ' + type; op = &castOp; } else { op = ops.value(id); @@ -1941,8 +1962,8 @@ void NameDemanglerPrivate::setupOps() ops["nt"] = new UnaryOperator("nt", "!"); ops["aa"] = new BinaryOperator("aa", "&&"); ops["oo"] = new BinaryOperator("oo", "||"); - ops["pp"] = new UnaryOperator("pp", "++"); // Prefix? - ops["mm"] = new UnaryOperator("mm", "--"); // Prefix? + ops["pp"] = new UnaryOperator("pp", "++"); + ops["mm"] = new UnaryOperator("mm", "--"); ops["cm"] = new BinaryOperator("cm", ","); ops["pm"] = new BinOpWithNoSpaces("pm", "->*"); ops["pt"] = new BinOpWithNoSpaces("pm", "->"); diff --git a/tests/auto/debugger/tst_namedemangler.cpp b/tests/auto/debugger/tst_namedemangler.cpp index 0586877c9af676a1d424f1069e6b5c22b3452f45..3c93050d7054a340a3bd53d6f36184fe2a072f79 100644 --- a/tests/auto/debugger/tst_namedemangler.cpp +++ b/tests/auto/debugger/tst_namedemangler.cpp @@ -164,6 +164,12 @@ void NameDemanglerAutoTest::testCorrectlyMangledNames() "test_func(void const * (ns1::c<unsigned long>::*)(int *, long &, unsigned long) const)"); testCorrectlyMangledName("_ZN3ns11fEPKPFPKiS1_RKhE", "ns1::f(int const * (* const *)(int const *, unsigned char const &))"); + testCorrectlyMangledName("_ZNK1CcviEv", "C::operator int() const"); + testCorrectlyMangledName("_ZN1CppEv", "C::operator++()"); + testCorrectlyMangledName("_ZN1CmmEv", "C::operator--()"); + testCorrectlyMangledName("_ZN1CppEi", "C::operator++(int)"); + testCorrectlyMangledName("_ZN1CmmEi", "C::operator--(int)"); + testCorrectlyMangledName("_ZNK1CcvT_IPKcEEv", "C::operator char const *<char const *>() const"); } void NameDemanglerAutoTest::testIncorrectlyMangledNames()