Commit 873ed718 authored by Christian Kandeler's avatar Christian Kandeler
Browse files

Name demangler: Fix some substitution bugs.



Also try to collapse references as much as it is possible with the
current design.

Change-Id: I1de55eac2d681a36f8b77d77968c4a06d19b6fac
Reviewed-by: default avatarChristian Kandeler <christian.kandeler@nokia.com>
parent b125f4f2
......@@ -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);
}
......
......@@ -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.")
......
......@@ -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;
}
......
......@@ -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");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment