diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 607037adaa2..7c7b8197fde 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -47,7 +47,6 @@ HEADERS += \ memoryagent.h \ moduleshandler.h \ moduleswindow.h \ - name_demangler.h \ outputcollector.h \ procinterrupt.h \ registerhandler.h \ @@ -103,7 +102,6 @@ SOURCES += \ memoryagent.cpp \ moduleshandler.cpp \ moduleswindow.cpp \ - name_demangler.cpp \ outputcollector.cpp \ procinterrupt.cpp \ registerhandler.cpp \ @@ -162,5 +160,6 @@ include(script/script.pri) include(pdb/pdb.pri) include(lldb/lldbhost.pri) include(qml/qml.pri) +include(namedemangler/namedemangler.pri) include(shared/shared.pri) diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index a642a3b8fd4..8be327c79cb 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -92,8 +92,6 @@ QtcPlugin { "moduleshandler.h", "moduleswindow.cpp", "moduleswindow.h", - "name_demangler.cpp", - "name_demangler.h", "outputcollector.cpp", "outputcollector.h", "procinterrupt.cpp", @@ -262,7 +260,12 @@ QtcPlugin { "lldb/ipcenginehost.cpp", "lldb/ipcenginehost.h", "lldb/lldbenginehost.cpp", - "lldb/lldbenginehost.h" + "lldb/lldbenginehost.h", + "namedemangler/namedemangler.cpp", + "namedemangler/namedemangler.h", + "namedemangler/parsetreenodes.cpp", + "namedemangler/parsetreenodes.h", + "namedemangler/demanglerexceptions.h" ] Group { diff --git a/src/plugins/debugger/name_demangler.cpp b/src/plugins/debugger/name_demangler.cpp deleted file mode 100644 index 3f82cc938d0..00000000000 --- a/src/plugins/debugger/name_demangler.cpp +++ /dev/null @@ -1,2064 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "name_demangler.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -// Debugging facility. -//#define DO_TRACE -#ifdef DO_TRACE -#define FUNC_START() \ - 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 -#define FUNC_START() -#define FUNC_END(result) -#endif // DO_TRACE - -// The first-sets for all non-terminals. -static QSet firstSetArrayType; -static QSet firstSetBareFunctionType; -static QSet firstSetBuiltinType; -static QSet firstSetCallOffset; -static QSet firstSetClassEnumType; -static QSet firstSetDiscriminator; -static QSet firstSetCtorDtorName; -static QSet firstSetCvQualifiers; -static QSet firstSetEncoding; -static QSet firstSetExpression; -static QSet firstSetExprPrimary; -static QSet firstSetFunctionType; -static QSet firstSetLocalName; -static QSet firstSetMangledName; -static QSet firstSetName; -static QSet firstSetNestedName; -static QSet firstSetNonNegativeNumber; -static QSet firstSetNumber; -static QSet firstSetOperatorName; -static QSet firstSetPointerToMemberType; -static QSet firstSetPositiveNumber; -static QSet firstSetPrefix; -static QSet firstSetPrefix2; -static QSet firstSetSeqId; -static QSet firstSetSourceName; -static QSet firstSetSpecialName; -static QSet firstSetSubstitution; -static QSet firstSetTemplateArg; -static QSet firstSetTemplateArgs; -static QSet firstSetTemplateParam; -static QSet firstSetType; -static QSet firstSetUnqualifiedName; -static QSet firstSetUnscopedName; - -namespace Debugger { -namespace Internal { -class ParseException -{ -public: - ParseException(const QString &error) : error(error) {} - - const QString error; -}; - -class NameDemanglerPrivate -{ -public: - NameDemanglerPrivate(); - ~NameDemanglerPrivate(); - - bool demangle(const QString &mangledName); - const QString &errorString() const { return m_errorString; } - const QString &demangledName() const { return m_demangledName; } - -private: - class Operator - { - public: - enum OpType { UnaryOp, BinaryOp, TernaryOp }; - Operator(const QByteArray &code, const QByteArray &repr) - : code(code), repr(repr) { } - virtual ~Operator() {} - virtual const QByteArray makeExpr(const QList &exprs) const=0; - virtual OpType type() const=0; - - const QByteArray code; - QByteArray repr; - }; - - class UnaryOperator : public Operator - { - public: - UnaryOperator(const QByteArray &code, const QByteArray &repr) - : Operator(code, repr) { } - virtual const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 1); - return repr + exprs.first(); - } - OpType type() const { return UnaryOp; } - }; - - class FunctionCallOperator : public UnaryOperator - { - public: - FunctionCallOperator() : UnaryOperator("cl", "") { } - const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 1); - return exprs.first() + "()"; - } - }; - - class SizeAlignOfOperator : public UnaryOperator - { - public: - SizeAlignOfOperator(const QByteArray &code, const QByteArray &repr) - : UnaryOperator(code, repr) { } - const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 1); - return repr + '(' + exprs.first() + ')'; - } - }; - - class BinaryOperator : public Operator - { - public: - BinaryOperator(const QByteArray &code, const QByteArray &repr) - : Operator(code, repr) { } - virtual const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 2); - return exprs.first() + ' ' + repr + ' ' + exprs.at(1); - } - OpType type() const { return BinaryOp; } - }; - - class ArrayNewOperator : public BinaryOperator - { - public: - ArrayNewOperator() : BinaryOperator("na", "") { } - - const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 2); - return "new " + exprs.first() + '[' + exprs.at(1) + ']'; - } - }; - - class BinOpWithNoSpaces : public BinaryOperator - { - public: - BinOpWithNoSpaces(const QByteArray &code, const QByteArray &repr) - : BinaryOperator(code, repr) { } - virtual const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 2); - return exprs.first() + repr + exprs.at(1); - } - }; - - class ArrayAccessOperator : public BinaryOperator - { - public: - ArrayAccessOperator() : BinaryOperator("ix", "") { } - - const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 2); - return exprs.first() + '[' + exprs.at(1) + ']'; - } - }; - - class QuestionMarkOperator : public Operator - { - public: - QuestionMarkOperator() : Operator("qu", "") { } - - virtual const QByteArray makeExpr(const QList &exprs) const - { - Q_ASSERT(exprs.size() == 3); - return exprs.first() + " ? " + exprs.at(1) + " : " + exprs.at(2); - } - OpType type() const { return TernaryOp; } - }; - - static void setupFirstSets(); - static void setupOps(); - - char peek(int ahead = 0); - char advance(int steps = 1); - const QByteArray readAhead(int charCount); - - void addSubstitution(const QByteArray &symbol); - - /* - * One parse function per Non-terminal. - * The functions return their unmangled representation, except where noted. - */ - const QByteArray parseArrayType(); - - /* - * Returns the list of argument types, the first of which may be - * the return type, depending on context. - */ - const QList parseBareFunctionType(); - - const QByteArray parseBuiltinType(); - void parseCallOffset(); - const QByteArray parseClassEnumType(); - const QByteArray parseCtorDtorName(); - const QByteArray parseCvQualifiers(); - int parseDigit(); - int parseDiscriminator(); - const QByteArray parseEncoding(); - const QByteArray parseExpression(); - const QByteArray parseExprPrimary(); - double parseFloat(); - const QByteArray parseFunctionType(); - const QByteArray parseIdentifier(int len); - const QByteArray parseLocalName(); - const QByteArray parseMangledName(); - const QByteArray parseName(); - const QByteArray parseNestedName(); - int parseNonNegativeNumber(int base = 10); - int parseNumber(); - void parseNvOffset(); - const Operator &parseOperatorName(); - const QByteArray parsePointerToMemberType(); - const QByteArray parsePrefix(); - const QByteArray parsePrefix2(const QByteArray &oldPrefix); - int parseSeqId(); - const QByteArray parseSpecialName(); - const QByteArray parseSourceName(); - const QByteArray parseSubstitution(); - const QByteArray parseTemplateArg(); - const QByteArray parseTemplateArgs(); - const QByteArray parseTemplateParam(); - const QByteArray parseType(); - const QByteArray parseUnqualifiedName(); - const QByteArray parseUnscopedName(); - void parseVOffset(); - - void insertQualifier(QByteArray &type, const QByteArray &qualifier); - - static const char eoi; - static bool staticInitializationsDone; - static QMap ops; - - int m_pos; - QByteArray m_mangledName; - QString m_errorString; - QString m_demangledName; - QList m_substitutions; - QList m_templateParams; - bool m_isConversionOperator; -}; - - -const char NameDemanglerPrivate::eoi('$'); -bool NameDemanglerPrivate::staticInitializationsDone = false; -QMap NameDemanglerPrivate::ops; - -NameDemanglerPrivate::NameDemanglerPrivate() -{ - // Not thread safe. We can easily add a mutex if that ever becomes a requirement. - if (staticInitializationsDone) - return; - - setupFirstSets(); - setupOps(); - staticInitializationsDone = true; -} - -NameDemanglerPrivate::~NameDemanglerPrivate() -{ - qDeleteAll(ops); -} - -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(); - m_demangledName = parseMangledName(); - m_demangledName.replace( - QRegExp(QLatin1String("([^a-zA-Z\\d>)])::")), QLatin1String("\\1")); - if (m_demangledName.startsWith(QLatin1String("::"))) - m_demangledName.remove(0, 2); - if (m_pos != m_mangledName.size()) - throw ParseException(QLatin1String("Unconsumed input")); -#ifdef DO_TRACE - qDebug("%d", m_substitutions.size()); - foreach (const QByteArray &s, m_substitutions) - qDebug("%s", s.constData()); -#endif - return true; - } catch (const ParseException &p) { - m_errorString = QString::fromLocal8Bit("Parse error at index %1 of mangled name '%2': %3.") - .arg(m_pos).arg(mangledName, p.error); - return false; - } -} - -/* - * Grammar: http://www.codesourcery.com/public/cxx-abi/abi.html#mangling - * The grammar as given there is not LL(k), so a number of transformations - * were necessary, which we will document at the respective parsing function. - * ::= _Z - */ -const QByteArray NameDemanglerPrivate::parseMangledName() -{ - FUNC_START(); - QByteArray name; - if (readAhead(2) != "_Z") { - name = m_mangledName; - advance(m_mangledName.size()); - } else { - advance(2); - name = parseEncoding(); - } - FUNC_END(name); - return name; -} - -/* - * ::= - * ::= - * ::= &signature = parseBareFunctionType(); - - /* - * Instantiations of function templates encode their return type, - * normal functions do not. Also, constructors, destructors - * and conversion operators never encode their return type. - */ - int start; - if (!m_isConversionOperator && encoding.endsWith('>')) { // Template instantiation. - start = 1; - encoding.prepend(signature.first() + ' '); - } else { // Normal function. - start = 0; - } - encoding += '('; - for (int i = start; i < signature.size(); ++i) { - if (i > start) - encoding += ", "; - const QByteArray &type = signature.at(i); - if (type != "void") - encoding += type; - } - encoding += ')'; - encoding += qualifiers; - addSubstitution(encoding); - } else { - addSubstitution(encoding); - } - m_templateParams.clear(); - m_isConversionOperator = false; - } else if (firstSetSpecialName.contains(next)) { - encoding = parseSpecialName(); - } else { - throw ParseException(QString::fromLatin1("Invalid encoding")); - } - - FUNC_END(encoding); - return encoding; -} - - -/* - * ::= - * ::= - * ::= - * ::= # See Scope Encoding below - * - * We can't use this rule directly, because - * can expand to . We therefore integrate it directly - * into the production for : - * ::= [] - * ::= - * - * Secondly, shares an expansion ("St") with , - * so we have to look further ahead to see which one matches. - */ -const QByteArray NameDemanglerPrivate::parseName() -{ - FUNC_START(); - Q_ASSERT((firstSetNestedName & firstSetUnscopedName).isEmpty()); - Q_ASSERT((firstSetNestedName & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetNestedName & firstSetLocalName).isEmpty()); - Q_ASSERT((firstSetUnscopedName & firstSetSubstitution).size() == 1); // 'S' - Q_ASSERT((firstSetUnscopedName & firstSetLocalName).isEmpty()); - Q_ASSERT((firstSetSubstitution & firstSetLocalName).isEmpty()); - - QByteArray name; - if ((readAhead(2) == "St" && firstSetUnqualifiedName.contains(peek(2))) - || firstSetUnscopedName.contains(peek())) { - name = parseUnscopedName(); - if (firstSetTemplateArgs.contains(peek())) { - addSubstitution(name); - name += parseTemplateArgs(); - } - } else { - const char next = peek(); - if (firstSetNestedName.contains(next)) - name = parseNestedName(); - else if (firstSetSubstitution.contains(next)) - name = parseSubstitution() + parseTemplateArgs(); - else if (firstSetLocalName.contains(next)) - name = parseLocalName(); - else - throw ParseException(QString::fromLatin1("Invalid name")); - } - - FUNC_END(name); - return name; -} - -/* - * ::= N [] E - * ::= N [] E - * ::= - * ::= - * ::= - * - * The rule leads to an indirect recursion with , so - * we integrate it into : - * ::= N [] - * [] E - * ::= N [] E - * ::= N [] E - * - * The occurrence of in the first expansion makes this rule - * completely unmanageable, because 's first and follow sets are - * not distinct and it also shares elements of its first set with - * and . However, can expand - * to both the non-terminals it is followed by as well as the two competing - * non-terminal sequences in the other rules, so we can just write: - * ::= N [] E - * - * That's not all, though: Both and can start - * with an 'r', so we have to do a two-character-look-ahead for that case. - */ -const QByteArray NameDemanglerPrivate::parseNestedName() -{ - FUNC_START(); - Q_ASSERT((firstSetCvQualifiers & firstSetPrefix).size() == 1); - - QByteArray name; - if (advance() != 'N') - throw ParseException(QString::fromLatin1("Invalid nested-name")); - - QByteArray cvQualifiers; - if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm' - && peek(1) != 'M' && peek(1) != 's' && peek(1) != 'S') { - cvQualifiers = parseCvQualifiers(); - } - name = parsePrefix(); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid nested-name")); - - /* - * These are member function qualifiers which will have to - * be moved to the back of the whole declaration later on, - * so we mark them with the '@' character to ne able to easily - * spot them. - */ - if (!cvQualifiers.isEmpty()) - name += '@' + cvQualifiers; - - FUNC_END(name); - return name; -} - -/* - * ::= - * ::= - * ::= - * ::= # empty - * ::= - * - * We have to eliminate the left-recursion and the template-prefix rule - * and end up with this: - * ::= [] - * ::= [] - * ::= - */ -const QByteArray NameDemanglerPrivate::parsePrefix() -{ - FUNC_START(); - Q_ASSERT((firstSetTemplateParam & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetTemplateArgs & firstSetPrefix2).isEmpty()); - Q_ASSERT((firstSetTemplateParam & firstSetPrefix2).isEmpty()); - Q_ASSERT((firstSetSubstitution & firstSetPrefix2).isEmpty()); - - QByteArray prefix; - char next = peek(); - if (firstSetTemplateParam.contains(next)) { - prefix = parseTemplateParam(); - if (firstSetTemplateArgs.contains(peek())) { - addSubstitution(prefix); - prefix += parseTemplateArgs(); - } - if (firstSetUnqualifiedName.contains(peek())) { - addSubstitution(prefix); - prefix = parsePrefix2(prefix); - } - } else if (firstSetSubstitution.contains(next)) { - prefix = parseSubstitution(); - QByteArray templateArgs; - if (firstSetTemplateArgs.contains(peek())) { - templateArgs = parseTemplateArgs(); - prefix += templateArgs; - } - if (firstSetUnqualifiedName.contains(peek()) && !templateArgs.isEmpty()) - addSubstitution(prefix); - prefix = parsePrefix2(prefix); - } else { - prefix = parsePrefix2(prefix); - } - - FUNC_END(prefix); - return prefix; -} - -/* - * ::= [] - * ::= # empty - */ -const QByteArray NameDemanglerPrivate::parsePrefix2(const QByteArray &oldPrefix) -{ - FUNC_START(); - Q_ASSERT((firstSetTemplateArgs & firstSetPrefix2).isEmpty()); - - QByteArray prefix = oldPrefix; - bool firstRun = true; - while (firstSetUnqualifiedName.contains(peek())) { - if (!firstRun) - addSubstitution(prefix); - prefix += parseUnqualifiedName(); - if (firstSetTemplateArgs.contains(peek())) { - addSubstitution(prefix); - prefix += parseTemplateArgs(); - } - firstRun = false; - } - - FUNC_END(prefix); - return prefix; -} - -/* - * ::= I + E - */ -const QByteArray NameDemanglerPrivate::parseTemplateArgs() -{ - FUNC_START(); - Q_ASSERT(!firstSetTemplateArg.contains('E')); - - QByteArray args = "<"; - if (advance() != 'I') - throw ParseException(QString::fromLatin1("Invalid template args")); - - do { - if (args.length() > 1) - args += ", "; - args += parseTemplateArg(); - } while (firstSetTemplateArg.contains(peek())); - - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid template args")); - - args += '>'; - FUNC_END(args); - return args; -} - -/* - * ::= T_ # first template parameter - * ::= T _ - */ -const QByteArray NameDemanglerPrivate::parseTemplateParam() -{ - FUNC_START(); - - QByteArray param; - if (advance() != 'T') - throw ParseException(QString::fromLatin1("Invalid template-param")); - - int index; - if (peek() == '_') - index = 0; - else - index = parseNonNegativeNumber() + 1; - if (advance() != '_') - 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); - } - - FUNC_END(param); - return param; -} - -/* ::= [r] [V] [K] # restrict (C99), volatile, const */ -const QByteArray NameDemanglerPrivate::parseCvQualifiers() -{ - FUNC_START(); - - QByteArray qualifiers; - bool volatileFound = false; - bool constFound = false; - while (true) { - if (peek() == 'V') { - if (volatileFound || constFound) - throw ParseException(QLatin1String("Invalid qualifiers: unexpected 'volatile'")); - volatileFound = true; - qualifiers += " volatile"; - advance(); - } else if (peek() == 'K') { - if (constFound) - throw ParseException(QLatin1String("Invalid qualifiers: 'const' appears twice")); - constFound = true; - qualifiers += " const"; - advance(); - } else { - break; - } - } - - FUNC_END(qualifiers); - return qualifiers; -} - -int NameDemanglerPrivate::parseNumber() -{ - FUNC_START(); - - bool negative = false; - if (peek() == 'n') { - negative = true; - advance(); - } - int val = parseNonNegativeNumber(); - int number = negative ? -val : val; - - FUNC_END(QString::number(number)); - return number; -} - - -int NameDemanglerPrivate::parseNonNegativeNumber(int base) -{ - FUNC_START(); - - int startPos = m_pos; - while (std::isdigit(peek())) - advance(); - if (m_pos == startPos) - throw ParseException(QString::fromLatin1("Invalid non-negative number")); - const int number = m_mangledName.mid(startPos, m_pos - startPos).toInt(0, base); - - FUNC_END(QString::number(number)); - return number; -} - -/* - * Floating-point literals are encoded using a fixed-length lowercase - * hexadecimal string corresponding to the internal representation - * (IEEE on Itanium), high-order bytes first, without leading zeroes. - * For example: "Lf bf800000 E" is -1.0f on Itanium. - */ -double NameDemanglerPrivate::parseFloat() -{ - FUNC_START(); - - // TODO: Implementation! - Q_ASSERT(0); - - FUNC_END(QString()); - return 0.0; -} - -/* - * ::= # type or template - * ::= X E # expression - * ::= # simple expressions - * ::= J * E # argument pack - * ::= sp # pack expansion of (C++0x) - */ -const QByteArray NameDemanglerPrivate::parseTemplateArg() -{ - FUNC_START(); - Q_ASSERT(!firstSetType.contains('X') && !firstSetType.contains('J') - /* && !firstSetType.contains('s') */); - Q_ASSERT((firstSetType & firstSetExprPrimary).isEmpty()); - Q_ASSERT(!firstSetExprPrimary.contains('X') - && !firstSetExprPrimary.contains('J') - && !firstSetExprPrimary.contains('s')); - Q_ASSERT(!firstSetTemplateArg.contains('E')); - - QByteArray arg; - char next = peek(); - if (readAhead(2) == "sp") { - advance(2); - arg = parseExpression(); - } else if (firstSetType.contains(next)) { - arg = parseType(); - } else if (firstSetExprPrimary.contains(next)) { - arg = parseExprPrimary(); - } else if (next == 'X') { - advance(); - arg = parseExpression(); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid template-arg")); - } else if (next == 'J') { - advance(); - while (firstSetTemplateArg.contains(peek())) { - if (!arg.isEmpty()) - arg += ", "; // TODO: is this correct? - arg += parseTemplateArg(); - } - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid template-arg")); - } else { - throw ParseException(QString::fromLatin1("Invalid template-arg")); - } - - m_templateParams.append(arg); - FUNC_END(arg); - return arg; -} - -/* - * ::= - * ::= - * ::= - * ::= cl * E # call - * ::= cv expression # conversion with one argument - * ::= cv _ * E # conversion with a different number of arguments - * ::= st # sizeof (a type) - * ::= at # alignof (a type) - * ::= - * ::= - * ::= sr # dependent name - * ::= sr # dependent template-id - * ::= sZ # size of a parameter pack - * ::= - * - * Note that the grammar is missing the definition of . This - * has not been a problem in the test cases so far. - */ -const QByteArray NameDemanglerPrivate::parseExpression() -{ - FUNC_START(); - Q_ASSERT((firstSetOperatorName & firstSetTemplateParam).isEmpty()); -// Q_ASSERT((firstSetOperatorName & firstSetFunctionParam).isEmpty()); - Q_ASSERT((firstSetOperatorName & firstSetExprPrimary).isEmpty()); -// Q_ASSERT((firstSetTemplateParam & firstSetFunctionParam).isEmpty()); - Q_ASSERT((firstSetTemplateParam & firstSetExprPrimary).isEmpty()); - Q_ASSERT(!firstSetTemplateParam.contains('c') - && !firstSetTemplateParam.contains('s') - && !firstSetTemplateParam.contains('a')); -// Q_ASSERT((firstSetFunctionParam & firstSetExprPrimary).isEmpty()); -/* - Q_ASSERT(!firstSetFunctionParam.contains('c') - && !firstSetFunctionParam.contains('s') - && !firstSetFunctionParam.contains('a')); -*/ - Q_ASSERT(!firstSetExprPrimary.contains('c') - && !firstSetExprPrimary.contains('s') - && !firstSetExprPrimary.contains('a')); - Q_ASSERT(!firstSetExpression.contains('E')); - Q_ASSERT(!firstSetExpression.contains('_')); - - QByteArray expr; - - /* - * Some of the terminals in the productions of - * also appear in the productions of . We assume the direct - * productions to have higher precedence and check them first to prevent - * them being parsed by parseOperatorName(). - */ - QByteArray str = readAhead(2); - if (str == "cl") { - advance(2); - while (firstSetExpression.contains(peek())) - expr += parseExpression(); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid expression")); - } else if (str == "cv") { - advance(2); - expr = parseType() + '('; - if (peek() == '_') { - advance(); - for (int numArgs = 0; firstSetExpression.contains(peek()); ++numArgs) { - if (numArgs > 0) - expr += ", "; - expr += parseExpression(); - } - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid expression")); - } else { - expr += parseExpression(); - } - expr += ')'; - } else if (str == "st") { - advance(2); - expr = "sizeof(" + parseType() + ')'; - } else if (str == "at") { - advance(2); - expr = "alignof(" + parseType() + ')'; - } else if (str == "sr") { // TODO: Which syntax to use here? - advance(2); - expr = parseType() + parseUnqualifiedName(); - if (firstSetTemplateArgs.contains(peek())) - parseTemplateArgs(); - } else if (str == "sZ") { - expr = parseTemplateParam(); // TODO: Syntax? - } else { - char next = peek(); - if (firstSetOperatorName.contains(next)) { - const Operator &op = parseOperatorName(); - QList exprs; - exprs.append(parseExpression()); - if (op.type() != Operator::UnaryOp) - exprs.append(parseExpression()); - if (op.type() == Operator::TernaryOp) - exprs.append(parseExpression()); - expr = op.makeExpr(exprs); - } else if (firstSetTemplateParam.contains(next)) { - expr = parseTemplateParam(); -#if 0 - } else if (firstSetFunctionParam.contains(next)) { - expr = parseFunctionParam(); -#endif - } else if (firstSetExprPrimary.contains(next)) { - expr = parseExprPrimary(); - } else { - throw ParseException(QString::fromLatin1("Invalid expression")); - } - } - - FUNC_END(expr); - return expr; -} - -/* - * ::= L E # integer literal - * ::= L E # floating literal - * ::= L E # external name - */ -const QByteArray NameDemanglerPrivate::parseExprPrimary() -{ - FUNC_START(); - Q_ASSERT((firstSetType & firstSetMangledName).isEmpty()); - - QByteArray expr; - if (advance() != 'L') - throw ParseException(QString::fromLatin1("Invalid primary expression")); - const char next = peek(); - if (firstSetType.contains(next)) { - const QByteArray type = parseType(); - if (true /* type just parsed indicates integer */) - expr += QByteArray::number(parseNumber()); - else if (true /* type just parsed indicates float */) - expr += QByteArray::number(parseFloat()); - else - throw ParseException(QString::fromLatin1("Invalid expr-primary")); - } else if (firstSetMangledName.contains(next)) { - expr = parseMangledName(); - } else { - throw ParseException(QString::fromLatin1("Invalid expr-primary")); - } - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid expr-primary")); - - FUNC_END(expr); - return expr; -} - -/* - * ::= - * ::= - * ::= - * ::= - * ::= - * ::= - * ::= - * ::= # See Compression below - * ::= - * ::= P # pointer-to - * ::= R # reference-to - * ::= O # rvalue reference-to (C++0x) - * ::= C # complex pair (C 2000) - * ::= G # imaginary (C 2000) - * ::= U # vendor extended type qualifier - * ::= Dp # pack expansion of (C++0x) - * ::= Dt E # decltype of an id-expression or class member access (C++0x) - * ::= DT E # decltype of an expression (C++0x) - * - * Because can expand to , we have to - * do a slight transformation: We get rid of and - * integrate its rhs into 's rhs. This leads to the following - * identical prefixes: - * ::= - * ::= - * ::= - * ::= - * - * Also, the first set of has some overlap with - * direct productions of , so these have to be worked around as well. - */ -const QByteArray NameDemanglerPrivate::parseType() -{ - FUNC_START(); - Q_ASSERT((firstSetBuiltinType & firstSetFunctionType).isEmpty()); - Q_ASSERT((firstSetBuiltinType & firstSetClassEnumType).size() == 1); - Q_ASSERT((firstSetBuiltinType & firstSetArrayType).isEmpty()); - Q_ASSERT((firstSetBuiltinType & firstSetPointerToMemberType).isEmpty()); - Q_ASSERT((firstSetBuiltinType & firstSetTemplateParam).isEmpty()); - Q_ASSERT((firstSetBuiltinType & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetBuiltinType & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetBuiltinType.contains('P') - && !firstSetBuiltinType.contains('R') - && !firstSetBuiltinType.contains('O') - && !firstSetBuiltinType.contains('C') - && !firstSetBuiltinType.contains('G') - && !firstSetBuiltinType.contains('U')); - Q_ASSERT((firstSetFunctionType & firstSetClassEnumType).isEmpty()); - Q_ASSERT((firstSetFunctionType & firstSetArrayType).isEmpty()); - Q_ASSERT((firstSetFunctionType & firstSetPointerToMemberType).isEmpty()); - Q_ASSERT((firstSetFunctionType & firstSetTemplateParam).isEmpty()); - Q_ASSERT((firstSetFunctionType & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetFunctionType & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetFunctionType.contains('P') - && !firstSetFunctionType.contains('R') - && !firstSetFunctionType.contains('O') - && !firstSetFunctionType.contains('C') - && !firstSetFunctionType.contains('G') - && !firstSetFunctionType.contains('U') - && !firstSetFunctionType.contains('D')); - Q_ASSERT((firstSetClassEnumType & firstSetArrayType).isEmpty()); - Q_ASSERT((firstSetClassEnumType & firstSetPointerToMemberType).isEmpty()); - Q_ASSERT((firstSetClassEnumType & firstSetTemplateParam).isEmpty()); - Q_ASSERT((firstSetClassEnumType & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetClassEnumType & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetClassEnumType.contains('P') - && !firstSetClassEnumType.contains('R') - && !firstSetClassEnumType.contains('O') - && !firstSetClassEnumType.contains('C') - && !firstSetClassEnumType.contains('G') - && !firstSetClassEnumType.contains('U') - /* && !firstSetClassEnumType.contains('D') */); - Q_ASSERT((firstSetArrayType & firstSetPointerToMemberType).isEmpty()); - Q_ASSERT((firstSetArrayType & firstSetTemplateParam).isEmpty()); - Q_ASSERT((firstSetArrayType & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetArrayType & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetArrayType.contains('P') - && !firstSetArrayType.contains('R') - && !firstSetArrayType.contains('O') - && !firstSetArrayType.contains('C') - && !firstSetArrayType.contains('G') - && !firstSetArrayType.contains('U') - && !firstSetArrayType.contains('D')); - Q_ASSERT((firstSetPointerToMemberType & firstSetTemplateParam).isEmpty()); - Q_ASSERT((firstSetPointerToMemberType & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetPointerToMemberType & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetPointerToMemberType.contains('P') - && !firstSetPointerToMemberType.contains('R') - && !firstSetPointerToMemberType.contains('O') - && !firstSetPointerToMemberType.contains('C') - && !firstSetPointerToMemberType.contains('G') - && !firstSetPointerToMemberType.contains('U') - && !firstSetPointerToMemberType.contains('D')); - Q_ASSERT((firstSetTemplateParam & firstSetSubstitution).isEmpty()); - Q_ASSERT((firstSetTemplateParam & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetTemplateParam.contains('P') - && !firstSetTemplateParam.contains('R') - && !firstSetTemplateParam.contains('O') - && !firstSetTemplateParam.contains('C') - && !firstSetTemplateParam.contains('G') - && !firstSetTemplateParam.contains('U') - && !firstSetTemplateParam.contains('D')); - Q_ASSERT((firstSetSubstitution & firstSetCvQualifiers).isEmpty()); - Q_ASSERT(!firstSetSubstitution.contains('P') - && !firstSetSubstitution.contains('R') - && !firstSetSubstitution.contains('O') - && !firstSetSubstitution.contains('C') - && !firstSetSubstitution.contains('G') - && !firstSetSubstitution.contains('U') - && !firstSetSubstitution.contains('D')); - Q_ASSERT(!firstSetCvQualifiers.contains('P') - && !firstSetCvQualifiers.contains('R') - && !firstSetCvQualifiers.contains('O') - && !firstSetCvQualifiers.contains('C') - && !firstSetCvQualifiers.contains('G') - && !firstSetCvQualifiers.contains('U') - && !firstSetCvQualifiers.contains('D')); - - QByteArray type; - QByteArray str = readAhead(2); - if (str == "Dp") { - advance(2); - type = parseType(); // TODO: Probably needs augmentation - } else if (str == "Dt") { - advance(2); - type = parseExpression(); // TODO: See above - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid type")); - } else if (str == "DT") { - advance(2); - type = parseExpression(); // TODO: See above - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid type")); - } else { - char next = peek(); - if (str == "Dd" || str == "De" || str == "Df" || str == "Dh" || str == "Di" || str == "Ds" - || (next != 'D' && firstSetBuiltinType.contains(next))) { - type = parseBuiltinType(); - } else if (firstSetFunctionType.contains(next)) { - type = parseFunctionType(); - addSubstitution(type); - } else if (firstSetClassEnumType.contains(next)) { - type = parseClassEnumType(); - addSubstitution(type); - } else if (firstSetArrayType.contains(next)) { - type = parseArrayType(); - } else if (firstSetPointerToMemberType.contains(next)) { - 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())) { - type += parseTemplateArgs(); - addSubstitution(type); - } - } else if (firstSetCvQualifiers.contains(next)) { - const QByteArray cvQualifiers = parseCvQualifiers(); - type = parseType(); - if (!cvQualifiers.isEmpty()) { - insertQualifier(type, cvQualifiers); - addSubstitution(type); - } - } else if (next == 'P') { - advance(); - type = parseType(); - insertQualifier(type, "*"); - addSubstitution(type); - } else if (next == 'R') { - advance(); - type = parseType(); - insertQualifier(type, "&"); - addSubstitution(type); - } else if (next == 'O') { - advance(); - type = parseType() + "&&"; // TODO: Correct notation? - addSubstitution(type); - } else if (next == 'C') { - advance(); - type = parseType(); // TODO: What to do append here? - addSubstitution(type); - } else if (next == 'G') { - advance(); - type = parseType(); // TODO: see above - addSubstitution(type); - } else if (next == 'U') { - advance(); - type = parseSourceName(); - type += parseType(); // TODO: handle this correctly - } else { - throw ParseException(QString::fromLatin1("Invalid type")); - } - } - - FUNC_END(type); - return type; -} - -/* ::= */ -const QByteArray NameDemanglerPrivate::parseSourceName() -{ - FUNC_START(); - - const int idLen = parseNonNegativeNumber(); - const QByteArray sourceName = parseIdentifier(idLen); - - FUNC_END(sourceName); - return sourceName; -} - -/* - * ::= v # void - * ::= w # wchar_t - * ::= b # bool - * ::= c # char - * ::= a # signed char - * ::= h # unsigned char - * ::= s # short - * ::= t # unsigned short - * ::= i # int - * ::= j # unsigned int - * ::= l # long - * ::= m # unsigned long - * ::= x # long long, __int64 - * ::= y # unsigned long long, __int64 - * ::= n # __int128 - * ::= o # unsigned __int128 - * ::= f # float - * ::= d # double - * ::= e # long double, __float80 - * ::= g # __float128 - * ::= z # ellipsis - * ::= Dd # IEEE 754r decimal floating point (64 bits) - * ::= De # IEEE 754r decimal floating point (128 bits) - * ::= Df # IEEE 754r decimal floating point (32 bits) - * ::= Dh # IEEE 754r half-precision floating point (16 bits) - * ::= Di # char32_t - * ::= Ds # char16_t - * ::= u # vendor extended type - */ -const QByteArray NameDemanglerPrivate::parseBuiltinType() -{ - FUNC_START(); - - QByteArray type; - switch (advance()) { - case 'v': type = "void"; break; - case 'w': type = "wchar_t"; break; - case 'b': type = "bool"; break; - case 'c': type = "char"; break; - case 'a': type = "signed char"; break; - case 'h': type = "unsigned char"; break; - case 's': type = "short"; break; - case 't': type = "unsigned short"; break; - case 'i': type = "int"; break; - case 'j': type = "unsigned int"; break; - case 'l': type = "long"; break; - case 'm': type = "unsigned long"; break; - case 'x': type = "long long"; break; - case 'y': type = "unsigned long long"; break; - case 'n': type = "__int128"; break; - case 'o': type = "unsigned __int128"; break; - case 'f': type = "float"; break; - case 'd': type = "double"; break; - case 'e': type = "long double"; break; - case 'g': type = "__float128"; break; - case 'z': type = "..."; break; - case 'u': type = parseSourceName(); break; - case 'D': - switch (advance()) { - case 'd': case 'e': case 'f': case 'h': type = "IEEE_special_float"; break; - case 'i': type = "char32_t"; break; - case 's': type = "char16_t"; break; - default: throw ParseException(QString::fromLatin1("Invalid built-in type")); - } - break; - default: - throw ParseException(QString::fromLatin1("Invalid builtin-type")); - } - - FUNC_END(type); - return type; -} - -/* ::= F [Y] E */ -const QByteArray NameDemanglerPrivate::parseFunctionType() -{ - FUNC_START(); - - // TODO: Check how we get here. Do we always have a return type or not? - if (advance() != 'F') - throw ParseException(QString::fromLatin1("Invalid function type")); - - bool externC = false; - if (peek() == 'Y') { - advance(); - externC = true; - } - - QByteArray funcType; - const QList &signature = parseBareFunctionType(); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid function type")); - QByteArray returnType = signature.first(); - QByteArray argList = "("; - for (int i = 1; i < signature.size(); ++i) { - if (i > 1) - argList.append(", "); - const QByteArray &type = signature.at(i); - if (type != "void") - argList.append(type); - } - argList.append(')'); - bool retTypeIsFuncPtr = false; - const int firstClosingParenIndex = returnType.indexOf(')'); - if (firstClosingParenIndex != -1) { - const int firstOpeningParenIndex = - returnType.lastIndexOf('(', firstClosingParenIndex); - const char next = returnType[firstOpeningParenIndex + 1]; - if (next == '*' || next =='&') { - retTypeIsFuncPtr = true; - funcType = returnType.left(firstOpeningParenIndex + 2) - + argList + returnType.mid(firstOpeningParenIndex + 2); - } - } - if (!retTypeIsFuncPtr) - funcType = returnType + ' ' + argList; - - if (externC) - funcType.prepend("extern \"C\" "); - FUNC_END(funcType); - return funcType; -} - -/* ::= + */ -const QList NameDemanglerPrivate::parseBareFunctionType() -{ - FUNC_START(); - - QList signature; - do - signature.append(parseType()); - while (firstSetType.contains(peek())); - - FUNC_END(QString::number(signature.count())); - return signature; -} - -/* ::= */ -const QByteArray NameDemanglerPrivate::parseClassEnumType() -{ - FUNC_START(); - const QByteArray &name = parseName(); - FUNC_END(name); - return name; -} - -/* - * ::= - * ::= - * ::= - */ -const QByteArray NameDemanglerPrivate::parseUnqualifiedName() -{ - FUNC_START(); - Q_ASSERT((firstSetOperatorName & firstSetCtorDtorName).isEmpty()); - Q_ASSERT((firstSetOperatorName & firstSetSourceName).isEmpty()); - Q_ASSERT((firstSetCtorDtorName & firstSetSourceName).isEmpty()); - - QByteArray name; - char next = peek(); - if (firstSetOperatorName.contains(next)) - name = "::operator" + parseOperatorName().repr; - else if (firstSetCtorDtorName.contains(next)) - name = "::" + parseCtorDtorName(); - else if (firstSetSourceName.contains(next)) - name = "::" + parseSourceName(); - else - throw ParseException(QString::fromLatin1("Invalid unqualified-name")); - - FUNC_END(name); - return name; -} - -/* - * ::= nw # new - * ::= na # new[] - * ::= dl # delete - * ::= da # delete[] - * ::= ps # + (unary) - * ::= ng # - (unary) - * ::= ad # & (unary) - * ::= de # * (unary) - * ::= co # ~ - * ::= pl # + - * ::= mi # - - * ::= ml # * - * ::= dv # / - * ::= rm # % - * ::= an # & - * ::= or # | - * ::= eo # ^ - * ::= aS # = - * ::= pL # += - * ::= mI # -= - * ::= mL # *= - * ::= dV # /= - * ::= rM # %= - * ::= aN # &= - * ::= oR # |= - * ::= eO # ^= - * ::= ls # << - * ::= rs # >> - * ::= lS # <<= - * ::= rS # >>= - * ::= eq # == - * ::= ne # != - * ::= lt # < - * ::= gt # > - * ::= le # <= - * ::= ge # >= - * ::= nt # ! - * ::= aa # && - * ::= oo # || - * ::= pp # ++ - * ::= mm # -- - * ::= cm # , - * ::= pm # ->* - * ::= pt # -> - * ::= cl # () - * ::= ix # [] - * ::= qu # ? - * ::= st # sizeof (a type) - * ::= sz # sizeof (an expression) - * ::= at # alignof (a type) - * ::= az # alignof (an expression) - * ::= cv # (cast) - * ::= v # vendor extended operator - */ -const NameDemanglerPrivate::Operator &NameDemanglerPrivate::parseOperatorName() -{ - FUNC_START(); - - const Operator *op; - if (peek() == 'v') { - // TODO: Implement vendor-extended operators. - static const UnaryOperator vendorOp("v", - "[unimplemented]"); - advance(); - int numExprs = parseDigit(); - Q_UNUSED(numExprs); - parseSourceName(); - op = &vendorOp; - } else { - const QByteArray id = readAhead(2); - advance(2); - if (id == "cv") { - static UnaryOperator castOp("cv", ""); - m_isConversionOperator = true; - QByteArray type = parseType(); - castOp.repr = ' ' + type; - op = &castOp; - } else { - op = ops.value(id); - if (op == 0) { - static const UnaryOperator pseudoOp("invalid", "invalid"); - op = &pseudoOp; - throw ParseException(QString::fromLatin1("Invalid operator-name '%s'") - .arg(QString::fromAscii(id))); - } - } - } - - FUNC_END(op->repr); - return *op; -} - -/* - * ::= A _ - * ::= A [] _ - */ -const QByteArray NameDemanglerPrivate::parseArrayType() -{ - FUNC_START(); - Q_ASSERT((firstSetNonNegativeNumber & firstSetExpression).isEmpty()); - Q_ASSERT(!firstSetNonNegativeNumber.contains('_')); - Q_ASSERT(!firstSetExpression.contains('_')); - - QByteArray type; - if (advance() != 'A') - throw ParseException(QString::fromLatin1("Invalid array-type")); - - const char next = peek(); - QByteArray dimension; - if (firstSetNonNegativeNumber.contains(next)) { - dimension = QByteArray::number(parseNonNegativeNumber()); - } else if (firstSetExpression.contains(next)){ - dimension = parseExpression(); - } - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid array-type")); - type = parseType() + '[' + dimension + ']'; - - FUNC_END(type); - return type; -} - -/* ::= M */ -const QByteArray NameDemanglerPrivate::parsePointerToMemberType() -{ - FUNC_START(); - - QByteArray type; - if (advance() != 'M') - throw ParseException(QString::fromLatin1("Invalid pointer-to-member-type")); - - const QByteArray classType = parseType(); - QByteArray memberType = parseType(); - if (memberType.contains(')')) { // Function? - const int parenIndex = memberType.indexOf('('); - QByteArray returnType = memberType.left(parenIndex); - memberType.remove(0, parenIndex); - type = returnType + '(' + classType + "::*)" + memberType; - } else { - type = memberType + ' ' + classType + "::*"; - } - - FUNC_END(type); - return type; -} - -/* - * ::= S _ - * ::= S_ - * ::= St # ::std:: - * ::= Sa # ::std::allocator - * ::= Sb # ::std::basic_string - * ::= Ss # ::std::basic_string < char, - * ::std::char_traits, - * ::std::allocator > - * ::= Si # ::std::basic_istream > - * ::= So # ::std::basic_ostream > - * ::= Sd # ::std::basic_iostream > - */ -const QByteArray NameDemanglerPrivate::parseSubstitution() -{ - FUNC_START(); - Q_ASSERT(!firstSetSeqId.contains('_') && !firstSetSeqId.contains('t') - && !firstSetSeqId.contains('a') && !firstSetSeqId.contains('b') - && !firstSetSeqId.contains('s') && !firstSetSeqId.contains('i') - && !firstSetSeqId.contains('o') && !firstSetSeqId.contains('d')); - - QByteArray substitution; - if (advance() != 'S') - throw ParseException(QString::fromLatin1("Invalid substitution")); - - if (firstSetSeqId.contains(peek())) { - int substIndex = parseSeqId() + 1; - if (substIndex >= m_substitutions.size()) { - throw ParseException(QString::fromLatin1("Invalid substitution: element %1 was requested, " - "but there are only %2"). - arg(substIndex + 1).arg(m_substitutions.size())); - } - substitution = m_substitutions.at(substIndex); - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid substitution")); - } else { - switch (advance()) { - case '_': - if (m_substitutions.isEmpty()) - throw ParseException(QString::fromLatin1("Invalid substitution: There are no elements")); - substitution = m_substitutions.first(); - break; - case 't': - substitution = "::std::"; - break; - case 'a': - substitution = "::std::allocator"; - break; - case 'b': - substitution = "::std::basic_string"; - break; - case 's': - substitution = "::std::basic_string, " - "::std::allocator >"; - break; - case 'i': - substitution = "::std::basic_istream >"; - break; - case 'o': - substitution = "::std::basic_ostream >"; - break; - case 'd': - substitution = "::std::basic_iostream >"; - break; - default: - throw ParseException(QString::fromLatin1("Invalid substitution")); - } - } - - FUNC_END(substitution); - return substitution; -} - - -/* - * The is a sequence number in base 36, using digits - * and upper case letters. - */ -int NameDemanglerPrivate::parseSeqId() -{ - FUNC_START(); - int seqId = parseNonNegativeNumber(36); - FUNC_END(QString::number(seqId)); - return seqId; -} - -/* - * ::= TV # virtual table - * ::= TT # VTT structure (construction vtable index) - * ::= TI # typeinfo structure - * ::= TS # typeinfo name (null-terminated byte string) - * ::= GV # Guard variable for one-time initialization - * ::= T - * ::= Tc - * # base is the nominal target function of thunk - * # first call-offset is 'this' adjustment - * # second call-offset is result adjustment - */ -const QByteArray NameDemanglerPrivate::parseSpecialName() -{ - FUNC_START(); - Q_ASSERT(!firstSetCallOffset.contains('V') - && !firstSetCallOffset.contains('T') - && !firstSetCallOffset.contains('I') - && !firstSetCallOffset.contains('S') - && !firstSetCallOffset.contains('c')); - - QByteArray name; - QByteArray str = readAhead(2); - if (str == "TV") { - advance(2); - name = "[virtual table of " + parseType() + ']'; - } else if (str == "TT") { - advance(2); - name = "[VTT struct of " + parseType() + ']'; - } else if (str == "TI") { - advance(2); - name = "typeid(" + parseType() + ')'; - } else if (str == "TS") { - advance(2); - name = "typeid(" + parseType() + ").name()"; - } else if (str == "GV") { - advance(2); - name = "[guard variable of " + parseName() + ']'; - } else if (str == "Tc") { - advance(2); - parseCallOffset(); - parseCallOffset(); - parseEncoding(); - } else if (advance() == 'T') { - parseCallOffset(); - parseEncoding(); - } else { - throw ParseException(QString::fromLatin1("Invalid special-name")); - } - - FUNC_END(name); - return name; -} - -/* - * ::= - * ::= St # ::std:: - */ -const QByteArray NameDemanglerPrivate::parseUnscopedName() -{ - FUNC_START(); - Q_ASSERT(!firstSetUnqualifiedName.contains('S')); - - QByteArray name; - if (readAhead(2) == "St") { - advance(2); - name = "::std" + parseUnqualifiedName(); - } else if (firstSetUnqualifiedName.contains(peek())) { - name = parseUnqualifiedName(); - } else { - throw ParseException(QString::fromLatin1("Invalid unqualified-name")); - } - - FUNC_END(name); - return name; -} - - -/* - * := Z E [] - * := Z E s [] - * - * Note that can start with 's', so we need to to read-ahead. - */ -const QByteArray NameDemanglerPrivate::parseLocalName() -{ - FUNC_START(); - - QByteArray name; - if (advance() != 'Z') - throw ParseException(QString::fromLatin1("Invalid local-name")); - - name = parseEncoding(); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid local-name")); - - QByteArray str = readAhead(2); - char next = peek(); - if (str == "sp" || str == "sr" || str == "st" || str == "sz" || str == "sZ" - || (next != 's' && firstSetName.contains(next))) - name += parseName(); - else if (next == 's') { - advance(); - name += "::\"string literal\""; - } else { - throw ParseException(QString::fromLatin1("Invalid local-name")); - } - if (firstSetDiscriminator.contains(peek())) - parseDiscriminator(); - - FUNC_END(name); - return name; -} - -/* := _ */ -int NameDemanglerPrivate::parseDiscriminator() -{ - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid discriminator")); - - const int index = parseNonNegativeNumber(); - - FUNC_END(QString::number(index)); - return index; -} - -/* - * ::= C1 # complete object constructor - * ::= C2 # base object constructor - * ::= C3 # complete object allocating constructor - * ::= D0 # deleting destructor - * ::= D1 # complete object destructor - * ::= D2 # base object destructor - */ -const QByteArray NameDemanglerPrivate::parseCtorDtorName() -{ - FUNC_START(); - - QByteArray name; - bool destructor = false; - switch (advance()) { - case 'C': - switch (advance()) { - case '1': case '2': case '3': break; - default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); - } - break; - case 'D': - switch (advance()) { - case '0': case '1': case '2': destructor = true; break; - default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); - } - break; - default: - throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); - } - - name = m_substitutions.last(); - int templateArgsStart = name.indexOf('<'); - if (templateArgsStart != -1) - name.remove(templateArgsStart, - name.indexOf('>') - templateArgsStart + 1); - int lastComponentStart = name.lastIndexOf("::"); - if (lastComponentStart != -1) - name.remove(0, lastComponentStart + 2); - if (destructor) - name.prepend('~'); - - FUNC_END(name); - return name; -} - -/* This will probably need the number of characters to read. */ -const QByteArray NameDemanglerPrivate::parseIdentifier(int len) -{ - FUNC_START(); - - const QByteArray id = m_mangledName.mid(m_pos, len); - advance(len); - - FUNC_END(id); - return id; -} - -/* - * ::= h _ - * ::= v _ - */ -void NameDemanglerPrivate::parseCallOffset() -{ - FUNC_START(); - - switch (advance()) { - case 'h': parseNvOffset(); break; - case 'v': parseVOffset(); break; - default: throw ParseException(QString::fromLatin1("Invalid call-offset")); - } - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid call-offset")); - FUNC_END(QString()); -} - -/* ::= # non-virtual base override */ -void NameDemanglerPrivate::parseNvOffset() -{ - FUNC_START(); - parseNumber(); - FUNC_END(QString()); -} - -/* - * ::= _ - * # virtual base override, with vcall offset - */ -void NameDemanglerPrivate::parseVOffset() -{ - FUNC_START(); - - parseNumber(); - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid v-offset")); - parseNumber(); - - FUNC_END(QString()); -} - -int NameDemanglerPrivate::parseDigit() -{ - FUNC_START(); - - int digit = advance(); - if (!std::isdigit(digit)) - throw ParseException(QString::fromLatin1("Invalid digit")); - digit -= 0x30; - - FUNC_END(QString::number(digit)); - return digit; -} - -char NameDemanglerPrivate::peek(int ahead) -{ - Q_ASSERT(m_pos >= 0); - - if (m_pos + ahead < m_mangledName.size()) - return m_mangledName[m_pos + ahead]; - return eoi; -} - -char NameDemanglerPrivate::advance(int steps) -{ - Q_ASSERT(steps > 0); - if (m_pos + steps > m_mangledName.size()) - throw ParseException(QLatin1String("Unexpected end of input")); - - const char c = m_mangledName[m_pos]; - m_pos += steps; - return c; -} - -const QByteArray NameDemanglerPrivate::readAhead(int charCount) -{ - QByteArray str; - if (m_pos + charCount < m_mangledName.size()) - str = m_mangledName.mid(m_pos, charCount); - else - str.fill(eoi, charCount); - return str; -} - -void NameDemanglerPrivate::setupFirstSets() -{ - firstSetMangledName << '_'; - firstSetNestedName << 'N'; - firstSetFunctionType << 'F'; - firstSetArrayType << 'A'; - firstSetPointerToMemberType << 'M'; - firstSetTemplateParam << 'T'; - firstSetSubstitution << 'S'; - firstSetLocalName << 'Z'; - firstSetTemplateArgs << 'I'; - firstSetExprPrimary << 'L'; - firstSetDiscriminator << '_'; - firstSetSpecialName << 'T' << 'G'; - firstSetCtorDtorName << 'C' << 'D'; - firstSetCallOffset << 'h' << 'v'; - firstSetCvQualifiers << 'K' << 'V' << 'r'; - firstSetOperatorName << 'n' << 'd' << 'p' << 'a' << 'c' << 'm' << 'r' - << 'o' << 'e' << 'l' << 'g' << 'i' << 'q' << 's' - << 'v'; - firstSetBuiltinType << 'v' << 'w' << 'b' << 'c' << 'a' << 'h' << 's' << 't' - << 'i' << 'j' << 'l' << 'm' << 'x' << 'y' << 'n' << 'o' - << 'f' << 'g' << 'e' << 'd' << 'z' << 'D' << 'u'; - firstSetPositiveNumber - << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9'; - (firstSetNonNegativeNumber += firstSetPositiveNumber) << '0'; - (firstSetNumber += firstSetPositiveNumber) << 'n'; - firstSetSourceName = firstSetPositiveNumber; - firstSetSeqId += firstSetNonNegativeNumber; - for (char c = 'A'; c != 'Z'; ++c) - firstSetSeqId << c; - (((firstSetExpression += firstSetOperatorName) += firstSetTemplateParam) - /* += firstSetFunctionParam */ += firstSetExprPrimary) - << 'c' << 's' << 'a'; - firstSetUnqualifiedName = firstSetOperatorName | firstSetCtorDtorName - | firstSetSourceName; - firstSetPrefix2 = firstSetUnqualifiedName; - firstSetPrefix = firstSetTemplateParam | firstSetSubstitution - | firstSetPrefix2; - firstSetUnscopedName = firstSetUnqualifiedName | (QSet() << 'S'); - firstSetName = firstSetNestedName | firstSetUnscopedName - | firstSetSubstitution | firstSetLocalName; - - /* - * The first set of is much smaller than - * the grammar claims. - * firstSetClassEnumType = firstSetName; - */ - (firstSetClassEnumType += firstSetNonNegativeNumber) << 'N' << 'D' << 'Z'; - - firstSetEncoding = firstSetName | firstSetSpecialName; - ((((((((firstSetType += firstSetBuiltinType) += firstSetFunctionType) - += firstSetClassEnumType) += firstSetArrayType) - += firstSetPointerToMemberType) += firstSetTemplateParam) - += firstSetSubstitution) += firstSetCvQualifiers) << 'P' << 'R' - << 'O' << 'C' << 'G' << 'U' << 'D'; - firstSetBareFunctionType = firstSetType; - ((firstSetTemplateArg += firstSetType) += firstSetExprPrimary) - << 'X' << 'I' << 's'; - -#if 0 - foreach (char c, firstSetType) - qDebug("'%c'", c.toAscii()); - qDebug("\n"); - foreach (char c, firstSetExprPrimary) - qDebug("'%c'", c.toAscii()); -#endif -} - -void NameDemanglerPrivate::setupOps() -{ - ops["nw"] = new UnaryOperator("nw", "new "); - ops["na"] = new ArrayNewOperator; - ops["dl"] = new UnaryOperator("dl", "delete "); - ops["da"] = new UnaryOperator("da", "delete[] "); - ops["ps"] = new UnaryOperator("ps", "+"); - ops["ng"] = new UnaryOperator("ng", "-"); - ops["ad"] = new UnaryOperator("ad", "&"); - ops["de"] = new UnaryOperator("de", "*"); - ops["co"] = new UnaryOperator("co", "~"); - ops["pl"] = new BinaryOperator("pl", "+"); - ops["mi"] = new BinaryOperator("mi", "-"); - ops["ml"] = new BinaryOperator("ml", "*"); - ops["dv"] = new BinaryOperator("dv", "/"); - ops["rm"] = new BinaryOperator("rm", "%"); - ops["an"] = new BinaryOperator("an", "&"); - ops["or"] = new BinaryOperator("or", "|"); - ops["eo"] = new BinaryOperator("eo", "^"); - ops["aS"] = new BinaryOperator("aS", "="); - ops["pL"] = new BinaryOperator("pl", "+="); - ops["mI"] = new BinaryOperator("mI", "-="); - ops["mL"] = new BinaryOperator("mL", "*="); - ops["dV"] = new BinaryOperator("dV", "/="); - ops["rM"] = new BinaryOperator("rM", "%="); - ops["aN"] = new BinaryOperator("aN", "&="); - ops["oR"] = new BinaryOperator("oR", "|="); - ops["eO"] = new BinaryOperator("eO", "^="); - ops["ls"] = new BinaryOperator("ls", "<<"); - ops["rs"] = new BinaryOperator("rs", ">>"); - ops["lS"] = new BinaryOperator("lS", "<<="); - ops["rS"] = new BinaryOperator("rS", ">>="); - ops["eq"] = new BinaryOperator("eq", "=="); - ops["ne"] = new BinaryOperator("ne", "!="); - ops["lt"] = new BinaryOperator("lt", "<"); - ops["gt"] = new BinaryOperator("gt", ">"); - ops["le"] = new BinaryOperator("le", "<="); - ops["ge"] = new BinaryOperator("ge", ">="); - ops["nt"] = new UnaryOperator("nt", "!"); - ops["aa"] = new BinaryOperator("aa", "&&"); - ops["oo"] = new BinaryOperator("oo", "||"); - 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", "->"); - ops["cl"] = new FunctionCallOperator; - ops["ix"] = new ArrayAccessOperator; - ops["qu"] = new QuestionMarkOperator; - ops["st"] = new SizeAlignOfOperator("st", "sizeof"); - ops["sz"] = new SizeAlignOfOperator("sz", "sizeof"); - ops["at"] = new SizeAlignOfOperator("at", "alignof"); - ops["az"] = new SizeAlignOfOperator("az", "alignof"); -} - -void NameDemanglerPrivate::addSubstitution(const QByteArray &symbol) -{ - if (!symbol.isEmpty() && !m_substitutions.contains(symbol)) - m_substitutions.append(symbol); -} - -void NameDemanglerPrivate::insertQualifier(QByteArray &type, const QByteArray &qualifier) -{ - int funcAnchor = -1; - while (true) { - funcAnchor = type.indexOf('(', funcAnchor + 1); - if (funcAnchor == -1) - break; - if (funcAnchor == type.count() - 1) { - funcAnchor = -1; - break; - } - const int next = type.at(funcAnchor + 1); - if (next != '*' && next != '&') - break; - } - - int qualAnchorCandidates[4]; - qualAnchorCandidates[0] = type.indexOf("*)"); - qualAnchorCandidates[1] = type.indexOf("&)"); - qualAnchorCandidates[2] = type.indexOf("const)"); - qualAnchorCandidates[3] = type.indexOf("volatile)"); - int qualAnchor = -1; - for (std::size_t i = 0 ; i < sizeof qualAnchorCandidates/sizeof *qualAnchorCandidates; ++i) { - const int candidate = qualAnchorCandidates[i]; - if (candidate == -1) - continue; - if (qualAnchor == -1) - qualAnchor = candidate; - else - qualAnchor = qMin(qualAnchor, candidate); - } - - int insertionPos; - QByteArray insertionString = qualifier; - if (funcAnchor == -1) { - if (qualAnchor == -1) { - insertionPos = type.size(); - } else { - insertionPos = type.indexOf(')', qualAnchor); - } - } else if (qualAnchor == -1 || funcAnchor < qualAnchor) { - if (qualifier == "*" || qualifier == "&") { - insertionPos = funcAnchor; - insertionString = '(' + qualifier + ')'; - } else { - insertionPos = type.size(); // Qualifier for pointer to member. - } - } else { - insertionPos = type.indexOf(')', qualAnchor); - } - if ((insertionString == "*" || insertionString == "&") - && (type[insertionPos - 1] != '*' && type[insertionPos - 1] != '&')) - insertionString.prepend(' '); - type.insert(insertionPos, insertionString); -} - -NameDemangler::NameDemangler() : d(new NameDemanglerPrivate) { } - -NameDemangler::~NameDemangler() -{ - delete d; -} - -bool NameDemangler::demangle(const QString &mangledName) -{ - return d->demangle(mangledName); -} - -QString NameDemangler::errorString() const -{ - return d->errorString(); -} - -QString NameDemangler::demangledName() const -{ - return d->demangledName(); -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/namedemangler/demanglerexceptions.h b/src/plugins/debugger/namedemangler/demanglerexceptions.h new file mode 100644 index 00000000000..2410e95ed27 --- /dev/null +++ b/src/plugins/debugger/namedemangler/demanglerexceptions.h @@ -0,0 +1,84 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#ifndef DEMANGLEREXCEPTIONS_H +#define DEMANGLEREXCEPTIONS_H + +#include +#include + +namespace Debugger { +namespace Internal { + +class ParseTreeNode; + +class ParseException +{ +public: + ParseException(const QString &error) : error(error) {} + + const QString error; +}; + +class InternalDemanglerException +{ +public: + InternalDemanglerException(const QString &func, const QString &file, int line) + : func(func), file(file), line(line) {} + + QString func; + QString file; + int line; +}; + +#define DEMANGLER_ASSERT(cond) \ + do { \ + if (!cond) { \ + throw InternalDemanglerException(Q_FUNC_INFO, __FILE__, __LINE__); \ + } \ + } while (0) + +template T *demanglerCast(ParseTreeNode *node, const QString &func, + const QString &file, int line) +{ + T * const out = dynamic_cast(node); + if (!out) + throw InternalDemanglerException(func, file, line); + return out; +} + +#define DEMANGLER_CAST(type, input) demanglerCast(input, QLatin1String(Q_FUNC_INFO), \ + QLatin1String(__FILE__), __LINE__) + +} // namespace Internal +} // namespace Debugger + +#endif // DEMANGLEREXCEPTIONS_H diff --git a/src/plugins/debugger/namedemangler/namedemangler.cpp b/src/plugins/debugger/namedemangler/namedemangler.cpp new file mode 100644 index 00000000000..e3f79dadc89 --- /dev/null +++ b/src/plugins/debugger/namedemangler/namedemangler.cpp @@ -0,0 +1,1751 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "namedemangler.h" + +#include "demanglerexceptions.h" +#include "parsetreenodes.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PARSE_RULE_AND_ADD_RESULT_AS_CHILD(rule, parentNode) \ + do { \ + parse##rule(); \ + DEMANGLER_ASSERT(!m_parseStack.isEmpty()); \ + DEMANGLER_ASSERT(dynamic_cast(m_parseStack.top())); \ + popNodeFromStackAndAddAsChild(parentNode); \ + } while (0) + +// Debugging facility. +//#define DO_TRACE +#ifdef DO_TRACE +#define FUNC_START() \ + qDebug("Function %s has started, input is at position %d.", Q_FUNC_INFO, m_pos) +#define FUNC_END() \ + qDebug("Function %s has finished, input is at position %d..", m_pos) +#else +#define FUNC_START() +#define FUNC_END() +#endif // DO_TRACE + +namespace Debugger { +namespace Internal { + +class NameDemanglerPrivate +{ +public: + bool demangle(const QString &mangledName); + const QString &errorString() const { return m_errorString; } + const QString &demangledName() const { return m_demangledName; } + +private: + char peek(int ahead = 0); + char advance(int steps = 1); + const QByteArray readAhead(int charCount); + + void addSubstitution(const ParseTreeNode *node); + + // One parse function per Non-terminal. + void parseArrayType(); + void parseBareFunctionType(); + void parseBuiltinType(); + void parseCallOffset(); + void parseClassEnumType(); + void parseCtorDtorName(); + void parseCvQualifiers(); + void parseDigit(); + void parseDiscriminator(); + void parseEncoding(); + void parseExpression(); + void parseExprPrimary(); + void parseFloatValue(); + void parseFunctionType(); + void parseLocalName(); + void parseMangledName(); + void parseName(); + void parseNestedName(); + void parseNonNegativeNumber(int base = 10); + void parseNumber(int base = 10); + void parseNvOffset(); + void parseOperatorName(); + void parsePointerToMemberType(); + void parsePrefix(); + void parsePrefix2(); + void parseSpecialName(); + void parseSourceName(); + void parseSubstitution(); + void parseTemplateArg(); + void parseTemplateArgs(); + int parseTemplateParam(); + void parseType(); + void parseUnqualifiedName(); + void parseUnscopedName(); + void parseVOffset(); + + const QByteArray getIdentifier(int len); + int getNonNegativeNumber(int base = 10); + + template T *allocateNodeAndAddToStack() + { + T * const node = new T; + m_parseStack.push(node); + return node; + } + + void popNodeFromStackAndAddAsChild(ParseTreeNode *parentNode) + { + parentNode->addChild(m_parseStack.pop()); + } + + static const char eoi = '$'; + + int m_pos; + QByteArray m_mangledName; + QString m_errorString; + QString m_demangledName; + QList m_substitutions; + QList m_templateParams; + bool m_isConversionOperator; + QStack m_parseStack; +}; + + +bool NameDemanglerPrivate::demangle(const QString &mangledName) +{ + bool success; + try { + m_mangledName = mangledName.toAscii(); + m_pos = 0; + m_isConversionOperator = false; + m_demangledName.clear(); + + if (!MangledNameNode::mangledRepresentationStartsWith(peek())) { + m_demangledName = m_mangledName; + return true; + } + + parseMangledName(); + if (m_pos != m_mangledName.size()) + throw ParseException(QLatin1String("Unconsumed input")); + if (m_parseStack.count() != 1) { + throw ParseException(QString::fromLocal8Bit("There are %1 elements on the parse stack; " + "expected one.").arg(m_parseStack.count())); + } + m_demangledName = m_parseStack.top()->toByteArray(); + + success = true; + } catch (const ParseException &p) { + m_errorString = QString::fromLocal8Bit("Parse error at index %1 of mangled name '%2': %3.") + .arg(m_pos).arg(mangledName, p.error); + success = false; + } catch (const InternalDemanglerException &e) { + m_errorString = QString::fromLocal8Bit("Internal demangler error at function %1, file %2, " + "line %3").arg(e.func, e.file).arg(e.line); + success = false; + } + + qDeleteAll(m_parseStack); + m_parseStack.clear(); + m_substitutions.clear(); + m_templateParams.clear(); + return success; +} + +/* + * Grammar: http://www.codesourcery.com/public/cxx-abi/abi.html#mangling + * The grammar as given there is not LL(k), so a number of transformations + * were necessary, which we will document at the respective parsing function. + * ::= _Z + */ +void NameDemanglerPrivate::parseMangledName() +{ + FUNC_START(); + + MangledNameNode * const node = allocateNodeAndAddToStack(); + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); + + FUNC_END(); +} + +/* + * ::= + * ::= + * ::= + */ +void NameDemanglerPrivate::parseEncoding() +{ + FUNC_START(); + + EncodingNode * const encodingNode = allocateNodeAndAddToStack(); + const char next = peek(); + if (NameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, encodingNode); + if (BareFunctionTypeNode::mangledRepresentationStartsWith(peek())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BareFunctionType, encodingNode); + addSubstitution(encodingNode); + m_templateParams.clear(); + m_isConversionOperator = false; + } else if (SpecialNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SpecialName, encodingNode); + } else { + throw ParseException(QString::fromLatin1("Invalid encoding")); + } + + FUNC_END(); +} + + +/* + * ::= + * ::= + * ::= + * ::= # See Scope Encoding below + * + * We can't use this rule directly, because + * can expand to . We therefore integrate it directly + * into the production for : + * ::= [] + * ::= + * + * Secondly, shares an expansion ("St") with , + * so we have to look further ahead to see which one matches. + */ +void NameDemanglerPrivate::parseName() +{ + FUNC_START(); + + NameNode * const node = allocateNodeAndAddToStack(); + + if ((readAhead(2) == "St" && UnqualifiedNameNode::mangledRepresentationStartsWith(peek(2))) + || UnscopedNameNode::mangledRepresentationStartsWith(peek())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnscopedName, node); + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { + addSubstitution(node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + } + } else { + const char next = peek(); + if (NestedNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NestedName, node); + } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Substitution, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + } else if (LocalNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(LocalName, node); + } else { + throw ParseException(QString::fromLatin1("Invalid name")); + } + } + + FUNC_END(); +} + +/* + * ::= N [] E + * ::= N [] E + * ::= + * ::= + * ::= + * + * The rule leads to an indirect recursion with , so + * we integrate it into : + * ::= N [] + * [] E + * ::= N [] E + * ::= N [] E + * + * The occurrence of in the first expansion makes this rule + * completely unmanageable, because 's first and follow sets are + * not distinct and it also shares elements of its first set with + * and . However, can expand + * to both the non-terminals it is followed by as well as the two competing + * non-terminal sequences in the other rules, so we can just write: + * ::= N [] E + * + * That's not all, though: Both and can start + * with an 'r', so we have to do a two-character-look-ahead for that case. + */ +void NameDemanglerPrivate::parseNestedName() +{ + FUNC_START(); + + if (!NestedNameNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid nested-name")); + + NestedNameNode * const node = allocateNodeAndAddToStack(); + + if (CvQualifiersNode::mangledRepresentationStartsWith(peek()) && peek(1) != 'm' + && peek(1) != 'M' && peek(1) != 's' && peek(1) != 'S') { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CvQualifiers, node); + } + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix, node); + + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid nested-name")); + + FUNC_END(); +} + +/* + * ::= + * ::= + * ::= + * ::= # empty + * ::= + * + * We have to eliminate the left-recursion and the template-prefix rule + * and end up with this: + * ::= [] + * ::= [] + * ::= + */ +void NameDemanglerPrivate::parsePrefix() +{ + FUNC_START(); + + PrefixNode * const node = allocateNodeAndAddToStack(); + + const char next = peek(); + if (TemplateParamNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParam, node); + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { + addSubstitution(node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + } + if (UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) { + addSubstitution(node); + parsePrefix2(); // Pops itself to child list. + } + } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Substitution, node); + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + if (UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) + addSubstitution(node); + } + parsePrefix2(); // Pops itself to child list. + } else { + parsePrefix2(); // Pops itself to child list. + } + + FUNC_END(); +} + +/* + * ::= [] + * ::= # empty + */ +void NameDemanglerPrivate::parsePrefix2() +{ + FUNC_START(); + + // We need to do this so we can correctly add all substitutions, which always start + // with the representation of the prefix node. + ParseTreeNode * const prefixNode = m_parseStack.top(); + Prefix2Node * const node = allocateNodeAndAddToStack(); + prefixNode->addChild(node); + + bool firstRun = true; + while (UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) { + if (!firstRun) + addSubstitution(prefixNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedName, node); + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { + addSubstitution(prefixNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + } + firstRun = false; + } + + m_parseStack.pop(); + FUNC_END(); +} + +/* + * ::= I + E + */ +void NameDemanglerPrivate::parseTemplateArgs() +{ + FUNC_START(); + + TemplateArgsNode * const node = allocateNodeAndAddToStack(); + + if (!TemplateArgsNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid template args")); + + do + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArg, node); + while (TemplateArgNode::mangledRepresentationStartsWith(peek())); + + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid template args")); + + FUNC_END(); +} + +/* + * ::= T_ # first template parameter + * ::= T _ + */ +int NameDemanglerPrivate::parseTemplateParam() +{ + FUNC_START(); + + if (!TemplateParamNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid template-param")); + + TemplateParamNode * const node = allocateNodeAndAddToStack(); + + int index; + if (peek() == '_') + index = 0; + else + index = getNonNegativeNumber() + 1; + if (advance() != '_') + 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)); + } + } else { + node->addChild(m_templateParams.at(index)); + } + + FUNC_END(); + return index; +} + +/* ::= [r] [V] [K] # restrict (C99), volatile, const */ +void NameDemanglerPrivate::parseCvQualifiers() +{ + FUNC_START(); + + CvQualifiersNode * const node = allocateNodeAndAddToStack(); + node->m_hasConst = false; + node->m_hasVolatile = false; + + while (true) { + if (peek() == 'V') { + if (node->m_hasConst || node->m_hasVolatile) + throw ParseException(QLatin1String("Invalid qualifiers: unexpected 'volatile'")); + node->m_hasVolatile = true; + advance(); + } else if (peek() == 'K') { + if (node->m_hasConst) + throw ParseException(QLatin1String("Invalid qualifiers: 'const' appears twice")); + node->m_hasConst = true; + advance(); + } else { + break; + } + } + + FUNC_END(); +} + +/* ::= [n] */ +void NameDemanglerPrivate::parseNumber(int base) +{ + FUNC_START(); + + const char next = peek(); + if (!NumberNode::mangledRepresentationStartsWith(next, base)) + throw ParseException("Invalid number"); + + NumberNode * const node = allocateNodeAndAddToStack(); + + if (next == 'n') { + node->m_isNegative = true; + advance(); + } else { + node->m_isNegative = false; + } + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumber, node); + + FUNC_END(); +} + + +void NameDemanglerPrivate::parseNonNegativeNumber(int base) +{ + FUNC_START(); + + NonNegativeNumberNode * const node = allocateNodeAndAddToStack(); + + int startPos = m_pos; + while (NonNegativeNumberNode::mangledRepresentationStartsWith(peek(), base)) + advance(); + if (m_pos == startPos) + throw ParseException(QString::fromLatin1("Invalid non-negative number")); + node->m_number = m_mangledName.mid(startPos, m_pos - startPos).toULongLong(0, base); + + FUNC_END(); +} + +/* + * Floating-point literals are encoded using a fixed-length lowercase + * hexadecimal string corresponding to the internal representation + * (IEEE on Itanium), high-order bytes first, without leading zeroes. + * For example: "Lf bf800000 E" is -1.0f on Itanium. + */ +void NameDemanglerPrivate::parseFloatValue() +{ + FUNC_START(); + + FloatValueNode * const node = allocateNodeAndAddToStack(); + node->m_value = 0; + + while (FloatValueNode::mangledRepresentationStartsWith(peek())) { + // TODO: Construct value; + advance(); + } + + FUNC_END(); +} + +/* + * ::= # type or template + * ::= X E # expression + * ::= # simple expressions + * ::= J * E # argument pack + * ::= sp # pack expansion of (C++0x) + */ +void NameDemanglerPrivate::parseTemplateArg() +{ + FUNC_START(); + + TemplateArgNode * const node = allocateNodeAndAddToStack(); + node->m_isTemplateArgumentPack = false; + + char next = peek(); + if (readAhead(2) == "sp") { + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + } else if (TypeNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (ExprPrimaryNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExprPrimary, node); + } else if (next == 'X') { + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid template-arg")); + } else if (next == 'J') { + advance(); + while (TemplateArgNode::mangledRepresentationStartsWith(peek())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArg, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid template-arg")); + } else { + throw ParseException(QString::fromLatin1("Invalid template-arg")); + } + + m_templateParams.append(node); + FUNC_END(); +} + +/* + * ::= + * ::= + * ::= + * ::= cl * E # call + * ::= cv expression # conversion with one argument + * ::= cv _ * E # conversion with a different number of arguments + * ::= st # sizeof (a type) + * ::= at # alignof (a type) + * ::= + * ::= + * ::= sr # dependent name + * ::= sr # dependent template-id + * ::= sZ # size of a parameter pack + * ::= + * + * Note that the grammar is missing the definition of . This + * has not been a problem in the test cases so far. + * TODO: is now defined and should therefore be supported + */ +void NameDemanglerPrivate::parseExpression() +{ + FUNC_START(); + + ExpressionNode * const node = allocateNodeAndAddToStack(); + node->m_type = ExpressionNode::OtherType; + + /* + * Some of the terminals in the productions of + * also appear in the productions of . We assume the direct + * productions to have higher precedence and check them first to prevent + * them being parsed by parseOperatorName(). + */ + QByteArray str = readAhead(2); + if (str == "cl") { + advance(2); + while (ExpressionNode::mangledRepresentationStartsWith(peek())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid expression")); + } else if (str == "cv") { + node->m_type = ExpressionNode::ConversionType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + if (peek() == '_') { + advance(); + while (ExpressionNode::mangledRepresentationStartsWith(peek())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid expression")); + } else { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + } + } else if (str == "st") { + node->m_type = ExpressionNode::SizeofType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "at") { + node->m_type = ExpressionNode::AlignofType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "sr") { // TODO: Which syntax to use here? + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedName, node); + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + } else if (str == "sZ") { + node->m_type = ExpressionNode::ParameterPackSizeType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParam, node); + } else { + const char next = peek(); + if (OperatorNameNode::mangledRepresentationStartsWith(next)) { + node->m_type = ExpressionNode::OperatorType; + parseOperatorName(); + OperatorNameNode * const opNode = DEMANGLER_CAST(OperatorNameNode, m_parseStack.pop()); + node->addChild(opNode); + + int expressionCount; + switch (opNode->m_type) { + case OperatorNameNode::TernaryType: + expressionCount = 3; + break; + case OperatorNameNode::ArrayNewType: + case OperatorNameNode::BinaryPlusType: + case OperatorNameNode::BinaryMinusType: + case OperatorNameNode::MultType: + case OperatorNameNode::DivType: + case OperatorNameNode::ModuloType: + case OperatorNameNode::BitwiseAndType: + case OperatorNameNode::BitwiseOrType: + case OperatorNameNode::XorType: + case OperatorNameNode::AssignType: + case OperatorNameNode::IncrementAndAssignType: + case OperatorNameNode::DecrementAndAssignType: + case OperatorNameNode::MultAndAssignType: + case OperatorNameNode::DivAndAssignType: + case OperatorNameNode::ModuloAndAssignType: + case OperatorNameNode::BitwiseAndAndAssignType: + case OperatorNameNode::BitwiseOrAndAssignType: + case OperatorNameNode::XorAndAssignType: + case OperatorNameNode::LeftShiftType: + case OperatorNameNode::RightShiftType: + case OperatorNameNode::LeftShiftAndAssignType: + case OperatorNameNode::RightShiftAndAssignType: + case OperatorNameNode::EqualsType: + case OperatorNameNode::NotEqualsType: + case OperatorNameNode::LessType: + case OperatorNameNode::GreaterType: + case OperatorNameNode::LessEqualType: + case OperatorNameNode::GreaterEqualType: + case OperatorNameNode::LogicalAndType: + case OperatorNameNode::LogicalOrType: + case OperatorNameNode::CommaType: + case OperatorNameNode::ArrowStarType: + case OperatorNameNode::ArrowType: + case OperatorNameNode::IndexType: + expressionCount = 2; + break; + default: + expressionCount = 1; + } + + for (int i = 0; i < expressionCount; ++i) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + + } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParam, node); + +#if 0 + } else if (FunctionParamNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FunctionParam, node); +#endif + } else if (ExprPrimaryNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExprPrimary, node); + } else { + throw ParseException(QString::fromLatin1("Invalid expression")); + } + } + + FUNC_END(); +} + +/* + * ::= L E # integer literal + * ::= L E # floating literal + * ::= L E # external name + */ + // TODO: This has been updated in the spec. Needs to be adapted. (nullptr etc.) +void NameDemanglerPrivate::parseExprPrimary() +{ + FUNC_START(); + + ExprPrimaryNode * const node = allocateNodeAndAddToStack(); + + if (!ExprPrimaryNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid primary expression")); + const char next = peek(); + if (TypeNode::mangledRepresentationStartsWith(next)) { + parseType(); + const ParseTreeNode * const topLevelTypeNode = m_parseStack.top(); + BuiltinTypeNode * const typeNode = topLevelTypeNode->childCount() == 0 + ? 0 : dynamic_cast(CHILD_AT(topLevelTypeNode, 0)); + if (!typeNode) + throw ParseException(QLatin1String("Invalid type in expr-primary")); + PredefinedBuiltinTypeNode * const predefTypeNode + = dynamic_cast(CHILD_AT(typeNode, 0)); + if (!predefTypeNode) + throw ParseException(QLatin1String("Invalid type in expr-primary")); + + // TODO: Of which type can a literal actually be? + switch (predefTypeNode->m_type) { + case PredefinedBuiltinTypeNode::SignedIntType: + case PredefinedBuiltinTypeNode::UnsignedIntType: + case PredefinedBuiltinTypeNode::UnsignedLongType: + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); + break; + case PredefinedBuiltinTypeNode::FloatType: case PredefinedBuiltinTypeNode::DoubleType: + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FloatValue, node); + break; + default: + throw ParseException(QString::fromLatin1("Invalid type in expr-primary")); + } + delete m_parseStack.pop(); // No need to keep the type node in the tree. + } else if (MangledNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(MangledName, node); + } else { + throw ParseException(QString::fromLatin1("Invalid expr-primary")); + } + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid expr-primary")); + + FUNC_END(); +} + +/* + * ::= + * ::= + * ::= + * ::= + * ::= + * ::= + * ::= + * ::= # See Compression below + * ::= + * ::= P # pointer-to + * ::= R # reference-to + * ::= O # rvalue reference-to (C++0x) + * ::= C # complex pair (C 2000) + * ::= G # imaginary (C 2000) + * ::= U # vendor extended type qualifier + * ::= Dp # pack expansion of (C++0x) + * ::= Dt E # decltype of an id-expression or class member access (C++0x) + * ::= DT E # decltype of an expression (C++0x) + * + * Because can expand to , we have to + * do a slight transformation: We get rid of and + * integrate its rhs into 's rhs. This leads to the following + * identical prefixes: + * ::= + * ::= + * ::= + * ::= + * + * Also, the first set of has some overlap with + * direct productions of , so these have to be worked around as well. + */ +void NameDemanglerPrivate::parseType() +{ + FUNC_START(); + + TypeNode * const node = allocateNodeAndAddToStack(); + + QByteArray str = readAhead(2); + if (str == "Dp") { + node->m_type = TypeNode::PackExpansionType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "Dt") { + node->m_type = TypeNode::DeclType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid type")); + } else if (str == "DT") { + node->m_type = TypeNode::DeclType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid type")); + } else { + const char next = peek(); + if (str == "Dd" || str == "De" || str == "Df" || str == "Dh" || str == "Di" || str == "Ds" + || (next != 'D' && BuiltinTypeNode::mangledRepresentationStartsWith(next))) { + node->m_type = TypeNode::OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BuiltinType, node); + } else if (FunctionTypeNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FunctionType, node); + addSubstitution(node); + } else if (ClassEnumTypeNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ClassEnumType, node); + addSubstitution(node); + } else if (ArrayTypeNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ArrayType, node); + } else if (PointerToMemberTypeNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(PointerToMemberType, node); + } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::OtherType; + const int templateIndex = parseTemplateParam(); + popNodeFromStackAndAddAsChild(node); + // The type is now a substitution candidate, but the child node may contain a forward + // reference, so we delay the substitution until it is resolved. + // TODO: Check whether this is really safe, i.e. whether the following parse function + // might indirectly expect this substitution to already exist. + + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + // Substitution delayed, see above. + } + + // Resolve forward reference, if necessary. + ParseTreeNode * const templateParamNode = CHILD_AT(node, 0); + if (templateParamNode->childCount() == 0) { + if (templateIndex >= m_templateParams.count()) { + throw ParseException(QString::fromLocal8Bit("Invalid template parameter " + "index %1 in forwarding").arg(templateIndex)); + } + templateParamNode->addChild(m_templateParams.at(templateIndex)); + } + + // Delayed substitutions from above. + addSubstitution(templateParamNode); + if (node->childCount() > 1) + addSubstitution(node); + } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Substitution, node); + if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); + addSubstitution(node); + } + } else if (CvQualifiersNode::mangledRepresentationStartsWith(next)) { + node->m_type = TypeNode::QualifiedType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CvQualifiers, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + const CvQualifiersNode * const cvNode + = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(node, 0)); + if (cvNode->m_hasConst || cvNode->m_hasVolatile) + addSubstitution(node); + } else if (next == 'P') { + node->m_type = TypeNode::PointerType; + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + addSubstitution(node); + } else if (next == 'R') { + node->m_type = TypeNode::ReferenceType; + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + addSubstitution(node); + } else if (next == 'O') { + node->m_type = TypeNode::RValueType; + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + addSubstitution(node); + } else if (next == 'C') { + node->m_type = TypeNode::OtherType; + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + addSubstitution(node); + } else if (next == 'G') { + node->m_type = TypeNode::OtherType; + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + addSubstitution(node); + } else if (next == 'U') { + node->m_type = TypeNode::VendorType; + advance(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else { + throw ParseException(QString::fromLatin1("Invalid type")); + } + } + + FUNC_END(); +} + +/* ::= */ +void NameDemanglerPrivate::parseSourceName() +{ + FUNC_START(); + + SourceNameNode * const node = allocateNodeAndAddToStack(); + + const int idLen = getNonNegativeNumber(); + node->m_name = getIdentifier(idLen); + + FUNC_END(); +} + +/* + * ::= v # void + * ::= w # wchar_t + * ::= b # bool + * ::= c # char + * ::= a # signed char + * ::= h # unsigned char + * ::= s # short + * ::= t # unsigned short + * ::= i # int + * ::= j # unsigned int + * ::= l # long + * ::= m # unsigned long + * ::= x # long long, __int64 + * ::= y # unsigned long long, __int64 + * ::= n # __int128 + * ::= o # unsigned __int128 + * ::= f # float + * ::= d # double + * ::= e # long double, __float80 + * ::= g # __float128 + * ::= z # ellipsis + * ::= Dd # IEEE 754r decimal floating point (64 bits) + * ::= De # IEEE 754r decimal floating point (128 bits) + * ::= Df # IEEE 754r decimal floating point (32 bits) + * ::= Dh # IEEE 754r half-precision floating point (16 bits) + * ::= Di # char32_t + * ::= Ds # char16_t + * ::= u # vendor extended type + */ +void NameDemanglerPrivate::parseBuiltinType() +{ + FUNC_START(); + + BuiltinTypeNode * const typeNode = allocateNodeAndAddToStack(); + const char next = advance(); + if (next == 'u') { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, typeNode); + } else { + PredefinedBuiltinTypeNode * const fixedTypeNode = new PredefinedBuiltinTypeNode; + typeNode->addChild(fixedTypeNode); + + switch (next) { + case 'v': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::VoidType; break; + case 'w': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::WCharType; break; + case 'b': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::BoolType; break; + case 'c': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::PlainCharType; break; + case 'a': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedCharType; break; + case 'h': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedCharType; break; + case 's': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedShortType; break; + case 't': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedShortType; break; + case 'i': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedIntType; break; + case 'j': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedIntType; break; + case 'l': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedLongType; break; + case 'm': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedLongType; break; + case 'x': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedLongLongType; break; + case 'y': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedLongLongType; break; + case 'n': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedInt128Type; break; + case 'o': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedInt128Type; break; + case 'f': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::FloatType; break; + case 'd': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DoubleType; break; + case 'e': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::LongDoubleType; break; + case 'g': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Float128Type; break; + case 'z': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::EllipsisType; break; + case 'D': + switch (advance()) { + case 'd': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType64; + break; + case 'e': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType128; + break; + case 'f': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType32; + break; + case 'h': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType16; break; + case 'i': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Char32Type; break; + case 's': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Char16Type; break; + default: throw ParseException(QString::fromLatin1("Invalid built-in type")); + } + break; + default: + DEMANGLER_ASSERT(false); + } + } + + FUNC_END(); +} + +/* ::= F [Y] E */ +void NameDemanglerPrivate::parseFunctionType() +{ + FUNC_START(); + + if (!FunctionTypeNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid function type")); + + FunctionTypeNode * const node = allocateNodeAndAddToStack(); + + if (peek() == 'Y') { + advance(); + node->m_isExternC = true; + } else { + node->m_isExternC = false; + } + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BareFunctionType, node); + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid function type")); + FUNC_END(); +} + +/* ::= + */ +void NameDemanglerPrivate::parseBareFunctionType() +{ + FUNC_START(); + + BareFunctionTypeNode * const node = allocateNodeAndAddToStack(); + + /* + * The following is verbatim from the spec: + * Whether the mangling of a function type includes the return type depends on the context + * and the nature of the function. The rules for deciding whether the return type is included + * are: + * (1) Template functions (names or types) have return types encoded, with the exceptions + * listed below. + * (2) Function types not appearing as part of a function name mangling, e.g. parameters, + * pointer types, etc., have return type encoded, with the exceptions listed below. + * (3) Non-template function names do not have return types encoded. + * The exceptions mentioned in (1) and (2) above, for which the return type is never included, + * are constructors, destructors and conversion operator functions, e.g. operator int. + */ + const EncodingNode * const encodingNode + = dynamic_cast(m_parseStack.at(m_parseStack.count() - 2)); + if (encodingNode) { // Case 1: Function name. + const NameNode * const nameNode = DEMANGLER_CAST(NameNode, CHILD_AT(encodingNode, 0)); + node->m_hasReturnType = nameNode->isTemplate() + && !nameNode->isConstructorOrDestructorOrConversionOperator(); + } else { // Case 2: function type. + // TODO: What do the exceptions look like for this case? + node->m_hasReturnType = true; + } + + do + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + while (TypeNode::mangledRepresentationStartsWith(peek())); + + + FUNC_END(); +} + +/* ::= */ +void NameDemanglerPrivate::parseClassEnumType() +{ + FUNC_START(); + + ClassEnumTypeNode * const node = allocateNodeAndAddToStack(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, node); + + FUNC_END(); +} + +/* + * ::= + * ::= + * ::= + */ +void NameDemanglerPrivate::parseUnqualifiedName() +{ + FUNC_START(); + + UnqualifiedNameNode * const node = allocateNodeAndAddToStack(); + + const char next = peek(); + if (OperatorNameNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(OperatorName, node); + else if (CtorDtorNameNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CtorDtorName, node); + else if (SourceNameNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, node); + else + throw ParseException(QString::fromLatin1("Invalid unqualified-name")); + + FUNC_END(); +} + +/* + * ::= nw # new + * ::= na # new[] + * ::= dl # delete + * ::= da # delete[] + * ::= ps # + (unary) + * ::= ng # - (unary) + * ::= ad # & (unary) + * ::= de # * (unary) + * ::= co # ~ + * ::= pl # + + * ::= mi # - + * ::= ml # * + * ::= dv # / + * ::= rm # % + * ::= an # & + * ::= or # | + * ::= eo # ^ + * ::= aS # = + * ::= pL # += + * ::= mI # -= + * ::= mL # *= + * ::= dV # /= + * ::= rM # %= + * ::= aN # &= + * ::= oR # |= + * ::= eO # ^= + * ::= ls # << + * ::= rs # >> + * ::= lS # <<= + * ::= rS # >>= + * ::= eq # == + * ::= ne # != + * ::= lt # < + * ::= gt # > + * ::= le # <= + * ::= ge # >= + * ::= nt # ! + * ::= aa # && + * ::= oo # || + * ::= pp # ++ + * ::= mm # -- + * ::= cm # , + * ::= pm # ->* + * ::= pt # -> + * ::= cl # () + * ::= ix # [] + * ::= qu # ? + * ::= st # sizeof (a type) + * ::= sz # sizeof (an expression) + * ::= at # alignof (a type) + * ::= az # alignof (an expression) + * ::= cv # (cast) + * ::= v # vendor extended operator + */ +void NameDemanglerPrivate::parseOperatorName() +{ + FUNC_START(); + + OperatorNameNode * const node = allocateNodeAndAddToStack(); + + if (peek() == 'v') { + node->m_type = OperatorNameNode::VendorType; + advance(); + parseDigit(); + popNodeFromStackAndAddAsChild(node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, node); + } else { + const QByteArray id = readAhead(2); + advance(2); + if (id == "cv") { + m_isConversionOperator = true; + node->m_type = OperatorNameNode::CastType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (id == "nw") { + node->m_type = OperatorNameNode::NewType; + } else if (id == "na") { + node->m_type = OperatorNameNode::ArrayNewType; + } else if (id == "dl") { + node->m_type = OperatorNameNode::DeleteType; + } else if (id == "da") { + node->m_type = OperatorNameNode::ArrayDeleteType; + } else if (id == "ps") { + node->m_type = OperatorNameNode::UnaryPlusType; + } else if (id == "ng") { + node->m_type = OperatorNameNode::UnaryMinusType; + } else if (id == "ad") { + node->m_type = OperatorNameNode::UnaryAmpersandType; + } else if (id == "de") { + node->m_type = OperatorNameNode::UnaryStarType; + } else if (id == "co") { + node->m_type = OperatorNameNode::BitwiseNotType; + } else if (id == "pl") { + node->m_type = OperatorNameNode::BinaryPlusType; + } else if (id == "mi") { + node->m_type = OperatorNameNode::BinaryMinusType; + } else if (id == "ml") { + node->m_type = OperatorNameNode::MultType; + } else if (id == "dv") { + node->m_type = OperatorNameNode::DivType; + } else if (id == "rm") { + node->m_type = OperatorNameNode::ModuloType; + } else if (id == "an") { + node->m_type = OperatorNameNode::BitwiseAndType; + } else if (id == "or") { + node->m_type = OperatorNameNode::BitwiseOrType; + } else if (id == "eo") { + node->m_type = OperatorNameNode::XorType; + } else if (id == "aS") { + node->m_type = OperatorNameNode::AssignType; + } else if (id == "pL") { + node->m_type = OperatorNameNode::IncrementAndAssignType; + } else if (id == "mI") { + node->m_type = OperatorNameNode::DecrementAndAssignType; + } else if (id == "mL") { + node->m_type = OperatorNameNode::MultAndAssignType; + } else if (id == "dV") { + node->m_type = OperatorNameNode::DivAndAssignType; + } else if (id == "rM") { + node->m_type = OperatorNameNode::ModuloAndAssignType; + } else if (id == "aN") { + node->m_type = OperatorNameNode::BitwiseAndAndAssignType; + } else if (id == "oR") { + node->m_type = OperatorNameNode::BitwiseOrAndAssignType; + } else if (id == "eO") { + node->m_type = OperatorNameNode::XorAndAssignType; + } else if (id == "ls") { + node->m_type = OperatorNameNode::LeftShiftType; + } else if (id == "rs") { + node->m_type = OperatorNameNode::RightShiftType; + } else if (id == "lS") { + node->m_type = OperatorNameNode::LeftShiftAndAssignType; + } else if (id == "rS") { + node->m_type = OperatorNameNode::RightShiftAndAssignType; + } else if (id == "eq") { + node->m_type = OperatorNameNode::EqualsType; + } else if (id == "ne") { + node->m_type = OperatorNameNode::NotEqualsType; + } else if (id == "lt") { + node->m_type = OperatorNameNode::LessType; + } else if (id == "gt") { + node->m_type = OperatorNameNode::GreaterType; + } else if (id == "le") { + node->m_type = OperatorNameNode::LessEqualType; + } else if (id == "ge") { + node->m_type = OperatorNameNode::GreaterEqualType; + } else if (id == "nt") { + node->m_type = OperatorNameNode::LogicalNotType; + } else if (id == "aa") { + node->m_type = OperatorNameNode::LogicalAndType; + } else if (id == "oo") { + node->m_type = OperatorNameNode::LogicalOrType; + } else if (id == "pp") { + node->m_type = OperatorNameNode::IncrementType; + } else if (id == "mm") { + node->m_type = OperatorNameNode::DecrementType; + } else if (id == "cm") { + node->m_type = OperatorNameNode::CommaType; + } else if (id == "pm") { + node->m_type = OperatorNameNode::ArrowStarType; + } else if (id == "pt") { + node->m_type = OperatorNameNode::ArrowType; + } else if (id == "cl") { + node->m_type = OperatorNameNode::CallType; + } else if (id == "ix") { + node->m_type = OperatorNameNode::IndexType; + } else if (id == "qu") { + node->m_type = OperatorNameNode::TernaryType; + } else if (id == "st") { + node->m_type = OperatorNameNode::SizeofTypeType; + } else if (id == "sz") { + node->m_type = OperatorNameNode::SizeofExprType; + } else if (id == "at") { + node->m_type = OperatorNameNode::AlignofTypeType; + } else if (id == "az") { + node->m_type = OperatorNameNode::AlignofExprType; + } else { + throw ParseException(QString::fromLocal8Bit("Invalid operator encoding '%1'") + .arg(QString::fromLocal8Bit(id))); + } + } + + FUNC_END(); +} + +/* + * ::= A _ + * ::= A [] _ + */ +void NameDemanglerPrivate::parseArrayType() +{ + FUNC_START(); + + if (!ArrayTypeNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid array-type")); + + ArrayTypeNode * const node = allocateNodeAndAddToStack(); + + const char next = peek(); + if (NonNegativeNumberNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumber, node); + else if (ExpressionNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); + + if (advance() != '_') + throw ParseException(QString::fromLatin1("Invalid array-type")); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + + FUNC_END(); +} + +/* ::= M */ +void NameDemanglerPrivate::parsePointerToMemberType() +{ + FUNC_START(); + + if (!PointerToMemberTypeNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid pointer-to-member-type")); + + PointerToMemberTypeNode * const node = allocateNodeAndAddToStack(); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); // Class type. + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); // Member type. + + FUNC_END(); +} + +/* + * ::= S _ # 36-bit number + * ::= S_ + * ::= St # ::std:: + * ::= Sa # ::std::allocator + * ::= Sb # ::std::basic_string + * ::= Ss # ::std::basic_string < char, + * ::std::char_traits, + * ::std::allocator > + * ::= Si # ::std::basic_istream > + * ::= So # ::std::basic_ostream > + * ::= Sd # ::std::basic_iostream > + */ +void NameDemanglerPrivate::parseSubstitution() +{ + FUNC_START(); + + if (!SubstitutionNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid substitution")); + + SubstitutionNode * const node = allocateNodeAndAddToStack(); + + if (NonNegativeNumberNode::mangledRepresentationStartsWith(peek(), 36)) { + const int substIndex = getNonNegativeNumber(36) + 1; + if (substIndex >= m_substitutions.size()) { + throw ParseException(QString::fromLatin1("Invalid substitution: substitution %1 " + "was requested, but there are only %2"). + arg(substIndex + 1).arg(m_substitutions.size())); + } + node->m_type = SubstitutionNode::ActualSubstitutionType; + node->m_substValue = m_substitutions.at(substIndex); + if (advance() != '_') + throw ParseException(QString::fromLatin1("Invalid substitution")); + } else { + switch (advance()) { + case '_': + if (m_substitutions.isEmpty()) + throw ParseException(QString::fromLatin1("Invalid substitution: " + "There are no substitutions")); + node->m_type = SubstitutionNode::ActualSubstitutionType; + node->m_substValue = m_substitutions.first(); + break; + case 't': + node->m_type = SubstitutionNode::StdType; + break; + case 'a': + node->m_type = SubstitutionNode::StdAllocType; + break; + case 'b': + node->m_type = SubstitutionNode::StdBasicStringType; + break; + case 's': + node->m_type = SubstitutionNode::FullStdBasicStringType; + break; + case 'i': + node->m_type = SubstitutionNode::StdBasicIStreamType; + break; + case 'o': + node->m_type = SubstitutionNode::StdBasicOStreamType; + break; + case 'd': + node->m_type = SubstitutionNode::StdBasicIoStreamType; + break; + default: + throw ParseException(QString::fromLatin1("Invalid substitution")); + } + } + + FUNC_END(); +} + +/* + * ::= TV # virtual table + * ::= TT # VTT structure (construction vtable index) + * ::= TI # typeinfo structure + * ::= TS # typeinfo name (null-terminated byte string) + * ::= GV # Guard variable for one-time initialization + * ::= T + * ::= Tc + * # base is the nominal target function of thunk + * # first call-offset is 'this' adjustment + * # second call-offset is result adjustment + */ +void NameDemanglerPrivate::parseSpecialName() +{ + FUNC_START(); + + SpecialNameNode * const node = allocateNodeAndAddToStack(); + + QByteArray str = readAhead(2); + if (str == "TV") { + node->m_type = SpecialNameNode::VirtualTableType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "TT") { + node->m_type = SpecialNameNode::VttStructType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "TI") { + node->m_type = SpecialNameNode::TypeInfoType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "TS") { + node->m_type = SpecialNameNode::TypeInfoNameType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); + } else if (str == "GV") { + node->m_type = SpecialNameNode::GuardVarType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, node); + } else if (str == "Tc") { + node->m_type = SpecialNameNode::DoubleCallOffsetType; + advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffset, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffset, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); + } else if (advance() == 'T') { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffset, node); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); + } else { + throw ParseException(QString::fromLatin1("Invalid special-name")); + } + + FUNC_END(); +} + +/* + * ::= + * ::= St # ::std:: + */ +void NameDemanglerPrivate::parseUnscopedName() +{ + FUNC_START(); + + UnscopedNameNode * const node = allocateNodeAndAddToStack(); + + if (readAhead(2) == "St") { + node->m_inStdNamespace = true; + advance(2); + } else { + node->m_inStdNamespace = false; + } + + if (!UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) + throw ParseException(QString::fromLatin1("Invalid unscoped-name")); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedName, node); + + FUNC_END(); +} + + +/* + * := Z E [] + * := Z E s [] + * + * Note that can start with 's', so we need to do read-ahead. + */ +void NameDemanglerPrivate::parseLocalName() +{ + FUNC_START(); + + if (!LocalNameNode::mangledRepresentationStartsWith(advance())) + throw ParseException(QString::fromLatin1("Invalid local-name")); + + LocalNameNode * const node = allocateNodeAndAddToStack(); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); + + if (advance() != 'E') + throw ParseException(QString::fromLatin1("Invalid local-name")); + + QByteArray str = readAhead(2); + char next = peek(); + if (str == "sp" || str == "sr" || str == "st" || str == "sz" || str == "sZ" + || (next != 's' && NameNode::mangledRepresentationStartsWith(next))) { + node->m_isStringLiteral = false; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, node); + } else if (next == 's') { + node->m_isStringLiteral = true; + advance(); + } else { + throw ParseException(QString::fromLatin1("Invalid local-name")); + } + if (DiscriminatorNode::mangledRepresentationStartsWith(peek())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Discriminator, node); + + FUNC_END(); +} + +/* := _ */ +void NameDemanglerPrivate::parseDiscriminator() +{ + FUNC_START(); + + if (advance() != '_') + throw ParseException(QString::fromLatin1("Invalid discriminator")); + + DiscriminatorNode * const node = allocateNodeAndAddToStack(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumber, node); + + FUNC_END(); +} + +/* + * ::= C1 # complete object constructor + * ::= C2 # base object constructor + * ::= C3 # complete object allocating constructor + * ::= D0 # deleting destructor + * ::= D1 # complete object destructor + * ::= D2 # base object destructor + */ +void NameDemanglerPrivate::parseCtorDtorName() +{ + FUNC_START(); + + CtorDtorNameNode * const node = allocateNodeAndAddToStack(); + + switch (advance()) { + case 'C': + switch (advance()) { + case '1': case '2': case '3': node->m_isDestructor = false; break; + default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); + } + break; + case 'D': + switch (advance()) { + case '0': case '1': case '2': node->m_isDestructor = true; break; + default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); + } + break; + default: + throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); + } + + node->m_representation = m_substitutions.last(); + + FUNC_END(); +} + +const QByteArray NameDemanglerPrivate::getIdentifier(int len) +{ + FUNC_START(); + + const QByteArray id = m_mangledName.mid(m_pos, len); + advance(len); + + FUNC_END(); + return id; +} + +/* + * ::= h _ + * ::= v _ + */ +void NameDemanglerPrivate::parseCallOffset() +{ + FUNC_START(); + + CallOffsetNode * const node = allocateNodeAndAddToStack(); + switch (advance()) { + case 'h': PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NvOffset, node); break; + case 'v': PARSE_RULE_AND_ADD_RESULT_AS_CHILD(VOffset, node); break; + default: DEMANGLER_ASSERT(false); + } + if (advance() != '_') + throw ParseException(QString::fromLatin1("Invalid call-offset")); + + FUNC_END(); +} + +/* ::= # non-virtual base override */ +void NameDemanglerPrivate::parseNvOffset() +{ + FUNC_START(); + + NvOffsetNode * const node = allocateNodeAndAddToStack(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); + + FUNC_END(); +} + +/* + * ::= _ + * # virtual base override, with vcall offset + */ +void NameDemanglerPrivate::parseVOffset() +{ + FUNC_START(); + + VOffsetNode * const node = allocateNodeAndAddToStack(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); + if (advance() != '_') + throw ParseException(QString::fromLatin1("Invalid v-offset")); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); + + FUNC_END(); +} + +int NameDemanglerPrivate::getNonNegativeNumber(int base) +{ + parseNonNegativeNumber(base); + NonNegativeNumberNode * const numberNode + = DEMANGLER_CAST(NonNegativeNumberNode, m_parseStack.pop()); + const int value = static_cast(numberNode->m_number); + delete numberNode; + return value; +} + +void NameDemanglerPrivate::parseDigit() +{ + FUNC_START(); + + NonNegativeNumberNode * const node = allocateNodeAndAddToStack(); + + const int digit = advance(); + if (!std::isdigit(digit)) + throw ParseException(QString::fromLatin1("Invalid digit")); + node->m_number = digit - 0x30; + + FUNC_END(); +} + +char NameDemanglerPrivate::peek(int ahead) +{ + Q_ASSERT(m_pos >= 0); + + if (m_pos + ahead < m_mangledName.size()) + return m_mangledName[m_pos + ahead]; + return eoi; +} + +char NameDemanglerPrivate::advance(int steps) +{ + Q_ASSERT(steps > 0); + if (m_pos + steps > m_mangledName.size()) + throw ParseException(QLatin1String("Unexpected end of input")); + + const char c = m_mangledName[m_pos]; + m_pos += steps; + return c; +} + +const QByteArray NameDemanglerPrivate::readAhead(int charCount) +{ + QByteArray str; + if (m_pos + charCount < m_mangledName.size()) + str = m_mangledName.mid(m_pos, charCount); + else + str.fill(eoi, charCount); + return str; +} + +void NameDemanglerPrivate::addSubstitution(const ParseTreeNode *node) +{ + const QByteArray symbol = node->toByteArray(); + if (!symbol.isEmpty() && !m_substitutions.contains(symbol)) + m_substitutions.append(symbol); +} + + +NameDemangler::NameDemangler() : d(new NameDemanglerPrivate) { } + +NameDemangler::~NameDemangler() +{ + delete d; +} + +bool NameDemangler::demangle(const QString &mangledName) +{ + return d->demangle(mangledName); +} + +QString NameDemangler::errorString() const +{ + return d->errorString(); +} + +QString NameDemangler::demangledName() const +{ + return d->demangledName(); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/name_demangler.h b/src/plugins/debugger/namedemangler/namedemangler.h similarity index 100% rename from src/plugins/debugger/name_demangler.h rename to src/plugins/debugger/namedemangler/namedemangler.h diff --git a/src/plugins/debugger/namedemangler/namedemangler.pri b/src/plugins/debugger/namedemangler/namedemangler.pri new file mode 100644 index 00000000000..9f5965a26dd --- /dev/null +++ b/src/plugins/debugger/namedemangler/namedemangler.pri @@ -0,0 +1,8 @@ +HEADERS += \ + $$PWD/namedemangler.h \ + $$PWD/parsetreenodes.h \ + namedemangler/demanglerexceptions.h + +SOURCES += \ + $$PWD/namedemangler.cpp \ + $$PWD/parsetreenodes.cpp diff --git a/src/plugins/debugger/namedemangler/parsetreenodes.cpp b/src/plugins/debugger/namedemangler/parsetreenodes.cpp new file mode 100644 index 00000000000..371a99f9086 --- /dev/null +++ b/src/plugins/debugger/namedemangler/parsetreenodes.cpp @@ -0,0 +1,963 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#include "parsetreenodes.h" + +#include "demanglerexceptions.h" + +#include + +#define MY_CHILD_AT(index) CHILD_AT(this, index) +#define CHILD_TO_BYTEARRAY(index) CHILD_AT(this, index)->toByteArray() + +namespace Debugger { +namespace Internal { + +ParseTreeNode::~ParseTreeNode() +{ + qDeleteAll(m_children); +} + +ParseTreeNode *ParseTreeNode::childAt(int i, const QString &func, const QString &file, + int line) const +{ + if (i < 0 || i >= m_children.count()) + throw InternalDemanglerException(func, file, line); + return m_children.at(i); +} + +QByteArray ParseTreeNode::pasteAllChildren() const +{ + QByteArray repr; + foreach (const ParseTreeNode * const node, m_children) + repr += node->toByteArray(); + return repr; +} + + +bool ArrayTypeNode::mangledRepresentationStartsWith(char c) +{ + return c == 'A'; +} + +QByteArray ArrayTypeNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(1) + '[' + CHILD_TO_BYTEARRAY(0) + ']'; +} + + +bool BareFunctionTypeNode::mangledRepresentationStartsWith(char c) +{ + return TypeNode::mangledRepresentationStartsWith(c); +} + +QByteArray BareFunctionTypeNode::toByteArray() const +{ + // This is only the parameter list, including parentheses. Where the return type is placed + // must be decided at a higher level. + QByteArray repr = "("; + for (int i = m_hasReturnType ? 1 : 0; i < childCount(); ++i) { + const QByteArray paramRepr = CHILD_TO_BYTEARRAY(i); + if (paramRepr != "void") + repr += paramRepr; + if (i < childCount() - 1) + repr += ", "; + } + return repr += ')'; +} + + +bool BuiltinTypeNode::mangledRepresentationStartsWith(char c) +{ + return strchr("vwbcahstijlmxynofgedzDu", c); +} + +QByteArray BuiltinTypeNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(0); +} + + +bool CallOffsetNode::mangledRepresentationStartsWith(char c) +{ + return c == 'h' || c == 'v'; +} + +QByteArray CallOffsetNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(0); +} + + +bool ClassEnumTypeNode::mangledRepresentationStartsWith(char c) +{ + /* + * The first set of is much smaller than + * the grammar claims. + * firstSetClassEnumType = firstSetName; + */ + return NonNegativeNumberNode::mangledRepresentationStartsWith(c) + || c == 'N' || c == 'D' || c == 'Z'; +} + +QByteArray ClassEnumTypeNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(0); +} + + +bool DiscriminatorNode::mangledRepresentationStartsWith(char c) +{ + return c == '_'; +} + +QByteArray DiscriminatorNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(0); +} + + +bool CtorDtorNameNode::mangledRepresentationStartsWith(char c) +{ + return c == 'C' || c == 'D'; +} + +QByteArray CtorDtorNameNode::toByteArray() const +{ + QByteArray repr = m_representation; + const int templateArgStart = repr.indexOf('<'); + if (templateArgStart != -1) + repr.truncate(templateArgStart); + const int prefixEnd = repr.lastIndexOf("::"); + if (prefixEnd != -1) + repr.remove(0, prefixEnd + 2); + if (m_isDestructor) + repr.prepend('~'); + return repr; +} + + +bool CvQualifiersNode::mangledRepresentationStartsWith(char c) +{ + return c == 'K' || c == 'V' || c == 'r'; +} + +QByteArray CvQualifiersNode::toByteArray() const +{ + QByteArray repr; + if (m_hasConst) + repr = "const"; + if (m_hasVolatile) { + if (m_hasConst) + repr +=' '; + repr += "volatile"; + } + return repr; +} + + +bool EncodingNode::mangledRepresentationStartsWith(char c) +{ + return NameNode::mangledRepresentationStartsWith(c) + || SpecialNameNode::mangledRepresentationStartsWith(c); +} + +QByteArray EncodingNode::toByteArray() const +{ + if (childCount() == 1) + return CHILD_TO_BYTEARRAY(0); + + const ParseTreeNode * const nameNode = MY_CHILD_AT(0); + const NestedNameNode * const nestedNameNode + = dynamic_cast(CHILD_AT(nameNode, 0)); + const CvQualifiersNode * const cvQualifiersNode = nestedNameNode + ? dynamic_cast(CHILD_AT(nestedNameNode, 0)) : 0; + + QByteArray repr; + const BareFunctionTypeNode * const funcNode + = DEMANGLER_CAST(BareFunctionTypeNode, MY_CHILD_AT(1)); + if (funcNode->m_hasReturnType) + repr = CHILD_AT(funcNode, 0)->toByteArray() + ' '; + if (cvQualifiersNode) { + return repr + CHILD_AT(nestedNameNode, 1)->toByteArray() + funcNode->toByteArray() + ' ' + + cvQualifiersNode->toByteArray(); + } + return repr + nameNode->toByteArray() + funcNode->toByteArray(); +} + + +bool ExpressionNode::mangledRepresentationStartsWith(char c) +{ + return OperatorNameNode::mangledRepresentationStartsWith(c) + || TemplateParamNode::mangledRepresentationStartsWith(c) +/* || FunctionParamNode::mangledRepresentationStartsWith(c) */ + || ExprPrimaryNode::mangledRepresentationStartsWith(c) + || c == 'c' || c == 's' || c == 'a'; +} + +QByteArray ExpressionNode::toByteArray() const +{ + QByteArray repr; + + switch (m_type) { + case ConversionType: + repr = CHILD_TO_BYTEARRAY(0) + '('; + for (int i = 1; i < childCount(); ++i) + repr += CHILD_TO_BYTEARRAY(i); + repr += ')'; + break; + case SizeofType: + repr = "sizeof(" + CHILD_TO_BYTEARRAY(0) + ')'; + break; + case AlignofType: + repr = "alignof(" + CHILD_TO_BYTEARRAY(0) + ')'; + break; + case ParameterPackSizeType: + repr = CHILD_TO_BYTEARRAY(0); // TODO: What does this look like? + case OperatorType: { + const OperatorNameNode * const opNode = DEMANGLER_CAST(OperatorNameNode, MY_CHILD_AT(0)); + switch (opNode->m_type) { + case OperatorNameNode::CallType: + repr = CHILD_TO_BYTEARRAY(1) + opNode->toByteArray(); + break; + case OperatorNameNode::SizeofExprType: case OperatorNameNode::AlignofExprType: + repr = opNode->toByteArray() + '(' + CHILD_TO_BYTEARRAY(1) + ')'; + break; + case OperatorNameNode::ArrayNewType: + repr = "new " + CHILD_TO_BYTEARRAY(1) + '[' + CHILD_TO_BYTEARRAY(2) + ']'; + break; + case OperatorNameNode::IndexType: + repr = CHILD_TO_BYTEARRAY(1) + '[' + CHILD_TO_BYTEARRAY(2) + ']'; + break; + case OperatorNameNode::TernaryType: + repr = CHILD_TO_BYTEARRAY(1) + " ? " + CHILD_TO_BYTEARRAY(2) + " : " + CHILD_TO_BYTEARRAY(3); + break; + case OperatorNameNode::ArrowStarType: case OperatorNameNode::ArrowType: + repr = CHILD_TO_BYTEARRAY(1) + opNode->toByteArray() + CHILD_TO_BYTEARRAY(2); + break; + case OperatorNameNode::BinaryPlusType: + case OperatorNameNode::BinaryMinusType: + case OperatorNameNode::MultType: + case OperatorNameNode::DivType: + case OperatorNameNode::ModuloType: + case OperatorNameNode::BitwiseAndType: + case OperatorNameNode::BitwiseOrType: + case OperatorNameNode::XorType: + case OperatorNameNode::AssignType: + case OperatorNameNode::IncrementAndAssignType: + case OperatorNameNode::DecrementAndAssignType: + case OperatorNameNode::MultAndAssignType: + case OperatorNameNode::DivAndAssignType: + case OperatorNameNode::ModuloAndAssignType: + case OperatorNameNode::BitwiseAndAndAssignType: + case OperatorNameNode::BitwiseOrAndAssignType: + case OperatorNameNode::XorAndAssignType: + case OperatorNameNode::LeftShiftType: + case OperatorNameNode::RightShiftType: + case OperatorNameNode::LeftShiftAndAssignType: + case OperatorNameNode::RightShiftAndAssignType: + case OperatorNameNode::EqualsType: + case OperatorNameNode::NotEqualsType: + case OperatorNameNode::LessType: + case OperatorNameNode::GreaterType: + case OperatorNameNode::LessEqualType: + case OperatorNameNode::GreaterEqualType: + case OperatorNameNode::LogicalAndType: + case OperatorNameNode::LogicalOrType: + case OperatorNameNode::CommaType: + repr = CHILD_TO_BYTEARRAY(1) + ' ' + opNode->toByteArray() + ' ' + CHILD_TO_BYTEARRAY(2); + break; + case OperatorNameNode::NewType: + case OperatorNameNode::DeleteType: + case OperatorNameNode::ArrayDeleteType: + repr = opNode->toByteArray() + ' ' + CHILD_TO_BYTEARRAY(1); + break; + default: // Other unary Operators; + repr = opNode->toByteArray() + CHILD_TO_BYTEARRAY(1); + } + break; + } + case OtherType: + repr = pasteAllChildren(); + } + + return repr; +} + + +bool OperatorNameNode::mangledRepresentationStartsWith(char c) +{ + return strchr("ndpacmroelgiqsv", c); +} + +QByteArray OperatorNameNode::toByteArray() const +{ + switch (m_type) { + case NewType: return "new"; + case ArrayNewType: return "new[]"; + case DeleteType: return "delete"; + case ArrayDeleteType: return "delete[]"; + case UnaryPlusType: case BinaryPlusType: return "+"; + case UnaryMinusType: case BinaryMinusType: return "-"; + case UnaryAmpersandType: case BitwiseAndType: return "&"; + case UnaryStarType: case MultType: return "*"; + case BitwiseNotType: return "~"; + case DivType: return "/"; + case ModuloType: return "%"; + case BitwiseOrType: return "|"; + case XorType: return "^"; + case AssignType: return "="; + case IncrementAndAssignType: return "+="; + case DecrementAndAssignType: return "-="; + case MultAndAssignType: return "*="; + case DivAndAssignType: return "/="; + case ModuloAndAssignType: return "%="; + case BitwiseAndAndAssignType: return "&="; + case BitwiseOrAndAssignType: return "|="; + case XorAndAssignType: return "^="; + case LeftShiftType: return "<<"; + case RightShiftType: return ">>"; + case LeftShiftAndAssignType: return "<<="; + case RightShiftAndAssignType: return ">>="; + case EqualsType: return "=="; + case NotEqualsType: return "!="; + case LessType: return "<"; + case GreaterType: return ">"; + case LessEqualType: return "<="; + case GreaterEqualType: return ">="; + case LogicalNotType: return "!"; + case LogicalAndType: return "&&"; + case LogicalOrType: return "||"; + case IncrementType: return "++"; + case DecrementType: return "--"; + case CommaType: return ","; + case ArrowStarType: return "->*"; + case ArrowType: return "->"; + case CallType: return "()"; + case IndexType: return "[]"; + case TernaryType: return "?"; + case SizeofTypeType: case SizeofExprType: return "sizeof"; + case AlignofTypeType: case AlignofExprType: return "alignof"; + case CastType: return ' ' + CHILD_TO_BYTEARRAY(0); + case VendorType: return "[vendor extended operator]"; + } + + DEMANGLER_ASSERT(false); + return QByteArray(); +} + + +QByteArray PredefinedBuiltinTypeNode::toByteArray() const +{ + switch (m_type) { + case VoidType: return "void"; + case WCharType: return "wchar_t"; + case BoolType: return "bool"; + case PlainCharType: return "char"; + case SignedCharType: return "signed char"; + case UnsignedCharType: return "unsigned char"; + case SignedShortType: return "signed short"; + case UnsignedShortType: return "unsigned short"; + case SignedIntType: return "int"; + case UnsignedIntType: return "unsigned int"; + case SignedLongType: return "long"; + case UnsignedLongType: return "unsigned long"; + case SignedLongLongType: return "long long"; + case UnsignedLongLongType: return "unsigned long long"; + case SignedInt128Type: return "__int128"; + case UnsignedInt128Type: return "unsigned __int128"; + case FloatType: return "float"; + case DoubleType: return "double"; + case LongDoubleType: return "long double"; + case Float128Type: return "__float128"; + case EllipsisType: return "..."; + case DecimalFloatingType16: return "[IEEE 754r half-precision floating point]"; + case DecimalFloatingType32: return "[IEEE 754r decimal floating point (32 bits)]"; + case DecimalFloatingType64: return "[IEEE 754r decimal floating point (64 bits)]"; + case DecimalFloatingType128: return "[IEEE 754r decimal floating point (128 bits)]"; + case Char32Type: return "char32_t"; + case Char16Type: return "char16_t"; + } + + DEMANGLER_ASSERT(false); + return QByteArray(); +} + + +bool ExprPrimaryNode::mangledRepresentationStartsWith(char c) +{ + return c == 'L'; +} + +QByteArray ExprPrimaryNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(0); +} + +bool FunctionTypeNode::mangledRepresentationStartsWith(char c) +{ + return c == 'F'; +} + +QByteArray FunctionTypeNode::toByteArray() const +{ + return QByteArray(); // Not enough knowledge here to generate a string representation. +} + + +bool LocalNameNode::mangledRepresentationStartsWith(char c) +{ + return c == 'Z'; +} + +QByteArray LocalNameNode::toByteArray() const +{ + QByteArray name; + bool hasDiscriminator; + if (m_isStringLiteral) { + name = CHILD_TO_BYTEARRAY(0) + "::[string literal]"; + hasDiscriminator = childCount() == 2; + } else { + name = CHILD_TO_BYTEARRAY(0) + "::" + CHILD_TO_BYTEARRAY(1); + hasDiscriminator = childCount() == 3; + } + if (hasDiscriminator) { + const QByteArray discriminator = MY_CHILD_AT(childCount() - 1)->toByteArray(); + const int rawDiscriminatorValue = discriminator.toInt(); + name += " (occurrence number " + QByteArray::number(rawDiscriminatorValue - 2) + ')'; + } + return name; +} + + +bool MangledNameNode::mangledRepresentationStartsWith(char c) +{ + return c == '_'; +} + +QByteArray MangledNameNode::toByteArray() const +{ + return pasteAllChildren(); +} + + +bool SourceNameNode::mangledRepresentationStartsWith(char c) +{ + return strchr("123456789", c); +} + + +bool UnqualifiedNameNode::mangledRepresentationStartsWith(char c) +{ + return OperatorNameNode::mangledRepresentationStartsWith(c) + || CtorDtorNameNode::mangledRepresentationStartsWith(c) + || SourceNameNode::mangledRepresentationStartsWith(c); +} + +QByteArray UnqualifiedNameNode::toByteArray() const +{ + QByteArray repr; + if (dynamic_cast(MY_CHILD_AT(0))) + repr = "operator"; + return repr += CHILD_TO_BYTEARRAY(0); +} + +bool UnqualifiedNameNode::isConstructorOrDestructorOrConversionOperator() const +{ + if (dynamic_cast(MY_CHILD_AT(0))) + return true; + const OperatorNameNode * const opNode = dynamic_cast(MY_CHILD_AT(0)); + return opNode && opNode->m_type == OperatorNameNode::CastType; +} + + +bool UnscopedNameNode::mangledRepresentationStartsWith(char c) +{ + return UnqualifiedNameNode::mangledRepresentationStartsWith(c) || c == 'S'; +} + +QByteArray UnscopedNameNode::toByteArray() const +{ + QByteArray name = CHILD_TO_BYTEARRAY(0); + if (m_inStdNamespace) + name.prepend("std::"); + return name; +} + +bool UnscopedNameNode::isConstructorOrDestructorOrConversionOperator() const +{ + const UnqualifiedNameNode * const childNode + = DEMANGLER_CAST(UnqualifiedNameNode, MY_CHILD_AT(0)); + return childNode->isConstructorOrDestructorOrConversionOperator(); +} + + +bool NestedNameNode::mangledRepresentationStartsWith(char c) +{ + return c == 'N'; +} + +QByteArray NestedNameNode::toByteArray() const +{ + // This the valid representation only if no cv-qualifiers are present. + // In that case (only possible for member functions), a higher-level object must + // create the string representation. + return CHILD_TO_BYTEARRAY(0); +} + +bool NestedNameNode::isTemplate() const +{ + const PrefixNode * const childNode = DEMANGLER_CAST(PrefixNode, MY_CHILD_AT(childCount() - 1)); + return childNode->isTemplate(); +} + +bool NestedNameNode::isConstructorOrDestructorOrConversionOperator() const +{ + const PrefixNode * const childNode = DEMANGLER_CAST(PrefixNode, MY_CHILD_AT(childCount() - 1)); + return childNode->isConstructorOrDestructorOrConversionOperator(); +} + + +bool SubstitutionNode::mangledRepresentationStartsWith(char c) +{ + return c == 'S'; +} + +QByteArray SubstitutionNode::toByteArray() const +{ + switch (m_type) { + case ActualSubstitutionType: return m_substValue; + case StdType: return "std"; + case StdAllocType: return "std::allocator"; + case StdBasicStringType: return "std::basic_string"; + case FullStdBasicStringType: return "std::basic_string, " + "std::allocator >"; + case StdBasicIStreamType: return "std::basic_istream >"; + case StdBasicOStreamType: return "std::basic_ostream >"; + case StdBasicIoStreamType: return "std::basic_iostream >"; + } + + DEMANGLER_ASSERT(false); + return QByteArray(); +} + + +bool PointerToMemberTypeNode::mangledRepresentationStartsWith(char c) +{ + return c == 'M'; +} + +QByteArray PointerToMemberTypeNode::toByteArray() const +{ + // Gather all qualifiers first, because we have to move them to the end en bloc + // . + QByteArray qualRepr; + const TypeNode *memberTypeNode = DEMANGLER_CAST(TypeNode, MY_CHILD_AT(1)); + while (memberTypeNode->m_type == TypeNode::QualifiedType) { + const CvQualifiersNode * const cvNode + = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(memberTypeNode, 0)); + if (cvNode->m_hasConst || cvNode->m_hasVolatile) { + if (!qualRepr.isEmpty()) + qualRepr += ' '; + qualRepr += cvNode->toByteArray(); + } + memberTypeNode = DEMANGLER_CAST(TypeNode, CHILD_AT(memberTypeNode, 1)); + } + + QByteArray repr; + const QByteArray classTypeRepr = CHILD_TO_BYTEARRAY(0); + const FunctionTypeNode * const functionNode + = dynamic_cast(CHILD_AT(memberTypeNode, 0)); + if (functionNode) { + const BareFunctionTypeNode * const bareFunctionNode + = DEMANGLER_CAST(BareFunctionTypeNode, CHILD_AT(functionNode, 0)); + if (functionNode->m_isExternC) + repr += "extern \"C\" "; + if (bareFunctionNode->m_hasReturnType) + repr += CHILD_AT(bareFunctionNode, 0)->toByteArray() + ' '; + repr += '(' + classTypeRepr + "::*)" + bareFunctionNode->toByteArray(); + if (!qualRepr.isEmpty()) + repr += ' ' + qualRepr; + } else { + repr = memberTypeNode->toByteArray() + ' ' + classTypeRepr + "::"; + if (!qualRepr.isEmpty()) + repr += qualRepr + ' '; + repr += '*'; + } + return repr; +} + + +TemplateParamNode::~TemplateParamNode() +{ + clearChildList(); // Child node is deleted elsewhere. +} + +bool TemplateParamNode::mangledRepresentationStartsWith(char c) +{ + return c == 'T'; +} + +QByteArray TemplateParamNode::toByteArray() const +{ + return CHILD_TO_BYTEARRAY(0); +} + + +bool TemplateArgsNode::mangledRepresentationStartsWith(char c) +{ + return c == 'I'; +} + +QByteArray TemplateArgsNode::toByteArray() const +{ + QByteArray repr = "<"; + for (int i = 0; i < childCount(); ++i) { + repr += CHILD_TO_BYTEARRAY(i); + if (i < childCount() - 1) + repr += ", "; + } + return repr += '>'; +} + + +bool SpecialNameNode::mangledRepresentationStartsWith(char c) +{ + return c == 'T' || c == 'G'; +} + +QByteArray SpecialNameNode::toByteArray() const +{ + switch (m_type) { + case VirtualTableType: + return "[virtual table of " + CHILD_TO_BYTEARRAY(0) + ']'; + case VttStructType: + return "[VTT struct of " + CHILD_TO_BYTEARRAY(0) + ']'; + case TypeInfoType: + return "typeid(" + CHILD_TO_BYTEARRAY(0) + ')'; + case TypeInfoNameType: + return "typeid(" + CHILD_TO_BYTEARRAY(0) + ").name()"; + case GuardVarType: + return "[guard variable of " + CHILD_TO_BYTEARRAY(0) + ']'; + case SingleCallOffsetType: + return "[offset:" + CHILD_TO_BYTEARRAY(0) + ']' + CHILD_TO_BYTEARRAY(1); + case DoubleCallOffsetType: + return "[this-adjustment:" + CHILD_TO_BYTEARRAY(0) + "][result-adjustment:" + + CHILD_TO_BYTEARRAY(1) + ']' + CHILD_TO_BYTEARRAY(2); + } + + DEMANGLER_ASSERT(false); + return QByteArray(); +} + + +bool NumberNode::mangledRepresentationStartsWith(char c, int base) +{ + return NonNegativeNumberNode::mangledRepresentationStartsWith(c, base) || c == 'n'; +} + +QByteArray NumberNode::toByteArray() const +{ + QByteArray repr = CHILD_TO_BYTEARRAY(0); + if (m_isNegative) + repr.prepend('-'); + return repr; +} + + +bool NonNegativeNumberNode::mangledRepresentationStartsWith(char c, int base) +{ + // Base can only be 10 or 36. + if (base == 10) + return strchr("0123456789", c); + else + return strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", c); +} + +QByteArray NonNegativeNumberNode::toByteArray() const +{ + return QByteArray::number(m_number); +} + + +bool NameNode::mangledRepresentationStartsWith(char c) +{ + return NestedNameNode::mangledRepresentationStartsWith(c) + || UnscopedNameNode::mangledRepresentationStartsWith(c) + || SubstitutionNode::mangledRepresentationStartsWith(c) + || LocalNameNode::mangledRepresentationStartsWith(c); +} + +QByteArray NameNode::toByteArray() const +{ + return pasteAllChildren(); +} + +bool NameNode::isTemplate() const +{ + if (childCount() > 1 && dynamic_cast(MY_CHILD_AT(1))) + return true; + const NestedNameNode * const nestedNameNode = dynamic_cast(MY_CHILD_AT(0)); + if (nestedNameNode) + return nestedNameNode->isTemplate(); + + // TODO: Is relevant? + return false; +} + +bool NameNode::isConstructorOrDestructorOrConversionOperator() const +{ + const NestedNameNode * const nestedNameNode = dynamic_cast(MY_CHILD_AT(0)); + if (nestedNameNode) + return nestedNameNode->isConstructorOrDestructorOrConversionOperator(); + + // TODO: Is relevant? + return false; +} + + +bool TemplateArgNode::mangledRepresentationStartsWith(char c) +{ + return TypeNode::mangledRepresentationStartsWith(c) + || ExprPrimaryNode::mangledRepresentationStartsWith(c) + || c == 'X' || c == 'I' || c == 's'; +} + +QByteArray TemplateArgNode::toByteArray() const +{ + if (m_isTemplateArgumentPack) { + QByteArray repr; + for (int i = 0; i < childCount(); ++i) { + if (i > 0 && i < childCount() - 1) + repr += ", "; // TODO: Probably not the right syntax + repr += CHILD_TO_BYTEARRAY(i); + } + return repr; + } + return CHILD_TO_BYTEARRAY(0); +} + + +bool Prefix2Node::mangledRepresentationStartsWith(char c) +{ + return UnqualifiedNameNode::mangledRepresentationStartsWith(c); +} + +QByteArray Prefix2Node::toByteArray() const +{ + if (childCount() == 0) + return QByteArray(); + QByteArray repr = CHILD_TO_BYTEARRAY(0); + for (int i = 1; i < childCount(); ++i) { + if (dynamic_cast(MY_CHILD_AT(i))) + repr += "::"; // Don't show the "global namespace" indicator. + repr += CHILD_TO_BYTEARRAY(i); + } + return repr; +} + +bool Prefix2Node::isTemplate() const +{ + return dynamic_cast(MY_CHILD_AT(childCount() - 1)); +} + +bool Prefix2Node::isConstructorOrDestructorOrConversionOperator() const +{ + for (int i = childCount() - 1; i >= 0; --i) { + const UnqualifiedNameNode * const n = dynamic_cast(MY_CHILD_AT(i)); + if (n) + return n->isConstructorOrDestructorOrConversionOperator(); + } + return false; +} + + +bool PrefixNode::mangledRepresentationStartsWith(char c) +{ + return TemplateParamNode::mangledRepresentationStartsWith(c) + || SubstitutionNode::mangledRepresentationStartsWith(c) + || Prefix2Node::mangledRepresentationStartsWith(c); +} + +QByteArray PrefixNode::toByteArray() const +{ + if (childCount() == 1) + return CHILD_TO_BYTEARRAY(0); + if (MY_CHILD_AT(childCount() - 1)->childCount() == 0) // Empty prefix2, i.e. no symbol follows. + return pasteAllChildren(); + if (childCount() == 2) + return CHILD_TO_BYTEARRAY(0) + "::" + CHILD_TO_BYTEARRAY(1); + return CHILD_TO_BYTEARRAY(0) + CHILD_TO_BYTEARRAY(1) + "::" + CHILD_TO_BYTEARRAY(2); +} + +bool PrefixNode::isTemplate() const +{ + if (childCount() > 1 && dynamic_cast(CHILD_AT(this, 1))) + return true; + const Prefix2Node * const childNode + = DEMANGLER_CAST(Prefix2Node, MY_CHILD_AT(childCount() - 1)); + return childNode->isTemplate(); +} + +bool PrefixNode::isConstructorOrDestructorOrConversionOperator() const +{ + const Prefix2Node * const childNode + = DEMANGLER_CAST(Prefix2Node, MY_CHILD_AT(childCount() - 1)); + return childNode->isConstructorOrDestructorOrConversionOperator(); +} + + +bool TypeNode::mangledRepresentationStartsWith(char c) +{ + return BuiltinTypeNode::mangledRepresentationStartsWith(c) + || FunctionTypeNode::mangledRepresentationStartsWith(c) + || ClassEnumTypeNode::mangledRepresentationStartsWith(c) + || ArrayTypeNode::mangledRepresentationStartsWith(c) + || PointerToMemberTypeNode::mangledRepresentationStartsWith(c) + || TemplateParamNode::mangledRepresentationStartsWith(c) + || SubstitutionNode::mangledRepresentationStartsWith(c) + || CvQualifiersNode::mangledRepresentationStartsWith(c) + || strchr("PROCGUD", c); + +} + +QByteArray TypeNode::toByteArray() const +{ + // A pure top-down approach is not possible to due to the weird function pointer syntax, + // e.g. things like (* const &)(int) etc. + // Instead, we have to gather all successive qualifiers, pointers and references first + // and then apply them as a whole to whatever follows. + // Note that "qualifier to function" is not possible here, since that is handled by + // PointerToMemberType. + QList qualPtrRefList; + const TypeNode *currentNode = this; + bool leafType = false; + while (!leafType) { + switch (currentNode->m_type) { + case QualifiedType: { + const CvQualifiersNode * const cvNode + = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(currentNode, 0)); + if (cvNode->m_hasConst || cvNode->m_hasVolatile) + qualPtrRefList << cvNode; + currentNode = DEMANGLER_CAST(TypeNode, CHILD_AT(currentNode, 1)); + break; + } + case PointerType: case ReferenceType: case RValueType: + qualPtrRefList << currentNode; + currentNode = DEMANGLER_CAST(TypeNode, CHILD_AT(currentNode, 0)); + break; + default: + leafType = true; + break; + } + } + + if (qualPtrRefList.isEmpty()) { + switch (currentNode->m_type) { + case PackExpansionType: return CHILD_TO_BYTEARRAY(0); // TODO: What's the syntax? + case DeclType: return "decltype(" + CHILD_TO_BYTEARRAY(0) + ')'; + case VendorType: return pasteAllChildren(); + case OtherType: return pasteAllChildren(); + default: DEMANGLER_ASSERT(false); + } + } + + return toByteArrayQualPointerRef(currentNode, qualPtrRefListToByteArray(qualPtrRefList)); +} + +QByteArray TypeNode::toByteArrayQualPointerRef(const TypeNode *typeNode, + const QByteArray &qualPtrRef) const +{ + const FunctionTypeNode * const functionNode + = dynamic_cast(CHILD_AT(typeNode, 0)); + if (functionNode) { + const BareFunctionTypeNode * const bareFunctionNode + = DEMANGLER_CAST(BareFunctionTypeNode, CHILD_AT(functionNode, 0)); + QByteArray repr; + if (functionNode->m_isExternC) + repr += "extern \"C\" "; + if (bareFunctionNode->m_hasReturnType) + repr += CHILD_AT(bareFunctionNode, 0)->toByteArray() + ' '; + return repr += '(' + qualPtrRef + ')' + bareFunctionNode->toByteArray(); + } + + if (dynamic_cast(CHILD_AT(typeNode, 0))) + return typeNode->toByteArray() + qualPtrRef; + + return typeNode->toByteArray() + ' ' + qualPtrRef; +} + +QByteArray TypeNode::qualPtrRefListToByteArray(const QList &nodeList) const +{ + QByteArray repr; + foreach (const ParseTreeNode * const n, nodeList) { + const TypeNode * const typeNode = dynamic_cast(n); + if (typeNode) { + switch (typeNode->m_type) { + case PointerType: + if (!repr.isEmpty() && !repr.startsWith('*')) + repr.prepend(' '); + repr.prepend('*'); + break; + case ReferenceType: + if (!repr.isEmpty()) + repr.prepend(' '); + repr.prepend('&'); + break; + case RValueType: + if (!repr.isEmpty()) + repr.prepend(' '); + repr.prepend("&&"); + default: + DEMANGLER_ASSERT(false); + } + } else { + if (!repr.isEmpty()) + repr.prepend(' '); + repr.prepend(n->toByteArray()); + } + } + return repr; +} + + +bool FloatValueNode::mangledRepresentationStartsWith(char c) +{ + return strchr("0123456789abcdef", c); +} + +QByteArray FloatValueNode::toByteArray() const +{ + return QByteArray::number(m_value); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/namedemangler/parsetreenodes.h b/src/plugins/debugger/namedemangler/parsetreenodes.h new file mode 100644 index 00000000000..c8730092a2c --- /dev/null +++ b/src/plugins/debugger/namedemangler/parsetreenodes.h @@ -0,0 +1,429 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#ifndef PARSETREENODES_H +#define PARSETREENODES_H + +#include +#include +#include + +#define CHILD_AT(obj, index) obj->childAt(index, Q_FUNC_INFO, __FILE__, __LINE__) + +namespace Debugger { +namespace Internal { + +class ParseTreeNode +{ +public: + virtual ~ParseTreeNode(); + virtual QByteArray toByteArray() const = 0; + + int childCount() const { return m_children.count(); } + void addChild(ParseTreeNode *childNode) { m_children << childNode; } + ParseTreeNode *childAt(int i, const QString &func, const QString &file, int line) const; + QByteArray pasteAllChildren() const; + +protected: + void clearChildList() { m_children.clear(); } + +private: + QList m_children; // Convention: Children are inserted in parse order. +}; + +class ArrayTypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class BareFunctionTypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool m_hasReturnType; +}; + +class BuiltinTypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class PredefinedBuiltinTypeNode : public ParseTreeNode +{ +public: + QByteArray toByteArray() const; + + enum Type { + VoidType, WCharType, BoolType, + PlainCharType, SignedCharType, UnsignedCharType, SignedShortType, UnsignedShortType, + SignedIntType, UnsignedIntType, SignedLongType, UnsignedLongType, + SignedLongLongType, UnsignedLongLongType, SignedInt128Type, UnsignedInt128Type, + FloatType, DoubleType, LongDoubleType, Float128Type, EllipsisType, + DecimalFloatingType64, DecimalFloatingType128, DecimalFloatingType32, + DecimalFloatingType16, Char32Type, Char16Type + } m_type; +}; + +class CallOffsetNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class NvOffsetNode : public ParseTreeNode +{ +public: + QByteArray toByteArray() const { return QByteArray(); } // TODO: How to encode this? +}; + +class VOffsetNode : public ParseTreeNode +{ +public: + QByteArray toByteArray() const { return QByteArray(); } // TODO: How to encode this? +}; + +class ClassEnumTypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class DiscriminatorNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class CtorDtorNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool m_isDestructor; + QByteArray m_representation; +}; + +class CvQualifiersNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool m_hasVolatile; + bool m_hasConst; +}; + +class EncodingNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class ExpressionNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + enum Type { + ConversionType, SizeofType, AlignofType, OperatorType, OtherType, ParameterPackSizeType + } m_type; +}; + +class OperatorNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + enum Type { + NewType, ArrayNewType, DeleteType, ArrayDeleteType, UnaryPlusType, UnaryMinusType, + UnaryAmpersandType, UnaryStarType, BitwiseNotType, BinaryPlusType, BinaryMinusType, + MultType, DivType, ModuloType, BitwiseAndType, BitwiseOrType, XorType, AssignType, + IncrementAndAssignType, DecrementAndAssignType, MultAndAssignType, DivAndAssignType, + ModuloAndAssignType, BitwiseAndAndAssignType, BitwiseOrAndAssignType, XorAndAssignType, + LeftShiftType, RightShiftType, LeftShiftAndAssignType, RightShiftAndAssignType, EqualsType, + NotEqualsType, LessType, GreaterType, LessEqualType, GreaterEqualType, LogicalNotType, + LogicalAndType, LogicalOrType, IncrementType, DecrementType, CommaType, ArrowStarType, + ArrowType, CallType, IndexType, TernaryType, SizeofTypeType, SizeofExprType, + AlignofTypeType, AlignofExprType, CastType, VendorType + } m_type; + +}; + +class ExprPrimaryNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class FunctionTypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool m_isExternC; +}; + +class LocalNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool m_isStringLiteral; +}; + +class MangledNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class NumberNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c, int base = 10); + + QByteArray toByteArray() const; + + bool m_isNegative; +}; + +class SourceNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const { return m_name; } + + QByteArray m_name; +}; + +class UnqualifiedNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool isConstructorOrDestructorOrConversionOperator() const; +}; + +class UnscopedNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool isConstructorOrDestructorOrConversionOperator() const; + + bool m_inStdNamespace; +}; + +class NestedNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool isTemplate() const; + bool isConstructorOrDestructorOrConversionOperator() const; +}; + +class SubstitutionNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + enum Type { + ActualSubstitutionType, StdType, StdAllocType, StdBasicStringType, FullStdBasicStringType, + StdBasicIStreamType, StdBasicOStreamType, StdBasicIoStreamType + } m_type; + QByteArray m_substValue; +}; + +class PointerToMemberTypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class TemplateParamNode : public ParseTreeNode +{ +public: + ~TemplateParamNode(); + + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class TemplateArgsNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; +}; + +class SpecialNameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + enum Type { + VirtualTableType, VttStructType, TypeInfoType, TypeInfoNameType, GuardVarType, + SingleCallOffsetType, DoubleCallOffsetType + } m_type; +}; + +class NonNegativeNumberNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c, int base = 10); + + QByteArray toByteArray() const; + + quint64 m_number; +}; + +class NameNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool isTemplate() const; + bool isConstructorOrDestructorOrConversionOperator() const; +}; + +class TemplateArgNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool m_isTemplateArgumentPack; +}; + +class Prefix2Node : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool isTemplate() const; + bool isConstructorOrDestructorOrConversionOperator() const; +}; + +class PrefixNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + bool isTemplate() const; + bool isConstructorOrDestructorOrConversionOperator() const; +}; + +class TypeNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + QByteArray toByteArrayQualPointerRef(const TypeNode *typeNode, + const QByteArray &qualPtrRef) const; + QByteArray qualPtrRefListToByteArray(const QList &nodeList) const; + + enum Type { + QualifiedType, PointerType, ReferenceType, RValueType, VendorType, PackExpansionType, + DeclType, OtherType + } m_type; +}; + +class FloatValueNode : public ParseTreeNode +{ +public: + static bool mangledRepresentationStartsWith(char c); + + QByteArray toByteArray() const; + + double m_value; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // PARSETREENODES_H diff --git a/tests/auto/debugger/namedemangler.pro b/tests/auto/debugger/namedemangler.pro index 8f8d0000980..663743b3af1 100644 --- a/tests/auto/debugger/namedemangler.pro +++ b/tests/auto/debugger/namedemangler.pro @@ -1,7 +1,15 @@ include(../qttest.pri) +APPSOURCEDIR = $$CREATORSOURCEDIR/src/plugins/qt4projectmanager/wizards +LIBS *= -L$$IDE_LIBRARY_PATH -lUtils + DEBUGGERDIR = $$IDE_SOURCE_TREE/src/plugins/debugger INCLUDEPATH += $$DEBUGGERDIR -HEADERS += $$DEBUGGERDIR/name_demangler.h -SOURCES += tst_namedemangler.cpp $$DEBUGGERDIR/name_demangler.cpp +HEADERS += \ + $$DEBUGGERDIR/namedemangler/namedemangler.h \ + $$DEBUGGERDIR/namedemangler/parsetreenodes.h +SOURCES += \ + tst_namedemangler.cpp \ + $$DEBUGGERDIR/namedemangler/namedemangler.cpp \ + $$DEBUGGERDIR/namedemangler/parsetreenodes.cpp diff --git a/tests/auto/debugger/tst_namedemangler.cpp b/tests/auto/debugger/tst_namedemangler.cpp index 3c93050d705..0516df52d6e 100644 --- a/tests/auto/debugger/tst_namedemangler.cpp +++ b/tests/auto/debugger/tst_namedemangler.cpp @@ -29,11 +29,18 @@ ** Nokia at qt-info@nokia.com. ** **************************************************************************/ -#include +#include +#include #include #include +#define TEST_CORRECTLY_MANGLED_NAME(mangled, expectedDemangled) \ + do { \ + QVERIFY2(demangler.demangle(mangled), qPrintable(demangler.errorString())); \ + QCOMPARE(demangler.demangledName(), QLatin1String(expectedDemangled)); \ + } while (0) + using namespace Debugger::Internal; class NameDemanglerAutoTest : public QObject @@ -41,12 +48,11 @@ class NameDemanglerAutoTest : public QObject Q_OBJECT private slots: void testUnmangledName(); - void testCorrectlyMangledNames(); + void testDisjunctFirstSets(); + void TEST_CORRECTLY_MANGLED_NAMEs(); void testIncorrectlyMangledNames(); private: - void testCorrectlyMangledName(const QString &mangledName, - const QString &demangledName); void testIncorrectlyMangledName(const QString &mangledName); NameDemangler demangler; }; @@ -56,131 +62,365 @@ void NameDemanglerAutoTest::testUnmangledName() QVERIFY(demangler.demangle("f") && demangler.demangledName() == "f"); } -void NameDemanglerAutoTest::testCorrectlyMangledNames() +void NameDemanglerAutoTest::TEST_CORRECTLY_MANGLED_NAMEs() { - testCorrectlyMangledName("_Z1fv", "f()"); - testCorrectlyMangledName("_Z1fi", "f(int)"); - testCorrectlyMangledName("_Z3foo3bar", "foo(bar)"); - testCorrectlyMangledName("_Zrm1XS_", "operator%(X, X)"); - testCorrectlyMangledName("_ZplR1XS0_", "operator+(X &, X &)"); - testCorrectlyMangledName("_ZlsRK1XS1_", "operator<<(X const &, X const &)"); - testCorrectlyMangledName("_ZN3FooIA4_iE3barE", "Foo::bar"); - testCorrectlyMangledName("_Z1fIiEvi", "void f(int)"); - testCorrectlyMangledName("_Z5firstI3DuoEvS0_", "void first(Duo)"); - testCorrectlyMangledName("_Z5firstI3DuoEvT_", "void first(Duo)"); - testCorrectlyMangledName("_Z3fooIiPFidEiEvv", + TEST_CORRECTLY_MANGLED_NAME("_Z1fv", "f()"); + TEST_CORRECTLY_MANGLED_NAME("_Z1fi", "f(int)"); + TEST_CORRECTLY_MANGLED_NAME("_Z3foo3bar", "foo(bar)"); + TEST_CORRECTLY_MANGLED_NAME("_Zrm1XS_", "operator%(X, X)"); + TEST_CORRECTLY_MANGLED_NAME("_ZplR1XS0_", "operator+(X &, X &)"); + TEST_CORRECTLY_MANGLED_NAME("_ZlsRK1XS1_", "operator<<(X const &, X const &)"); + TEST_CORRECTLY_MANGLED_NAME("_ZN3FooIA4_iE3barE", "Foo::bar"); + TEST_CORRECTLY_MANGLED_NAME("_Z1fIiEvi", "void f(int)"); + TEST_CORRECTLY_MANGLED_NAME("_Z5firstI3DuoEvS0_", "void first(Duo)"); + TEST_CORRECTLY_MANGLED_NAME("_Z5firstI3DuoEvT_", "void first(Duo)"); + TEST_CORRECTLY_MANGLED_NAME("_Z3fooIiPFidEiEvv", "void foo()"); - testCorrectlyMangledName("_ZN1N1fE", "N::f"); - testCorrectlyMangledName("_ZN6System5Sound4beepEv", + TEST_CORRECTLY_MANGLED_NAME("_ZN1N1fE", "N::f"); + TEST_CORRECTLY_MANGLED_NAME("_ZN6System5Sound4beepEv", "System::Sound::beep()"); - testCorrectlyMangledName("_ZN5Arena5levelE", "Arena::level"); - testCorrectlyMangledName("_ZN5StackIiiE5levelE", "Stack::level"); - testCorrectlyMangledName("_Z1fI1XEvPVN1AIT_E1TE", + TEST_CORRECTLY_MANGLED_NAME("_ZN5Arena5levelE", "Arena::level"); + TEST_CORRECTLY_MANGLED_NAME("_ZN5StackIiiE5levelE", "Stack::level"); + TEST_CORRECTLY_MANGLED_NAME("_Z1fI1XEvPVN1AIT_E1TE", "void f(A::T volatile *)"); - testCorrectlyMangledName("_ZngILi42EEvN1AIXplT_Li2EEE1TE", + TEST_CORRECTLY_MANGLED_NAME("_ZngILi42EEvN1AIXplT_Li2EEE1TE", "void operator-<42>(A<42 + 2>::T)"); - testCorrectlyMangledName("_Z4makeI7FactoryiET_IT0_Ev", + TEST_CORRECTLY_MANGLED_NAME("_Z4makeI7FactoryiET_IT0_Ev", "Factory make()"); - testCorrectlyMangledName("_Z3foo5Hello5WorldS0_S_", + TEST_CORRECTLY_MANGLED_NAME("_Z3foo5Hello5WorldS0_S_", "foo(Hello, World, World, Hello)"); - testCorrectlyMangledName("_Z3fooPM2ABi", "foo(int AB::**)"); - testCorrectlyMangledName("_ZlsRSoRKSs", + TEST_CORRECTLY_MANGLED_NAME("_Z3fooPM2ABi", "foo(int AB::**)"); + TEST_CORRECTLY_MANGLED_NAME("_ZlsRSoRKSs", "operator<<(std::basic_ostream > &, " "std::basic_string, " "std::allocator > const &)"); - testCorrectlyMangledName("_ZTI7a_class", "typeid(a_class)"); - testCorrectlyMangledName("_ZZN1A3fooEiE1B", "A::foo(int)::B"); - testCorrectlyMangledName("_ZZ3foovEN1C1DE", "foo()::C::D"); - testCorrectlyMangledName("_ZZZ3foovEN1C3barEvEN1E3bazEv", + TEST_CORRECTLY_MANGLED_NAME("_ZTI7a_class", "typeid(a_class)"); + TEST_CORRECTLY_MANGLED_NAME("_ZZN1A3fooEiE1B", "A::foo(int)::B"); + TEST_CORRECTLY_MANGLED_NAME("_ZZ3foovEN1C1DE", "foo()::C::D"); + TEST_CORRECTLY_MANGLED_NAME("_ZZZ3foovEN1C3barEvEN1E3bazEv", "foo()::C::bar()::E::baz()"); - testCorrectlyMangledName("_ZZN1N1fEiE1p", "N::f(int)::p"); - testCorrectlyMangledName("_ZZN1N1fEiEs", "N::f(int)::\"string literal\""); - testCorrectlyMangledName("_Z3fooc", "foo(char)"); - testCorrectlyMangledName("_Z2CBIL_Z3foocEE", "CB"); - testCorrectlyMangledName("_Z2CBIL_Z7IsEmptyEE", "CB"); - testCorrectlyMangledName("_ZN1N1TIiiE2mfES0_IddE", + TEST_CORRECTLY_MANGLED_NAME("_ZZN1N1fEiE1p", "N::f(int)::p"); + TEST_CORRECTLY_MANGLED_NAME("_ZZN1N1fEiEs", "N::f(int)::[string literal]"); + TEST_CORRECTLY_MANGLED_NAME("_Z3fooc", "foo(char)"); + TEST_CORRECTLY_MANGLED_NAME("_Z2CBIL_Z3foocEE", "CB"); + TEST_CORRECTLY_MANGLED_NAME("_Z2CBIL_Z7IsEmptyEE", "CB"); + TEST_CORRECTLY_MANGLED_NAME("_ZN1N1TIiiE2mfES0_IddE", "N::T::mf(N::T)"); - testCorrectlyMangledName("_ZSt5state", "std::state"); - testCorrectlyMangledName("_ZNSt3_In4wardE", "std::_In::ward"); - testCorrectlyMangledName("_Z41__static_initialization_and_destruction_0ii", + TEST_CORRECTLY_MANGLED_NAME("_ZSt5state", "std::state"); + TEST_CORRECTLY_MANGLED_NAME("_ZNSt3_In4wardE", "std::_In::ward"); + TEST_CORRECTLY_MANGLED_NAME("_Z41__static_initialization_and_destruction_0ii", "__static_initialization_and_destruction_0(int, int)"); - testCorrectlyMangledName("_ZN20NameDemanglerPrivate3eoiE", + TEST_CORRECTLY_MANGLED_NAME("_ZN20NameDemanglerPrivate3eoiE", "NameDemanglerPrivate::eoi"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZZN20NameDemanglerPrivate15parseIdentifierEiE8__func__", "NameDemanglerPrivate::parseIdentifier(int)::__func__"); - testCorrectlyMangledName("_ZN4QSetI5QCharED1Ev", "QSet::~QSet()"); - testCorrectlyMangledName("_Zne5QCharS_", "operator!=(QChar, QChar)"); - testCorrectlyMangledName("_ZN20NameDemanglerPrivate17parseFunctionTypeEv", + TEST_CORRECTLY_MANGLED_NAME("_ZN4QSetI5QCharED1Ev", "QSet::~QSet()"); + TEST_CORRECTLY_MANGLED_NAME("_Zne5QCharS_", "operator!=(QChar, QChar)"); + TEST_CORRECTLY_MANGLED_NAME("_ZN20NameDemanglerPrivate17parseFunctionTypeEv", "NameDemanglerPrivate::parseFunctionType()"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZNK20NameDemanglerPrivate16ArrayNewOperator8makeExprERK11QStringList", "NameDemanglerPrivate::ArrayNewOperator::makeExpr(QStringList const &) const"); - testCorrectlyMangledName("_ZN13QLatin1StringC1EPKc", + TEST_CORRECTLY_MANGLED_NAME("_ZN13QLatin1StringC1EPKc", "QLatin1String::QLatin1String(char const *)"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZN15QtSharedPointer16ExternalRefCountIN20NameDemanglerPrivate8OperatorEE12internalCopyIS2_EEvRKNS0_IT_EE", "void QtSharedPointer::ExternalRefCount::internalCopy(QtSharedPointer::ExternalRefCount const &)"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZN15QtSharedPointer16ExternalRefCountIN20NameDemanglerPrivate8OperatorEE11internalSetEPNS_20ExternalRefCountDataEPS2_", "QtSharedPointer::ExternalRefCount::internalSet(QtSharedPointer::ExternalRefCountData *, NameDemanglerPrivate::Operator *)"); - testCorrectlyMangledName("_ZN20NameDemanglerPrivate17parseUnscopedNameEv", + TEST_CORRECTLY_MANGLED_NAME("_ZN20NameDemanglerPrivate17parseUnscopedNameEv", "NameDemanglerPrivate::parseUnscopedName()"); - testCorrectlyMangledName("_ZNK7QString3argExiiRK5QChar", + TEST_CORRECTLY_MANGLED_NAME("_ZNK7QString3argExiiRK5QChar", "QString::arg(long long, int, int, QChar const &) const"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZN20NameDemanglerPrivate8OperatorC2ERK7QStringS3_", "NameDemanglerPrivate::Operator::Operator(QString const &, QString const &)"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZN15QtSharedPointer16ExternalRefCountIN20NameDemanglerPrivate8OperatorEEC2EN2Qt14InitializationE", "QtSharedPointer::ExternalRefCount::ExternalRefCount(Qt::Initialization)"); - testCorrectlyMangledName("_ZN7QString5clearEv", "QString::clear()"); - testCorrectlyMangledName("_ZNK5QListI7QStringE2atEi", + TEST_CORRECTLY_MANGLED_NAME("_ZN7QString5clearEv", "QString::clear()"); + TEST_CORRECTLY_MANGLED_NAME("_ZNK5QListI7QStringE2atEi", "QList::at(int) const"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZNK7QString10startsWithERKS_N2Qt15CaseSensitivityE", "QString::startsWith(QString const &, Qt::CaseSensitivity) const"); - testCorrectlyMangledName("_ZNK4QSetI5QCharE8constEndEv", + TEST_CORRECTLY_MANGLED_NAME("_ZNK4QSetI5QCharE8constEndEv", "QSet::constEnd() const"); - testCorrectlyMangledName("_Z11qt_assert_xPKcS0_S0_i", + TEST_CORRECTLY_MANGLED_NAME("_Z11qt_assert_xPKcS0_S0_i", "qt_assert_x(char const *, char const *, char const *, int)"); - testCorrectlyMangledName("_ZN9QHashData8willGrowEv", + TEST_CORRECTLY_MANGLED_NAME("_ZN9QHashData8willGrowEv", "QHashData::willGrow()"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZNK5QHashI5QChar15QHashDummyValueE14const_iteratorneERKS3_", "QHash::const_iterator::operator!=(QHash::const_iterator const &) const"); - testCorrectlyMangledName("_ZNK13NameDemangler11errorStringEv", + TEST_CORRECTLY_MANGLED_NAME("_ZNK13NameDemangler11errorStringEv", "NameDemangler::errorString() const"); - testCorrectlyMangledName("_ZN7QString7replaceERK7QRegExpRKS_", + TEST_CORRECTLY_MANGLED_NAME("_ZN7QString7replaceERK7QRegExpRKS_", "QString::replace(QRegExp const &, QString const &)"); - testCorrectlyMangledName("_ZN7QString4freeEPNS_4DataE", + TEST_CORRECTLY_MANGLED_NAME("_ZN7QString4freeEPNS_4DataE", "QString::free(QString::Data *)"); - testCorrectlyMangledName( + TEST_CORRECTLY_MANGLED_NAME( "_ZTSN20NameDemanglerPrivate19ArrayAccessOperatorE", "typeid(NameDemanglerPrivate::ArrayAccessOperator).name()"); - testCorrectlyMangledName("_ZN3ns11fERKPFPKiS1_RKhE", + TEST_CORRECTLY_MANGLED_NAME("_ZN3ns11fERKPFPKiS1_RKhE", "ns1::f(int const * (* const &)(int const *, unsigned char const &))"); - testCorrectlyMangledName("_Z9test_funcMN3ns11cImEEKFPKvPiRlmE", - "test_func(void const * (ns1::c::*)(int *, long &, unsigned long) const)"); - testCorrectlyMangledName("_ZN3ns11fEPKPFPKiS1_RKhE", + TEST_CORRECTLY_MANGLED_NAME("_Z9test_funcMN3ns11cImEEKFPKvPiRlmE", + "test_func(void const * (ns1::c::*)(int *, long &, unsigned long) const)"); + TEST_CORRECTLY_MANGLED_NAME("_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 *() const"); + TEST_CORRECTLY_MANGLED_NAME("_ZNK1CcviEv", "C::operator int() const"); + TEST_CORRECTLY_MANGLED_NAME("_ZN1CppEv", "C::operator++()"); + TEST_CORRECTLY_MANGLED_NAME("_ZN1CmmEv", "C::operator--()"); + TEST_CORRECTLY_MANGLED_NAME("_ZN1CppEi", "C::operator++(int)"); + TEST_CORRECTLY_MANGLED_NAME("_ZN1CmmEi", "C::operator--(int)"); + TEST_CORRECTLY_MANGLED_NAME("_ZNK1CcvT_IPKcEEv", "C::operator char const *() const"); } void NameDemanglerAutoTest::testIncorrectlyMangledNames() { } -void NameDemanglerAutoTest::testCorrectlyMangledName( - const QString &mangledName, const QString &demangledName) +void NameDemanglerAutoTest::testDisjunctFirstSets() { - demangler.demangle(mangledName); - QCOMPARE(demangler.demangledName(), demangledName); + for (char c = 0x20; c < 0x7e; ++c) { + + // + QVERIFY(!NameNode::mangledRepresentationStartsWith(c) + || !SpecialNameNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!NestedNameNode::mangledRepresentationStartsWith(c) + || !UnscopedNameNode::mangledRepresentationStartsWith(c)); + QVERIFY(!NestedNameNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!NestedNameNode::mangledRepresentationStartsWith(c) + || !LocalNameNode::mangledRepresentationStartsWith(c)); + QVERIFY(!UnscopedNameNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c) || c == 'S'); + QVERIFY(!UnscopedNameNode::mangledRepresentationStartsWith(c) + || !LocalNameNode::mangledRepresentationStartsWith(c)); + QVERIFY(!SubstitutionNode::mangledRepresentationStartsWith(c) + || !LocalNameNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!CvQualifiersNode::mangledRepresentationStartsWith(c) + || !PrefixNode::mangledRepresentationStartsWith(c) || c == 'r'); + + // + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!TemplateArgsNode::mangledRepresentationStartsWith(c) + || !Prefix2Node::mangledRepresentationStartsWith(c)); + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith(c) + || !Prefix2Node::mangledRepresentationStartsWith(c)); + QVERIFY(!SubstitutionNode::mangledRepresentationStartsWith(c) + || !Prefix2Node::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!TemplateArgsNode::mangledRepresentationStartsWith(c) + || !Prefix2Node::mangledRepresentationStartsWith(c)); + + + // + QVERIFY(!TypeNode::mangledRepresentationStartsWith(c) + || !ExprPrimaryNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!OperatorNameNode::mangledRepresentationStartsWith(c) + || !TemplateParamNode::mangledRepresentationStartsWith(c)); +// QVERIFY(!OperatorNameNode::mangledRepresentationStartsWith(c) +// || !FunctionParamNode::mangledRepresentationStartsWith(c)) + QVERIFY(!OperatorNameNode::mangledRepresentationStartsWith(c) + || !ExprPrimaryNode::mangledRepresentationStartsWith(c)); +// QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith(c) +// || !FunctionParamNode::mangledRepresentationStartsWith(c)); + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith(c) + || !ExprPrimaryNode::mangledRepresentationStartsWith(c)); +// QVERIFY(!FunctionParamNode::mangledRepresentationStartsWith(c) +// || !ExprPrimaryNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!TypeNode::mangledRepresentationStartsWith(c) + || !MangledNameNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !FunctionTypeNode::mangledRepresentationStartsWith(c)); + + QVERIFY2(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !ClassEnumTypeNode::mangledRepresentationStartsWith(c) || c == 'D', &c); + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !ArrayTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !PointerToMemberTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !TemplateParamNode::mangledRepresentationStartsWith(c)); + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith(c) + || !ClassEnumTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith(c) + || !ArrayTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith(c) + || !PointerToMemberTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith(c) + || !TemplateParamNode::mangledRepresentationStartsWith(c)); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ClassEnumTypeNode::mangledRepresentationStartsWith(c) + || !ArrayTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ClassEnumTypeNode::mangledRepresentationStartsWith(c) + || !PointerToMemberTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ClassEnumTypeNode::mangledRepresentationStartsWith(c) + || !TemplateParamNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ClassEnumTypeNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ClassEnumTypeNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ArrayTypeNode::mangledRepresentationStartsWith(c) + || !PointerToMemberTypeNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ArrayTypeNode::mangledRepresentationStartsWith(c) + || !TemplateParamNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ArrayTypeNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!ArrayTypeNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + QVERIFY(!PointerToMemberTypeNode::mangledRepresentationStartsWith(c) + || !TemplateParamNode::mangledRepresentationStartsWith(c)); + QVERIFY(!PointerToMemberTypeNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!PointerToMemberTypeNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith(c) + || !SubstitutionNode::mangledRepresentationStartsWith(c)); + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + QVERIFY(!SubstitutionNode::mangledRepresentationStartsWith(c) + || !CvQualifiersNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!OperatorNameNode::mangledRepresentationStartsWith(c) + || !CtorDtorNameNode::mangledRepresentationStartsWith(c)); + QVERIFY(!OperatorNameNode::mangledRepresentationStartsWith(c) + || !SourceNameNode::mangledRepresentationStartsWith(c)); + QVERIFY(!CtorDtorNameNode::mangledRepresentationStartsWith(c) + || !SourceNameNode::mangledRepresentationStartsWith(c)); + + // + QVERIFY(!NonNegativeNumberNode::mangledRepresentationStartsWith(c) + || !ExpressionNode::mangledRepresentationStartsWith(c)); + } + + // , + QVERIFY(!TemplateArgNode::mangledRepresentationStartsWith('E')); + + // + QVERIFY(!TypeNode::mangledRepresentationStartsWith('X') + && !TypeNode::mangledRepresentationStartsWith('J') + /* && !TypeNode::mangledRepresentationStartsWith('s') */); + QVERIFY(!ExprPrimaryNode::mangledRepresentationStartsWith('X') + && !ExprPrimaryNode::mangledRepresentationStartsWith('J') + && !ExprPrimaryNode::mangledRepresentationStartsWith('s')); + + // + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith('c') + && !TemplateParamNode::mangledRepresentationStartsWith('s') + && !TemplateParamNode::mangledRepresentationStartsWith('a')); +// QVERIFY(!FunctionParamNode::mangledRepresentationStartsWith('c') +// && !FunctionParamNode::mangledRepresentationStartsWith('c') +// && !FunctionParamNode::mangledRepresentationStartsWith('c')); + QVERIFY(!ExprPrimaryNode::mangledRepresentationStartsWith('c') + && !ExprPrimaryNode::mangledRepresentationStartsWith('s') + && !ExprPrimaryNode::mangledRepresentationStartsWith('a')); + QVERIFY(!ExpressionNode::mangledRepresentationStartsWith('E')); + QVERIFY(!ExpressionNode::mangledRepresentationStartsWith('_')); + + // + QVERIFY(!BuiltinTypeNode::mangledRepresentationStartsWith('P') + && !BuiltinTypeNode::mangledRepresentationStartsWith('R') + && !BuiltinTypeNode::mangledRepresentationStartsWith('O') + && !BuiltinTypeNode::mangledRepresentationStartsWith('C') + && !BuiltinTypeNode::mangledRepresentationStartsWith('G') + && !BuiltinTypeNode::mangledRepresentationStartsWith('U')); + QVERIFY(!FunctionTypeNode::mangledRepresentationStartsWith('P') + && !FunctionTypeNode::mangledRepresentationStartsWith('R') + && !FunctionTypeNode::mangledRepresentationStartsWith('O') + && !FunctionTypeNode::mangledRepresentationStartsWith('C') + && !FunctionTypeNode::mangledRepresentationStartsWith('G') + && !FunctionTypeNode::mangledRepresentationStartsWith('U') + && !FunctionTypeNode::mangledRepresentationStartsWith('D')); + QVERIFY(!ClassEnumTypeNode::mangledRepresentationStartsWith('P') + && !ClassEnumTypeNode::mangledRepresentationStartsWith('R') + && !ClassEnumTypeNode::mangledRepresentationStartsWith('O') + && !ClassEnumTypeNode::mangledRepresentationStartsWith('C') + && !ClassEnumTypeNode::mangledRepresentationStartsWith('G') + && !ClassEnumTypeNode::mangledRepresentationStartsWith('U') + /* && !firstSetClassEnumType.contains('D') */); + QVERIFY(!ArrayTypeNode::mangledRepresentationStartsWith('P') + && !ArrayTypeNode::mangledRepresentationStartsWith('R') + && !ArrayTypeNode::mangledRepresentationStartsWith('O') + && !ArrayTypeNode::mangledRepresentationStartsWith('C') + && !ArrayTypeNode::mangledRepresentationStartsWith('G') + && !ArrayTypeNode::mangledRepresentationStartsWith('U') + && !ArrayTypeNode::mangledRepresentationStartsWith('D')); + QVERIFY(!PointerToMemberTypeNode::mangledRepresentationStartsWith('P') + && !PointerToMemberTypeNode::mangledRepresentationStartsWith('R') + && !PointerToMemberTypeNode::mangledRepresentationStartsWith('O') + && !PointerToMemberTypeNode::mangledRepresentationStartsWith('C') + && !PointerToMemberTypeNode::mangledRepresentationStartsWith('G') + && !PointerToMemberTypeNode::mangledRepresentationStartsWith('U') + && !PointerToMemberTypeNode::mangledRepresentationStartsWith('D')); + QVERIFY(!TemplateParamNode::mangledRepresentationStartsWith('P') + && !TemplateParamNode::mangledRepresentationStartsWith('R') + && !TemplateParamNode::mangledRepresentationStartsWith('O') + && !TemplateParamNode::mangledRepresentationStartsWith('C') + && !TemplateParamNode::mangledRepresentationStartsWith('G') + && !TemplateParamNode::mangledRepresentationStartsWith('U') + && !TemplateParamNode::mangledRepresentationStartsWith('D')); + QVERIFY(!SubstitutionNode::mangledRepresentationStartsWith('P') + && !SubstitutionNode::mangledRepresentationStartsWith('R') + && !SubstitutionNode::mangledRepresentationStartsWith('O') + && !SubstitutionNode::mangledRepresentationStartsWith('C') + && !SubstitutionNode::mangledRepresentationStartsWith('G') + && !SubstitutionNode::mangledRepresentationStartsWith('U') + && !SubstitutionNode::mangledRepresentationStartsWith('D')); + QVERIFY(!CvQualifiersNode::mangledRepresentationStartsWith('P') + && !CvQualifiersNode::mangledRepresentationStartsWith('R') + && !CvQualifiersNode::mangledRepresentationStartsWith('O') + && !CvQualifiersNode::mangledRepresentationStartsWith('C') + && !CvQualifiersNode::mangledRepresentationStartsWith('G') + && !CvQualifiersNode::mangledRepresentationStartsWith('U') + && !CvQualifiersNode::mangledRepresentationStartsWith('D')); + + // + QVERIFY(!NonNegativeNumberNode::mangledRepresentationStartsWith('_')); + QVERIFY(!ExpressionNode::mangledRepresentationStartsWith('_')); + + // + QVERIFY(!NonNegativeNumberNode::mangledRepresentationStartsWith('_', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('t', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('a', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('b', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('s', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('i', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('o', 36) + && !NonNegativeNumberNode::mangledRepresentationStartsWith('d', 36)); + + // + QVERIFY(!CallOffsetNode::mangledRepresentationStartsWith('V') + && !CallOffsetNode::mangledRepresentationStartsWith('T') + && !CallOffsetNode::mangledRepresentationStartsWith('I') + && !CallOffsetNode::mangledRepresentationStartsWith('S') + && !CallOffsetNode::mangledRepresentationStartsWith('c')); + + // + QVERIFY(!UnqualifiedNameNode::mangledRepresentationStartsWith('S')); } void NameDemanglerAutoTest::testIncorrectlyMangledName(