forked from qt-creator/qt-creator
Debugger: Name demangler improvements.
- Correctly decode conversion operators and add test cases. - Adapt to change in the specification regarding template parameter packs. - Make #ifdef'ed code compile. Change-Id: Ifea1408d08172f9aeccd5e64a1e4818cd632a0d0 Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -46,7 +46,7 @@
|
|||||||
//#define DO_TRACE
|
//#define DO_TRACE
|
||||||
#ifdef DO_TRACE
|
#ifdef DO_TRACE
|
||||||
#define FUNC_START() \
|
#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) \
|
#define FUNC_END(result) \
|
||||||
qDebug("Function %s has finished, result is '%s'.", Q_FUNC_INFO, qPrintable(result))
|
qDebug("Function %s has finished, result is '%s'.", Q_FUNC_INFO, qPrintable(result))
|
||||||
#else
|
#else
|
||||||
@@ -291,6 +291,7 @@ private:
|
|||||||
QString m_demangledName;
|
QString m_demangledName;
|
||||||
QList<QByteArray> m_substitutions;
|
QList<QByteArray> m_substitutions;
|
||||||
QList<QByteArray> m_templateParams;
|
QList<QByteArray> m_templateParams;
|
||||||
|
bool m_isConversionOperator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -319,6 +320,7 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName)
|
|||||||
try {
|
try {
|
||||||
m_mangledName = mangledName.toAscii();
|
m_mangledName = mangledName.toAscii();
|
||||||
m_pos = 0;
|
m_pos = 0;
|
||||||
|
m_isConversionOperator = false;
|
||||||
m_demangledName.clear();
|
m_demangledName.clear();
|
||||||
m_substitutions.clear();
|
m_substitutions.clear();
|
||||||
m_templateParams.clear();
|
m_templateParams.clear();
|
||||||
@@ -330,9 +332,9 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName)
|
|||||||
if (m_pos != m_mangledName.size())
|
if (m_pos != m_mangledName.size())
|
||||||
throw ParseException(QLatin1String("Unconsumed input"));
|
throw ParseException(QLatin1String("Unconsumed input"));
|
||||||
#ifdef DO_TRACE
|
#ifdef DO_TRACE
|
||||||
qDebug("%d", substitutions.size());
|
qDebug("%d", m_substitutions.size());
|
||||||
foreach (const QByteArray &s, substitutions)
|
foreach (const QByteArray &s, m_substitutions)
|
||||||
qDebug(qPrintable(s));
|
qDebug("%s", s.constData());
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
} catch (const ParseException &p) {
|
} catch (const ParseException &p) {
|
||||||
@@ -395,10 +397,9 @@ const QByteArray NameDemanglerPrivate::parseEncoding()
|
|||||||
* Instantiations of function templates encode their return type,
|
* Instantiations of function templates encode their return type,
|
||||||
* normal functions do not. Also, constructors, destructors
|
* normal functions do not. Also, constructors, destructors
|
||||||
* and conversion operators never encode their return type.
|
* and conversion operators never encode their return type.
|
||||||
* TODO: The latter are probably not handled yet.
|
|
||||||
*/
|
*/
|
||||||
int start;
|
int start;
|
||||||
if (encoding.endsWith('>')) { // Template instantiation.
|
if (!m_isConversionOperator && encoding.endsWith('>')) { // Template instantiation.
|
||||||
start = 1;
|
start = 1;
|
||||||
encoding.prepend(signature.first() + ' ');
|
encoding.prepend(signature.first() + ' ');
|
||||||
} else { // Normal function.
|
} else { // Normal function.
|
||||||
@@ -419,6 +420,7 @@ const QByteArray NameDemanglerPrivate::parseEncoding()
|
|||||||
addSubstitution(encoding);
|
addSubstitution(encoding);
|
||||||
}
|
}
|
||||||
m_templateParams.clear();
|
m_templateParams.clear();
|
||||||
|
m_isConversionOperator = false;
|
||||||
} else if (firstSetSpecialName.contains(next)) {
|
} else if (firstSetSpecialName.contains(next)) {
|
||||||
encoding = parseSpecialName();
|
encoding = parseSpecialName();
|
||||||
} else {
|
} else {
|
||||||
@@ -657,7 +659,15 @@ const QByteArray NameDemanglerPrivate::parseTemplateParam()
|
|||||||
index = parseNonNegativeNumber() + 1;
|
index = parseNonNegativeNumber() + 1;
|
||||||
if (advance() != '_')
|
if (advance() != '_')
|
||||||
throw ParseException(QString::fromLatin1("Invalid template-param"));
|
throw ParseException(QString::fromLatin1("Invalid template-param"));
|
||||||
|
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);
|
param = m_templateParams.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
FUNC_END(param);
|
FUNC_END(param);
|
||||||
return param;
|
return param;
|
||||||
@@ -746,17 +756,17 @@ double NameDemanglerPrivate::parseFloat()
|
|||||||
* <template-arg> ::= <type> # type or template
|
* <template-arg> ::= <type> # type or template
|
||||||
* ::= X <expression> E # expression
|
* ::= X <expression> E # expression
|
||||||
* ::= <expr-primary> # simple expressions
|
* ::= <expr-primary> # simple expressions
|
||||||
* ::= I <template-arg>* E # argument pack
|
* ::= J <template-arg>* E # argument pack
|
||||||
* ::= sp <expression> # pack expansion of (C++0x)
|
* ::= sp <expression> # pack expansion of (C++0x)
|
||||||
*/
|
*/
|
||||||
const QByteArray NameDemanglerPrivate::parseTemplateArg()
|
const QByteArray NameDemanglerPrivate::parseTemplateArg()
|
||||||
{
|
{
|
||||||
FUNC_START();
|
FUNC_START();
|
||||||
Q_ASSERT(!firstSetType.contains('X') && !firstSetType.contains('I')
|
Q_ASSERT(!firstSetType.contains('X') && !firstSetType.contains('J')
|
||||||
/* && !firstSetType.contains('s') */);
|
/* && !firstSetType.contains('s') */);
|
||||||
Q_ASSERT((firstSetType & firstSetExprPrimary).isEmpty());
|
Q_ASSERT((firstSetType & firstSetExprPrimary).isEmpty());
|
||||||
Q_ASSERT(!firstSetExprPrimary.contains('X')
|
Q_ASSERT(!firstSetExprPrimary.contains('X')
|
||||||
&& !firstSetExprPrimary.contains('I')
|
&& !firstSetExprPrimary.contains('J')
|
||||||
&& !firstSetExprPrimary.contains('s'));
|
&& !firstSetExprPrimary.contains('s'));
|
||||||
Q_ASSERT(!firstSetTemplateArg.contains('E'));
|
Q_ASSERT(!firstSetTemplateArg.contains('E'));
|
||||||
|
|
||||||
@@ -774,7 +784,7 @@ const QByteArray NameDemanglerPrivate::parseTemplateArg()
|
|||||||
arg = parseExpression();
|
arg = parseExpression();
|
||||||
if (advance() != 'E')
|
if (advance() != 'E')
|
||||||
throw ParseException(QString::fromLatin1("Invalid template-arg"));
|
throw ParseException(QString::fromLatin1("Invalid template-arg"));
|
||||||
} else if (next == 'I') {
|
} else if (next == 'J') {
|
||||||
advance();
|
advance();
|
||||||
while (firstSetTemplateArg.contains(peek())) {
|
while (firstSetTemplateArg.contains(peek())) {
|
||||||
if (!arg.isEmpty())
|
if (!arg.isEmpty())
|
||||||
@@ -838,7 +848,7 @@ const QByteArray NameDemanglerPrivate::parseExpression()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Some of the terminals in the productions of <expression>
|
* 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
|
* productions to have higher precedence and check them first to prevent
|
||||||
* them being parsed by parseOperatorName().
|
* them being parsed by parseOperatorName().
|
||||||
*/
|
*/
|
||||||
@@ -1091,11 +1101,21 @@ const QByteArray NameDemanglerPrivate::parseType()
|
|||||||
type = parsePointerToMemberType();
|
type = parsePointerToMemberType();
|
||||||
} else if (firstSetTemplateParam.contains(next)) {
|
} else if (firstSetTemplateParam.contains(next)) {
|
||||||
type = parseTemplateParam();
|
type = parseTemplateParam();
|
||||||
|
const int typeLen = type.count();
|
||||||
|
bool ok;
|
||||||
|
const int index = type.toInt(&ok);
|
||||||
addSubstitution(type);
|
addSubstitution(type);
|
||||||
if (firstSetTemplateArgs.contains(peek())) {
|
if (firstSetTemplateArgs.contains(peek())) {
|
||||||
type += parseTemplateArgs();
|
type += parseTemplateArgs();
|
||||||
addSubstitution(type);
|
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)) {
|
} else if (firstSetSubstitution.contains(next)) {
|
||||||
type = parseSubstitution();
|
type = parseSubstitution();
|
||||||
if (firstSetTemplateArgs.contains(peek())) {
|
if (firstSetTemplateArgs.contains(peek())) {
|
||||||
@@ -1290,7 +1310,7 @@ const QList<QByteArray> NameDemanglerPrivate::parseBareFunctionType()
|
|||||||
signature.append(parseType());
|
signature.append(parseType());
|
||||||
while (firstSetType.contains(peek()));
|
while (firstSetType.contains(peek()));
|
||||||
|
|
||||||
FUNC_END(signature.join(':'));
|
FUNC_END(QString::number(signature.count()));
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,8 +1424,9 @@ const NameDemanglerPrivate::Operator &NameDemanglerPrivate::parseOperatorName()
|
|||||||
advance(2);
|
advance(2);
|
||||||
if (id == "cv") {
|
if (id == "cv") {
|
||||||
static UnaryOperator castOp("cv", "");
|
static UnaryOperator castOp("cv", "");
|
||||||
|
m_isConversionOperator = true;
|
||||||
QByteArray type = parseType();
|
QByteArray type = parseType();
|
||||||
castOp.repr = '(' + type + ')';
|
castOp.repr = ' ' + type;
|
||||||
op = &castOp;
|
op = &castOp;
|
||||||
} else {
|
} else {
|
||||||
op = ops.value(id);
|
op = ops.value(id);
|
||||||
@@ -1941,8 +1962,8 @@ void NameDemanglerPrivate::setupOps()
|
|||||||
ops["nt"] = new UnaryOperator("nt", "!");
|
ops["nt"] = new UnaryOperator("nt", "!");
|
||||||
ops["aa"] = new BinaryOperator("aa", "&&");
|
ops["aa"] = new BinaryOperator("aa", "&&");
|
||||||
ops["oo"] = new BinaryOperator("oo", "||");
|
ops["oo"] = new BinaryOperator("oo", "||");
|
||||||
ops["pp"] = new UnaryOperator("pp", "++"); // Prefix?
|
ops["pp"] = new UnaryOperator("pp", "++");
|
||||||
ops["mm"] = new UnaryOperator("mm", "--"); // Prefix?
|
ops["mm"] = new UnaryOperator("mm", "--");
|
||||||
ops["cm"] = new BinaryOperator("cm", ",");
|
ops["cm"] = new BinaryOperator("cm", ",");
|
||||||
ops["pm"] = new BinOpWithNoSpaces("pm", "->*");
|
ops["pm"] = new BinOpWithNoSpaces("pm", "->*");
|
||||||
ops["pt"] = new BinOpWithNoSpaces("pm", "->");
|
ops["pt"] = new BinOpWithNoSpaces("pm", "->");
|
||||||
|
@@ -164,6 +164,12 @@ void NameDemanglerAutoTest::testCorrectlyMangledNames()
|
|||||||
"test_func(void const * (ns1::c<unsigned long>::*)(int *, long &, unsigned long) const)");
|
"test_func(void const * (ns1::c<unsigned long>::*)(int *, long &, unsigned long) const)");
|
||||||
testCorrectlyMangledName("_ZN3ns11fEPKPFPKiS1_RKhE",
|
testCorrectlyMangledName("_ZN3ns11fEPKPFPKiS1_RKhE",
|
||||||
"ns1::f(int const * (* const *)(int const *, unsigned char const &))");
|
"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()
|
void NameDemanglerAutoTest::testIncorrectlyMangledNames()
|
||||||
|
Reference in New Issue
Block a user