aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/debugger/debuggerprotocol.cpp
diff options
context:
space:
mode:
authorhjk <[email protected]>2014-01-08 14:10:56 +0100
committerhjk <[email protected]>2014-01-08 14:49:35 +0100
commitdf2ecb4edd792efd10592c71a9d157d518cd9eea (patch)
tree8bd829e3f27f352e9d177b69ce5ef4bbdb1e4741 /src/plugins/debugger/debuggerprotocol.cpp
parent11264ef6b9123b313c30a8da225de4b6a90871e6 (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.cpp222
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