diff --git a/src/plugins/debugger/namedemangler/globalparsestate.cpp b/src/plugins/debugger/namedemangler/globalparsestate.cpp index f14cf6aae5b57be053531209f3ad1e47113ce27d..c9841a14719ad9e9425fecfdf07a85b4aaf50b01 100644 --- a/src/plugins/debugger/namedemangler/globalparsestate.cpp +++ b/src/plugins/debugger/namedemangler/globalparsestate.cpp @@ -71,7 +71,7 @@ void GlobalParseState::addSubstitution(const ParseTreeNode *node) void GlobalParseState::addSubstitution(const QByteArray &symbol) { - if (!symbol.isEmpty() && !m_substitutions.contains(symbol)) + if (!symbol.isEmpty()) m_substitutions.append(symbol); } diff --git a/src/plugins/debugger/namedemangler/namedemangler.cpp b/src/plugins/debugger/namedemangler/namedemangler.cpp index 3a4e7cb261f287d3fccdd014ab868d2e347d1086..2414b2f0ba413420c7012e4ce075b37a8410a412 100644 --- a/src/plugins/debugger/namedemangler/namedemangler.cpp +++ b/src/plugins/debugger/namedemangler/namedemangler.cpp @@ -73,6 +73,21 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName) "expected one.").arg(m_parseState.m_parseStack.count())); } m_demangledName = m_parseState.m_parseStack.top()->toByteArray(); + + /* + * FIXME: This is a hack we do because TypeNode::toByteArray() cannot catch all + * all nested reference due to the way substitutions are currently implented. + * Note that even with this hack, we do not catch things like + * "reference to reference to array", because the operators do not follow each other + * in the string. + * For a correct solution, we'll probably have to clone substitution nodes instead of + * just dumping their strings (which means adding a copy constructor and a clone function + * to every node). + */ + m_demangledName.replace("&& &&", "&&"); + m_demangledName.replace("&& &", "&"); + m_demangledName.replace(" & &", "&"); + success = true; } catch (const ParseException &p) { m_errorString = QString::fromLocal8Bit("Parse error at index %1 of mangled name '%2': %3.") diff --git a/src/plugins/debugger/namedemangler/parsetreenodes.cpp b/src/plugins/debugger/namedemangler/parsetreenodes.cpp index 92f88bfe0b1f364120349cf993a56a753af5cfdb..435c6b564af8980631b41dff108da05d87ba58d1 100644 --- a/src/plugins/debugger/namedemangler/parsetreenodes.cpp +++ b/src/plugins/debugger/namedemangler/parsetreenodes.cpp @@ -229,6 +229,7 @@ void BuiltinTypeNode::parse() if (next == 'u') { m_type = VendorType; PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceNameNode); + parseState()->addSubstitution(this); return; } @@ -1581,6 +1582,7 @@ bool SubstitutionNode::mangledRepresentationStartsWith(char c) * ::= Si # ::std::basic_istream<char, std::char_traits<char> > * ::= So # ::std::basic_ostream<char, std::char_traits<char> > * ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > + * ::= St <unqualified-name> # ::std:: */ void SubstitutionNode::parse() { @@ -1607,7 +1609,13 @@ void SubstitutionNode::parse() m_type = ActualSubstitutionType; m_substValue = parseState()->substitutionAt(0); break; - case 't': m_type = StdType; break; + case 't': + m_type = StdType; + if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedNameNode); + parseState()->addSubstitution(this); + } + break; case 'a': m_type = StdAllocType; break; case 'b': m_type = StdBasicStringType; break; case 's': m_type = FullStdBasicStringType; break; @@ -1623,7 +1631,12 @@ QByteArray SubstitutionNode::toByteArray() const { switch (m_type) { case ActualSubstitutionType: return m_substValue; - case StdType: return "std"; + case StdType: { + QByteArray repr = "std"; + if (childCount() > 0) + repr.append("::").append(CHILD_TO_BYTEARRAY(0)); + return repr; + } case StdAllocType: return "std::allocator"; case StdBasicStringType: return "std::basic_string"; case FullStdBasicStringType: return "std::basic_string<char, std::char_traits<char>, " @@ -2194,15 +2207,14 @@ void PrefixNode::parse() parseState()->addSubstitution(this); PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); } - if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) { + if (Prefix2Node::mangledRepresentationStartsWith(PEEK())) parseState()->addSubstitution(this); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node); - } + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node); } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode); if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); - if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) + if (Prefix2Node::mangledRepresentationStartsWith(PEEK())) parseState()->addSubstitution(this); } PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node); @@ -2210,7 +2222,7 @@ void PrefixNode::parse() PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode); if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); - if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) + if (Prefix2Node::mangledRepresentationStartsWith(PEEK())) parseState()->addSubstitution(this); } PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node); @@ -2289,8 +2301,10 @@ void TypeNode::parse() parseState()->addSubstitution(this); } else if (ArrayTypeNode::mangledRepresentationStartsWith(next)) { PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ArrayTypeNode); + parseState()->addSubstitution(this); } else if (PointerToMemberTypeNode::mangledRepresentationStartsWith(next)) { PARSE_RULE_AND_ADD_RESULT_AS_CHILD(PointerToMemberTypeNode); + parseState()->addSubstitution(this); } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParamNode); // The type is now a substitution candidate, but the child node may contain a forward @@ -2378,8 +2392,10 @@ QByteArray TypeNode::toByteArray() const QList<const ParseTreeNode *> qualPtrRefList; const TypeNode *currentNode = this; bool leafType = false; + Type lastType = TypeNode::OtherType; while (!leafType) { - switch (currentNode->m_type) { + Type currentType = currentNode->m_type; + switch (currentType) { case QualifiedType: { const CvQualifiersNode * const cvNode = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(currentNode, 0)); @@ -2389,13 +2405,32 @@ QByteArray TypeNode::toByteArray() const break; } case PointerType: case ReferenceType: case RValueType: - qualPtrRefList << currentNode; + /* + * The Standard says (8.3.2/6) that nested references collapse according + * to the following rules: + * (1) Reference to reference -> reference + * (2) Reference to rvalue -> reference + * (3) Rvalue to reference -> reference + * (4) Rvalue to Rvalue -> Rvalue + */ + if (currentType == ReferenceType + && (lastType == ReferenceType || lastType == RValueType)) { // (1) and (3) + qualPtrRefList.removeLast(); + qualPtrRefList << currentNode; + } else if (currentType == RValueType + && (lastType == ReferenceType || lastType == RValueType)) { // (2) and (4) + // Ignore current element. + currentType = lastType; + } else { + qualPtrRefList << currentNode; + } currentNode = DEMANGLER_CAST(TypeNode, CHILD_AT(currentNode, 0)); break; default: leafType = true; break; } + lastType = currentType; } if (qualPtrRefList.isEmpty()) { @@ -2471,6 +2506,7 @@ QByteArray TypeNode::qualPtrRefListToByteArray(const QList<const ParseTreeNode * repr.prepend(n->toByteArray()); } } + return repr; } diff --git a/tests/auto/debugger/tst_namedemangler.cpp b/tests/auto/debugger/tst_namedemangler.cpp index 01578704c791fce22dfb37bfe0934563573c84cf..5567f31c6daf77a0e09d6fb086e3bbc2b6c06033 100644 --- a/tests/auto/debugger/tst_namedemangler.cpp +++ b/tests/auto/debugger/tst_namedemangler.cpp @@ -174,6 +174,13 @@ void NameDemanglerAutoTest::testCorrectlyMangledNames() TEST_CORRECTLY_MANGLED_NAME("_Z9weirdfuncIiEvT_DtfL0p_E", "void weirdfunc<int>(int, decltype({param#1}))"); TEST_CORRECTLY_MANGLED_NAME("_Z9weirdfuncIiEvT_S0_S0_", "void weirdfunc<int>(int, int, int)"); TEST_CORRECTLY_MANGLED_NAME("_Z9weirdfuncIiEvT_S0_DtfL0p0_E", "void weirdfunc<int>(int, int, decltype({param#2}))"); + TEST_CORRECTLY_MANGLED_NAME("_Z8toStringIiESsT_", + "std::basic_string<char, std::char_traits<char>, std::allocator<char> > toString<int>(int)"); + + // TODO: The rvalue reference at the end has to actually collapse. Remove it once collapsing + // is properly implemented. + TEST_CORRECTLY_MANGLED_NAME("_ZSt9make_pairIiRA5_KcESt4pairINSt17__decay_and_stripIT_E6__typeENS4_IT0_E6__typeEEOS5_OS8_", + "std::pair<std::__decay_and_strip<int>::__type, std::__decay_and_strip<char const (&)[5]>::__type> std::make_pair<int, char const (&)[5]>(int &&, char const (&)[5] &&)"); // All examples from the ABI spec. TEST_CORRECTLY_MANGLED_NAME("_ZN1S1xE", "S::x");