forked from qt-creator/qt-creator
Debugger: Split type simplification into file of its own
This still needs to use a proper parser at some time. Change-Id: Ia0afe593dd9dc32f22f80adb7232c04f4db79cf6 Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -72,7 +72,8 @@ HEADERS += \
|
|||||||
debuggersourcepathmappingwidget.h \
|
debuggersourcepathmappingwidget.h \
|
||||||
memoryview.h \
|
memoryview.h \
|
||||||
localsandexpressionswindow.h \
|
localsandexpressionswindow.h \
|
||||||
imageviewer.h
|
imageviewer.h \
|
||||||
|
simplifytype.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
basewindow.cpp \
|
basewindow.cpp \
|
||||||
@@ -127,7 +128,8 @@ SOURCES += \
|
|||||||
debuggersourcepathmappingwidget.cpp \
|
debuggersourcepathmappingwidget.cpp \
|
||||||
memoryview.cpp \
|
memoryview.cpp \
|
||||||
localsandexpressionswindow.cpp \
|
localsandexpressionswindow.cpp \
|
||||||
imageviewer.cpp
|
imageviewer.cpp \
|
||||||
|
simplifytype.cpp
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
localsandexpressionsoptionspage.ui
|
localsandexpressionsoptionspage.ui
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ QtcPlugin {
|
|||||||
"watchhandler.cpp", "watchhandler.h",
|
"watchhandler.cpp", "watchhandler.h",
|
||||||
"watchutils.cpp", "watchutils.h",
|
"watchutils.cpp", "watchutils.h",
|
||||||
"watchwindow.cpp", "watchwindow.h",
|
"watchwindow.cpp", "watchwindow.h",
|
||||||
|
"simplifytype.cpp", "simplifytype.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -729,261 +729,5 @@ QString decodeData(const QByteArray &ba, int encoding)
|
|||||||
return QCoreApplication::translate("Debugger", "<Encoding error>");
|
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);
|
|
||||||
|
|
||||||
const bool isLibCpp = type.contains(QLatin1String("std::__1"));
|
|
||||||
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) {
|
|
||||||
// boost::shared_ptr<...>::element_type
|
|
||||||
if (type.startsWith(QLatin1String("boost::shared_ptr<"))
|
|
||||||
&& type.endsWith(QLatin1String(">::element_type")))
|
|
||||||
type = type.mid(18, type.size() - 33);
|
|
||||||
|
|
||||||
// std::shared_ptr<...>::element_type
|
|
||||||
if (type.startsWith(QLatin1String("std::shared_ptr<"))
|
|
||||||
&& type.endsWith(QLatin1String(">::element_type")))
|
|
||||||
type = type.mid(16, type.size() - 31);
|
|
||||||
|
|
||||||
// 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"));
|
|
||||||
|
|
||||||
|
|
||||||
// std::__1::hash_node<int, void *>::value_type -> int
|
|
||||||
if (isLibCpp) {
|
|
||||||
//QRegExp hashNodeRE(QLatin1String("std::__hash_node<([^<>]*),\\s*void\\s*@>::value_type"));
|
|
||||||
QRegExp hashNodeRE(QLatin1String("std::__hash_node<([^<>]*),\\s*void\\s*@>::value_type"));
|
|
||||||
QTC_ASSERT(hashNodeRE.isValid(), return typeIn);
|
|
||||||
if (hashNodeRE.indexIn(type) != -1)
|
|
||||||
type.replace(hashNodeRE.cap(0), hashNodeRE.cap(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Anything with a std::allocator
|
|
||||||
int start = type.indexOf(QLatin1String("std::allocator<"));
|
|
||||||
if (start != -1) {
|
|
||||||
// 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::hash<char>
|
|
||||||
QRegExp hashCharRE(QString::fromLatin1("hash<char, std::char_traits<char>, ?%1\\s*>").arg(allocEsc));
|
|
||||||
hashCharRE.setMinimal(true);
|
|
||||||
QTC_ASSERT(hashCharRE.isValid(), return typeIn);
|
|
||||||
if (hashCharRE.indexIn(type) != -1)
|
|
||||||
type.replace(hashCharRE.cap(0), QString::fromLatin1("hash<char>"));
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
if (isLibCpp) {
|
|
||||||
QRegExp mapRE2(QString::fromLatin1("unordered_map<std::string, ?%1, "
|
|
||||||
"?std::hash<char>, ?std::equal_to<std::string>, ?%2\\s*>")
|
|
||||||
.arg(valueEsc, allocEsc));
|
|
||||||
mapRE2.setMinimal(true);
|
|
||||||
QTC_ASSERT(mapRE2.isValid(), return typeIn);
|
|
||||||
if (mapRE2.indexIn(type) != -1)
|
|
||||||
type.replace(mapRE2.cap(0), QString::fromLatin1("unordered_map<std::string, %2>").arg(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // with std::allocator
|
|
||||||
}
|
|
||||||
type.replace(QLatin1Char('@'), QLatin1Char('*'));
|
|
||||||
type.replace(QLatin1String(" >"), QLatin1String(">"));
|
|
||||||
qDebug() << "TYPE: " << type;
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -221,11 +221,6 @@ enum DebuggerDisplay {
|
|||||||
// Decode string data as returned by the dumper helpers.
|
// Decode string data as returned by the dumper helpers.
|
||||||
QString decodeData(const QByteArray &baIn, int encoding);
|
QString decodeData(const QByteArray &baIn, int encoding);
|
||||||
|
|
||||||
// Simplify complicated STL template types, such as
|
|
||||||
// 'std::basic_string<char,std::char_traits<char>,std::allocator<char> > '->
|
|
||||||
// 'std::string'.
|
|
||||||
QString simplifySTLType(const QString &typeIn);
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
301
src/plugins/debugger/simplifytype.cpp
Normal file
301
src/plugins/debugger/simplifytype.cpp
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, 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, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "simplifytype.h"
|
||||||
|
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
|
#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 {
|
||||||
|
|
||||||
|
// 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 simplifyType(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);
|
||||||
|
|
||||||
|
const bool isLibCpp = type.contains(QLatin1String("std::__1"));
|
||||||
|
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) {
|
||||||
|
// boost::shared_ptr<...>::element_type
|
||||||
|
if (type.startsWith(QLatin1String("boost::shared_ptr<"))
|
||||||
|
&& type.endsWith(QLatin1String(">::element_type")))
|
||||||
|
type = type.mid(18, type.size() - 33);
|
||||||
|
|
||||||
|
// std::shared_ptr<...>::element_type
|
||||||
|
if (type.startsWith(QLatin1String("std::shared_ptr<"))
|
||||||
|
&& type.endsWith(QLatin1String(">::element_type")))
|
||||||
|
type = type.mid(16, type.size() - 31);
|
||||||
|
|
||||||
|
// 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"));
|
||||||
|
|
||||||
|
|
||||||
|
// std::__1::hash_node<int, void *>::value_type -> int
|
||||||
|
if (isLibCpp) {
|
||||||
|
//QRegExp hashNodeRE(QLatin1String("std::__hash_node<([^<>]*),\\s*void\\s*@>::value_type"));
|
||||||
|
QRegExp hashNodeRE(QLatin1String("std::__hash_node<([^<>]*),\\s*void\\s*@>::value_type"));
|
||||||
|
QTC_ASSERT(hashNodeRE.isValid(), return typeIn);
|
||||||
|
if (hashNodeRE.indexIn(type) != -1)
|
||||||
|
type.replace(hashNodeRE.cap(0), hashNodeRE.cap(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anything with a std::allocator
|
||||||
|
int start = type.indexOf(QLatin1String("std::allocator<"));
|
||||||
|
if (start != -1) {
|
||||||
|
// 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::hash<char>
|
||||||
|
QRegExp hashCharRE(QString::fromLatin1("hash<char, std::char_traits<char>, ?%1\\s*>").arg(allocEsc));
|
||||||
|
hashCharRE.setMinimal(true);
|
||||||
|
QTC_ASSERT(hashCharRE.isValid(), return typeIn);
|
||||||
|
if (hashCharRE.indexIn(type) != -1)
|
||||||
|
type.replace(hashCharRE.cap(0), QString::fromLatin1("hash<char>"));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
if (isLibCpp) {
|
||||||
|
QRegExp mapRE2(QString::fromLatin1("unordered_map<std::string, ?%1, "
|
||||||
|
"?std::hash<char>, ?std::equal_to<std::string>, ?%2\\s*>")
|
||||||
|
.arg(valueEsc, allocEsc));
|
||||||
|
mapRE2.setMinimal(true);
|
||||||
|
QTC_ASSERT(mapRE2.isValid(), return typeIn);
|
||||||
|
if (mapRE2.indexIn(type) != -1)
|
||||||
|
type.replace(mapRE2.cap(0), QString::fromLatin1("unordered_map<std::string, %2>").arg(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // with std::allocator
|
||||||
|
}
|
||||||
|
type.replace(QLatin1Char('@'), QLatin1Char('*'));
|
||||||
|
type.replace(QLatin1String(" >"), QLatin1String(">"));
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
47
src/plugins/debugger/simplifytype.h
Normal file
47
src/plugins/debugger/simplifytype.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, 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, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DEBUGGER_SIMPLIFY_TYPE_H
|
||||||
|
#define DEBUGGER_SIMPLIFY_TYPE_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
// Simplify complicated STL template types, such as
|
||||||
|
// 'std::basic_string<char,std::char_traits<char>,std::allocator<char> > '->
|
||||||
|
// 'std::string'.
|
||||||
|
QString simplifyType(const QString &typeIn);
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DEBUGGER_SIMPLIFY_TYPE_H
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "debuggerengine.h"
|
#include "debuggerengine.h"
|
||||||
#include "debuggerinternalconstants.h"
|
#include "debuggerinternalconstants.h"
|
||||||
#include "debuggerprotocol.h"
|
#include "debuggerprotocol.h"
|
||||||
|
#include "simplifytype.h"
|
||||||
#include "imageviewer.h"
|
#include "imageviewer.h"
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
|
|
||||||
@@ -477,7 +478,7 @@ static QString niceTypeHelper(const QByteArray &typeIn)
|
|||||||
const Cache::const_iterator it = cache.constFind(typeIn);
|
const Cache::const_iterator it = cache.constFind(typeIn);
|
||||||
if (it != cache.constEnd())
|
if (it != cache.constEnd())
|
||||||
return it.value();
|
return it.value();
|
||||||
const QString simplified = simplifySTLType(QLatin1String(typeIn));
|
const QString simplified = simplifyType(QLatin1String(typeIn));
|
||||||
cache.insert(typeIn, simplified); // For simplicity, also cache unmodified types
|
cache.insert(typeIn, simplified); // For simplicity, also cache unmodified types
|
||||||
return simplified;
|
return simplified;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ include($$IDE_SOURCE_TREE/src/rpath.pri)
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$DEBUGGERDIR/debuggerprotocol.cpp \
|
$$DEBUGGERDIR/debuggerprotocol.cpp \
|
||||||
|
$$DEBUGGERDIR/simplifytype.cpp \
|
||||||
$$DEBUGGERDIR/watchdata.cpp \
|
$$DEBUGGERDIR/watchdata.cpp \
|
||||||
$$DEBUGGERDIR/watchutils.cpp \
|
$$DEBUGGERDIR/watchutils.cpp \
|
||||||
tst_dumpers.cpp
|
tst_dumpers.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$DEBUGGERDIR/debuggerprotocol.h \
|
$$DEBUGGERDIR/debuggerprotocol.h \
|
||||||
|
$$DEBUGGERDIR/simplifytype.h \
|
||||||
$$DEBUGGERDIR/watchdata.h \
|
$$DEBUGGERDIR/watchdata.h \
|
||||||
$$DEBUGGERDIR/watchutils.h \
|
$$DEBUGGERDIR/watchutils.h \
|
||||||
temporarydir.h
|
temporarydir.h
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ INCLUDEPATH += $$DEBUGGERDIR
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
tst_simplifytypes.cpp \
|
tst_simplifytypes.cpp \
|
||||||
$$DEBUGGERDIR/debuggerprotocol.cpp \
|
$$DEBUGGERDIR/simplifytype.cpp \
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "debuggerprotocol.h"
|
#include "debuggerprotocol.h"
|
||||||
|
#include "simplifytype.h"
|
||||||
#include "watchdata.h"
|
#include "watchdata.h"
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
|
|
||||||
@@ -348,7 +349,7 @@ struct Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QByteArray actualType =
|
QByteArray actualType =
|
||||||
simplifySTLType(QString::fromLatin1(actualType0)).toLatin1();
|
simplifyType(QString::fromLatin1(actualType0)).toLatin1();
|
||||||
actualType.replace(' ', "");
|
actualType.replace(' ', "");
|
||||||
actualType.replace("const", "");
|
actualType.replace("const", "");
|
||||||
QByteArray expectedType = type;
|
QByteArray expectedType = type;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "debuggerprotocol.h"
|
#include "simplifytype.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
@@ -154,7 +154,7 @@ void SimplifyTypesTest::test()
|
|||||||
{
|
{
|
||||||
QFETCH(QString, input);
|
QFETCH(QString, input);
|
||||||
QFETCH(QString, expected);
|
QFETCH(QString, expected);
|
||||||
const QString output = simplifySTLType(input);
|
const QString output = simplifyType(input);
|
||||||
QCOMPARE(output, expected);
|
QCOMPARE(output, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user