diff options
author | hjk <[email protected]> | 2014-01-08 14:10:56 +0100 |
---|---|---|
committer | hjk <[email protected]> | 2014-01-08 14:49:35 +0100 |
commit | df2ecb4edd792efd10592c71a9d157d518cd9eea (patch) | |
tree | 8bd829e3f27f352e9d177b69ce5ef4bbdb1e4741 /src/plugins/debugger/debuggerprotocol.cpp | |
parent | 11264ef6b9123b313c30a8da225de4b6a90871e6 (diff) |
Move the textual simplification of container type to debugger again
This is the only user, and likely will stay so for a while, and
eases the linking of the debugger autotests.
Change-Id: I822fa892f105a5b7985370b26e50aa94cac74bb3
Reviewed-by: Nikolai Kosjar <[email protected]>
Diffstat (limited to 'src/plugins/debugger/debuggerprotocol.cpp')
-rw-r--r-- | src/plugins/debugger/debuggerprotocol.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index 5e5ab738214..5423c81f036 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -33,12 +33,18 @@ #include <QDateTime> #include <QDebug> #include <QHostAddress> +#include <QRegExp> #if QT_VERSION >= 0x050200 #include <QTimeZone> #endif #include <ctype.h> +#define QTC_ASSERT_STRINGIFY_HELPER(x) #x +#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x) +#define QTC_ASSERT_STRING(cond) qDebug("SOFT ASSERT: \"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__)) +#define QTC_ASSERT(cond, action) if (cond) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0) + namespace Debugger { namespace Internal { @@ -723,5 +729,221 @@ QString decodeData(const QByteArray &ba, int encoding) return QCoreApplication::translate("Debugger", "<Encoding error>"); } +// Simplify complicated STL template types, +// such as 'std::basic_string<char,std::char_traits<char>,std::allocator<char> >' +// -> 'std::string' and helpers. + +static QString chopConst(QString type) +{ + while (1) { + if (type.startsWith(QLatin1String("const"))) + type = type.mid(5); + else if (type.startsWith(QLatin1Char(' '))) + type = type.mid(1); + else if (type.endsWith(QLatin1String("const"))) + type.chop(5); + else if (type.endsWith(QLatin1Char(' '))) + type.chop(1); + else + break; + } + return type; +} + +static inline QRegExp stdStringRegExp(const QString &charType) +{ + QString rc = QLatin1String("basic_string<"); + rc += charType; + rc += QLatin1String(",[ ]?std::char_traits<"); + rc += charType; + rc += QLatin1String(">,[ ]?std::allocator<"); + rc += charType; + rc += QLatin1String("> >"); + const QRegExp re(rc); + QTC_ASSERT(re.isValid(), /**/); + return re; +} + +// Simplify string types in a type +// 'std::set<std::basic_string<char... > >' -> std::set<std::string>' +static inline void simplifyStdString(const QString &charType, const QString &replacement, + QString *type) +{ + QRegExp stringRegexp = stdStringRegExp(charType); + const int replacementSize = replacement.size(); + for (int pos = 0; pos < type->size(); ) { + // Check next match + const int matchPos = stringRegexp.indexIn(*type, pos); + if (matchPos == -1) + break; + const int matchedLength = stringRegexp.matchedLength(); + type->replace(matchPos, matchedLength, replacement); + pos = matchPos + replacementSize; + // If we were inside an 'allocator<std::basic_string..char > >' + // kill the following blank -> 'allocator<std::string>' + if (pos + 1 < type->size() && type->at(pos) == QLatin1Char(' ') + && type->at(pos + 1) == QLatin1Char('>')) + type->remove(pos, 1); + } +} + +// Fix 'std::allocator<std::string >' -> 'std::allocator<std::string>', +// which can happen when replacing/simplifying +static inline QString fixNestedTemplates(QString s) +{ + const int size = s.size(); + if (size > 3 + && s.at(size - 1) == QLatin1Char('>') + && s.at(size - 2) == QLatin1Char(' ') + && s.at(size - 3) != QLatin1Char('>')) + s.remove(size - 2, 1); + return s; +} + +QString simplifySTLType(const QString &typeIn) +{ + QString type = typeIn; + if (type.startsWith(QLatin1String("class "))) // MSVC prepends class,struct + type.remove(0, 6); + if (type.startsWith(QLatin1String("struct "))) + type.remove(0, 7); + + type.replace(QLatin1String("std::__1::"), QLatin1String("std::")); + type.replace(QLatin1String("std::__debug::"), QLatin1String("std::")); + type.replace(QLatin1Char('*'), QLatin1Char('@')); + + for (int i = 0; i < 10; ++i) { + // std::ifstream + QRegExp ifstreamRE(QLatin1String("std::basic_ifstream<char,\\s*std::char_traits<char>\\s*>")); + ifstreamRE.setMinimal(true); + QTC_ASSERT(ifstreamRE.isValid(), return typeIn); + if (ifstreamRE.indexIn(type) != -1) + type.replace(ifstreamRE.cap(0), QLatin1String("std::ifstream")); + + // Anything with a std::allocator + int start = type.indexOf(QLatin1String("std::allocator<")); + if (start == -1) + break; + // search for matching '>' + int pos; + int level = 0; + for (pos = start + 12; pos < type.size(); ++pos) { + int c = type.at(pos).unicode(); + if (c == '<') { + ++level; + } else if (c == '>') { + --level; + if (level == 0) + break; + } + } + const QString alloc = fixNestedTemplates(type.mid(start, pos + 1 - start).trimmed()); + const QString inner = fixNestedTemplates(alloc.mid(15, alloc.size() - 16).trimmed()); + const QString allocEsc = QRegExp::escape(alloc); + const QString innerEsc = QRegExp::escape(inner); + if (inner == QLatin1String("char")) { // std::string + simplifyStdString(QLatin1String("char"), QLatin1String("string"), &type); + } else if (inner == QLatin1String("wchar_t")) { // std::wstring + simplifyStdString(QLatin1String("wchar_t"), QLatin1String("wstring"), &type); + } else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC + simplifyStdString(QLatin1String("unsigned short"), QLatin1String("wstring"), &type); + } + // std::vector, std::deque, std::list + QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1, ?%2\\s*>").arg(innerEsc, allocEsc)); + QTC_ASSERT(re1.isValid(), return typeIn); + if (re1.indexIn(type) != -1) + type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner)); + + // std::stack + QRegExp stackRE(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(innerEsc, innerEsc)); + stackRE.setMinimal(true); + QTC_ASSERT(stackRE.isValid(), return typeIn); + if (stackRE.indexIn(type) != -1) + type.replace(stackRE.cap(0), QString::fromLatin1("stack<%1>").arg(inner)); + + // std::set + QRegExp setRE(QString::fromLatin1("set<%1, ?std::less<%2>, ?%3\\s*>").arg(innerEsc, innerEsc, allocEsc)); + setRE.setMinimal(true); + QTC_ASSERT(setRE.isValid(), return typeIn); + if (setRE.indexIn(type) != -1) + type.replace(setRE.cap(0), QString::fromLatin1("set<%1>").arg(inner)); + + // std::unordered_set + QRegExp unorderedSetRE(QString::fromLatin1("unordered_set<%1, ?std::hash<%2>, ?std::equal_to<%3>, ?%4\\s*>") + .arg(innerEsc, innerEsc, innerEsc, allocEsc)); + unorderedSetRE.setMinimal(true); + QTC_ASSERT(unorderedSetRE.isValid(), return typeIn); + if (unorderedSetRE.indexIn(type) != -1) + type.replace(unorderedSetRE.cap(0), QString::fromLatin1("unordered_set<%1>").arg(inner)); + + // std::map + if (inner.startsWith(QLatin1String("std::pair<"))) { + // search for outermost ',', split key and value + int pos; + int level = 0; + for (pos = 10; pos < inner.size(); ++pos) { + int c = inner.at(pos).unicode(); + if (c == '<') + ++level; + else if (c == '>') + --level; + else if (c == ',' && level == 0) + break; + } + const QString key = chopConst(inner.mid(10, pos - 10)); + const QString keyEsc = QRegExp::escape(key); + // Get value: MSVC: 'pair<a const ,b>', gcc: 'pair<const a, b>' + if (inner.at(++pos) == QLatin1Char(' ')) + pos++; + const QString value = inner.mid(pos, inner.size() - pos - 1).trimmed(); + const QString valueEsc = QRegExp::escape(value); + QRegExp mapRE1(QString::fromLatin1("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*>") + .arg(keyEsc, valueEsc, keyEsc, allocEsc)); + mapRE1.setMinimal(true); + QTC_ASSERT(mapRE1.isValid(), return typeIn); + if (mapRE1.indexIn(type) != -1) { + type.replace(mapRE1.cap(0), QString::fromLatin1("map<%1, %2>").arg(key, value)); + } else { + QRegExp mapRE2(QString::fromLatin1("map<const %1, ?%2, ?std::less<const %3>, ?%4\\s*>") + .arg(keyEsc, valueEsc, keyEsc, allocEsc)); + mapRE2.setMinimal(true); + if (mapRE2.indexIn(type) != -1) + type.replace(mapRE2.cap(0), QString::fromLatin1("map<const %1, %2>").arg(key, value)); + } + } + + // std::unordered_map + if (inner.startsWith(QLatin1String("std::pair<"))) { + // search for outermost ',', split key and value + int pos; + int level = 0; + for (pos = 10; pos < inner.size(); ++pos) { + int c = inner.at(pos).unicode(); + if (c == '<') + ++level; + else if (c == '>') + --level; + else if (c == ',' && level == 0) + break; + } + const QString key = chopConst(inner.mid(10, pos - 10)); + const QString keyEsc = QRegExp::escape(key); + // Get value: MSVC: 'pair<a const ,b>', gcc: 'pair<const a, b>' + if (inner.at(++pos) == QLatin1Char(' ')) + pos++; + const QString value = inner.mid(pos, inner.size() - pos - 1).trimmed(); + const QString valueEsc = QRegExp::escape(value); + QRegExp mapRE1(QString::fromLatin1("unordered_map<%1, ?%2, ?std::hash<%3 ?>, ?std::equal_to<%4 ?>, ?%5\\s*>") + .arg(keyEsc, valueEsc, keyEsc, keyEsc, allocEsc)); + mapRE1.setMinimal(true); + QTC_ASSERT(mapRE1.isValid(), return typeIn); + if (mapRE1.indexIn(type) != -1) + type.replace(mapRE1.cap(0), QString::fromLatin1("unordered_map<%1, %2>").arg(key, value)); + } + } + type.replace(QLatin1Char('@'), QLatin1Char('*')); + type.replace(QLatin1String(" >"), QLatin1String(">")); + return type; +} } // namespace Internal } // namespace Debugger |