forked from qt-creator/qt-creator
Debugger: Add dumper for Nim's string and sequence types
... and make the auto test infrastructure able to handle a test. To pass the test, some Nim compiler must be accessible. Change-Id: I707aa72c0f3a2ea35c7131cba490cafb41617f6c Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -1015,7 +1015,8 @@ class DumperBase:
|
|||||||
if arrayByteSize == 0:
|
if arrayByteSize == 0:
|
||||||
# This should not happen. But it does, see QTCREATORBUG-14755.
|
# This should not happen. But it does, see QTCREATORBUG-14755.
|
||||||
# GDB/GCC produce sizeof == 0 for QProcess arr[3]
|
# GDB/GCC produce sizeof == 0 for QProcess arr[3]
|
||||||
s = str(value.type)
|
# And in the Nim string dumper.
|
||||||
|
s = value.type.name
|
||||||
itemCount = s[s.find('[')+1:s.find(']')]
|
itemCount = s[s.find('[')+1:s.find(']')]
|
||||||
if not itemCount:
|
if not itemCount:
|
||||||
itemCount = '100'
|
itemCount = '100'
|
||||||
|
@@ -161,6 +161,25 @@ def qdump__Eigen__Matrix(d, value):
|
|||||||
s = s + 1
|
s = s + 1
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Nim
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def qdump__NimStringDesc(d, value):
|
||||||
|
size, reserved = value.split('pp')
|
||||||
|
data = value.address() + 2 * d.ptrSize()
|
||||||
|
d.putCharArrayHelper(data, size, d.createType('char'), 'utf8')
|
||||||
|
|
||||||
|
def qdump__NimGenericSequence__(d, value, regex = "^TY[\d]+$"):
|
||||||
|
size, reserved = d.split('pp', value)
|
||||||
|
data = value.address() + 2 * d.ptrSize()
|
||||||
|
typeobj = value["data"].type.dereference()
|
||||||
|
d.putItemCount(size)
|
||||||
|
d.putArrayData(data, size, typeobj)
|
||||||
|
d.putBetterType("%s (%s[%s])" % (value.type.name, typeobj.name, size))
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
#
|
#
|
||||||
# D
|
# D
|
||||||
|
@@ -646,33 +646,11 @@ struct NetworkProfile {};
|
|||||||
struct QmlProfile {};
|
struct QmlProfile {};
|
||||||
struct QmlPrivateProfile {};
|
struct QmlPrivateProfile {};
|
||||||
|
|
||||||
|
struct NimProfile {};
|
||||||
|
|
||||||
struct BigArrayProfile {};
|
struct BigArrayProfile {};
|
||||||
|
|
||||||
struct DataBase
|
class Data
|
||||||
{
|
|
||||||
DataBase()
|
|
||||||
: useQt(false), useQHash(false),
|
|
||||||
forceC(false), engines(AllEngines),
|
|
||||||
glibcxxDebug(false), useDebugImage(false),
|
|
||||||
bigArray(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
mutable bool useQt;
|
|
||||||
mutable bool useQHash;
|
|
||||||
mutable bool forceC;
|
|
||||||
mutable int engines;
|
|
||||||
mutable bool glibcxxDebug;
|
|
||||||
mutable bool useDebugImage;
|
|
||||||
mutable bool bigArray;
|
|
||||||
mutable GdbVersion neededGdbVersion; // DEC. 70600
|
|
||||||
mutable LldbVersion neededLldbVersion;
|
|
||||||
mutable QtVersion neededQtVersion; // HEX! 0x50300
|
|
||||||
mutable GccVersion neededGccVersion; // DEC. 40702 for 4.7.2
|
|
||||||
mutable ClangVersion neededClangVersion; // DEC.
|
|
||||||
mutable BoostVersion neededBoostVersion; // DEC. 105400 for 1.54.0
|
|
||||||
};
|
|
||||||
|
|
||||||
class Data : public DataBase
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Data() {}
|
Data() {}
|
||||||
@@ -854,14 +832,37 @@ public:
|
|||||||
|
|
||||||
const Data &operator+(const ForceC &) const
|
const Data &operator+(const ForceC &) const
|
||||||
{
|
{
|
||||||
forceC = true;
|
mainFile = "main.c";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
mutable bool useQt = false;
|
||||||
|
mutable bool useQHash = false;
|
||||||
|
mutable int engines = AllEngines;
|
||||||
|
mutable int skipLevels = 0; // Levels to go 'up' before dumping variables.
|
||||||
|
mutable bool glibcxxDebug = false;
|
||||||
|
mutable bool useDebugImage = false;
|
||||||
|
mutable bool bigArray = false;
|
||||||
|
mutable GdbVersion neededGdbVersion; // DEC. 70600
|
||||||
|
mutable LldbVersion neededLldbVersion;
|
||||||
|
mutable QtVersion neededQtVersion; // HEX! 0x50300
|
||||||
|
mutable GccVersion neededGccVersion; // DEC. 40702 for 4.7.2
|
||||||
|
mutable ClangVersion neededClangVersion; // DEC.
|
||||||
|
mutable BoostVersion neededBoostVersion; // DEC. 105400 for 1.54.0
|
||||||
|
|
||||||
|
mutable QString configTest;
|
||||||
|
|
||||||
|
mutable QString allProfile; // Overrides anything below if not empty.
|
||||||
|
mutable QString allCode; // Overrides anything below if not empty.
|
||||||
|
|
||||||
|
mutable QString mainFile = "main.cpp";
|
||||||
|
mutable QString projectFile = "doit.pro";
|
||||||
|
|
||||||
mutable QString profileExtra;
|
mutable QString profileExtra;
|
||||||
mutable QString includes;
|
mutable QString includes;
|
||||||
mutable QString code;
|
mutable QString code;
|
||||||
|
|
||||||
mutable QList<Check> checks;
|
mutable QList<Check> checks;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1150,28 +1151,42 @@ void tst_Dumpers::dumper()
|
|||||||
+ QByteArray::number(data.neededGccVersion.max));
|
+ QByteArray::number(data.neededGccVersion.max));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mainFile = data.forceC ? "main.c" : "main.cpp";
|
if (!data.configTest.isEmpty()) {
|
||||||
|
QProcess configTest;
|
||||||
|
configTest.start(data.configTest);
|
||||||
|
QVERIFY(configTest.waitForFinished());
|
||||||
|
output = configTest.readAllStandardOutput();
|
||||||
|
error = configTest.readAllStandardError();
|
||||||
|
if (configTest.exitCode()) {
|
||||||
|
MSKIP_SINGLE("Configure test failed: '"
|
||||||
|
+ data.configTest.toUtf8() + "' " + output + ' ' + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QFile proFile(t->buildPath + QLatin1String("/doit.pro"));
|
QFile proFile(t->buildPath + '/' + data.projectFile);
|
||||||
QVERIFY(proFile.open(QIODevice::ReadWrite));
|
QVERIFY(proFile.open(QIODevice::ReadWrite));
|
||||||
proFile.write("SOURCES = ");
|
if (data.allProfile.isEmpty()) {
|
||||||
proFile.write(mainFile);
|
proFile.write("SOURCES = ");
|
||||||
proFile.write("\nTARGET = doit\n");
|
proFile.write(data.mainFile.toUtf8());
|
||||||
proFile.write("\nCONFIG -= app_bundle\n");
|
proFile.write("\nTARGET = doit\n");
|
||||||
proFile.write("\nCONFIG -= release\n");
|
proFile.write("\nCONFIG -= app_bundle\n");
|
||||||
proFile.write("\nCONFIG += debug\n");
|
proFile.write("\nCONFIG -= release\n");
|
||||||
if (data.useQt)
|
proFile.write("\nCONFIG += debug\n");
|
||||||
proFile.write("QT -= widgets gui\n");
|
if (data.useQt)
|
||||||
else
|
proFile.write("QT -= widgets gui\n");
|
||||||
proFile.write("CONFIG -= QT\n");
|
else
|
||||||
if (m_useGLibCxxDebug)
|
proFile.write("CONFIG -= QT\n");
|
||||||
proFile.write("DEFINES += _GLIBCXX_DEBUG\n");
|
if (m_useGLibCxxDebug)
|
||||||
if (m_debuggerEngine == GdbEngine && m_debuggerVersion < 70500)
|
proFile.write("DEFINES += _GLIBCXX_DEBUG\n");
|
||||||
proFile.write("QMAKE_CXXFLAGS += -gdwarf-3\n");
|
if (m_debuggerEngine == GdbEngine && m_debuggerVersion < 70500)
|
||||||
proFile.write(data.profileExtra.toUtf8());
|
proFile.write("QMAKE_CXXFLAGS += -gdwarf-3\n");
|
||||||
|
proFile.write(data.profileExtra.toUtf8());
|
||||||
|
} else {
|
||||||
|
proFile.write(data.allProfile.toUtf8());
|
||||||
|
}
|
||||||
proFile.close();
|
proFile.close();
|
||||||
|
|
||||||
QFile source(t->buildPath + QLatin1Char('/') + QLatin1String(mainFile));
|
QFile source(t->buildPath + QLatin1Char('/') + data.mainFile);
|
||||||
QVERIFY(source.open(QIODevice::ReadWrite));
|
QVERIFY(source.open(QIODevice::ReadWrite));
|
||||||
QString fullCode = QString() +
|
QString fullCode = QString() +
|
||||||
"\n\n#if defined(_MSC_VER)" + (data.useQt ?
|
"\n\n#if defined(_MSC_VER)" + (data.useQt ?
|
||||||
@@ -1234,6 +1249,8 @@ void tst_Dumpers::dumper()
|
|||||||
"\n BREAK;"
|
"\n BREAK;"
|
||||||
"\n return 0;"
|
"\n return 0;"
|
||||||
"\n}\n";
|
"\n}\n";
|
||||||
|
if (!data.allCode.isEmpty())
|
||||||
|
fullCode = data.allCode;
|
||||||
source.write(fullCode.toUtf8());
|
source.write(fullCode.toUtf8());
|
||||||
source.close();
|
source.close();
|
||||||
|
|
||||||
@@ -1251,7 +1268,12 @@ void tst_Dumpers::dumper()
|
|||||||
output = qmake.readAllStandardOutput();
|
output = qmake.readAllStandardOutput();
|
||||||
error = qmake.readAllStandardError();
|
error = qmake.readAllStandardError();
|
||||||
//qDebug() << "stdout: " << output;
|
//qDebug() << "stdout: " << output;
|
||||||
if (!error.isEmpty()) { qDebug() << error; QVERIFY(false); }
|
|
||||||
|
if (data.allProfile.isEmpty()) { // Nim...
|
||||||
|
if (!error.isEmpty()) {
|
||||||
|
qDebug() << error; QVERIFY(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QProcess make;
|
QProcess make;
|
||||||
make.setWorkingDirectory(t->buildPath);
|
make.setWorkingDirectory(t->buildPath);
|
||||||
@@ -1267,7 +1289,7 @@ void tst_Dumpers::dumper()
|
|||||||
qDebug() << "\n------------------ CODE --------------------";
|
qDebug() << "\n------------------ CODE --------------------";
|
||||||
qDebug() << fullCode;
|
qDebug() << fullCode;
|
||||||
qDebug() << "\n------------------ CODE --------------------";
|
qDebug() << "\n------------------ CODE --------------------";
|
||||||
qDebug() << ".pro: " << qPrintable(proFile.fileName());
|
qDebug() << "Project file: " << qPrintable(proFile.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray dumperDir = DUMPERDIR;
|
QByteArray dumperDir = DUMPERDIR;
|
||||||
@@ -1321,6 +1343,7 @@ void tst_Dumpers::dumper()
|
|||||||
"python from gdbbridge import *\n"
|
"python from gdbbridge import *\n"
|
||||||
"python theDumper.setupDumpers()\n"
|
"python theDumper.setupDumpers()\n"
|
||||||
"run " + nograb + "\n"
|
"run " + nograb + "\n"
|
||||||
|
"up " + QString::number(data.skipLevels) + "\n"
|
||||||
"python theDumper.fetchVariables({"
|
"python theDumper.fetchVariables({"
|
||||||
"'token':2,'fancy':1,'forcens':1,"
|
"'token':2,'fancy':1,'forcens':1,"
|
||||||
"'autoderef':1,'dyntype':1,'passexceptions':1,"
|
"'autoderef':1,'dyntype':1,'passexceptions':1,"
|
||||||
@@ -6207,6 +6230,54 @@ void tst_Dumpers::dumper_data()
|
|||||||
+ Check("v14.2", "[2]", "116", "@QChar")
|
+ Check("v14.2", "[2]", "116", "@QChar")
|
||||||
+ Check("v15", "\"utf16\"", "@QJSValue (QString)")
|
+ Check("v15", "\"utf16\"", "@QJSValue (QString)")
|
||||||
+ Check("v15.1", "[1]", "116", "@QChar");
|
+ Check("v15.1", "[1]", "116", "@QChar");
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
// Hint: To open a failing test in Creator, do:
|
||||||
|
// touch qt_tst_dumpers_Nim_.../dummy.nimproject
|
||||||
|
// qtcreator qt_tst_dumpers_Nim_*/dummy.nimproject
|
||||||
|
Data nimData;
|
||||||
|
nimData.configTest = "which nim";
|
||||||
|
nimData.allProfile =
|
||||||
|
"CONFIG -= qt\n"
|
||||||
|
"# Prevents linking\n"
|
||||||
|
"TARGET=\n"
|
||||||
|
"# Overwrites qmake-generated 'all' target.\n"
|
||||||
|
"all.commands = nim c --debugInfo --lineDir:on --out:doit main.nim\n"
|
||||||
|
"all.depends = main.nim\n"
|
||||||
|
"all.CONFIG = phony\n\n"
|
||||||
|
"QMAKE_EXTRA_TARGETS += all\n";
|
||||||
|
nimData.allCode =
|
||||||
|
"type Mirror = ref object\n"
|
||||||
|
" tag:int\n"
|
||||||
|
" other:array[0..1, Mirror]\n\n"
|
||||||
|
"proc mainProc =\n"
|
||||||
|
" var name: string = \"Hello World\"\n"
|
||||||
|
" var i: int = 43\n"
|
||||||
|
" var x: seq[int]\n"
|
||||||
|
" x = @[1, 2, 3, 4, 5, 6]\n\n"
|
||||||
|
" # Crash it.\n"
|
||||||
|
" var m1 = Mirror(tag:1)\n"
|
||||||
|
" var m2 = Mirror(tag:2)\n"
|
||||||
|
" var m3 = Mirror(tag:3)\n\n"
|
||||||
|
" m1.other[0] = m2; m1.other[1] = m3\n"
|
||||||
|
" m2.other[0] = m1; m2.other[1] = m3\n"
|
||||||
|
" m3.other[0] = m1; m3.other[1] = m2\n\n"
|
||||||
|
" for i in 1..30000:\n"
|
||||||
|
//" echo i\n"
|
||||||
|
" var mx : Mirror; mx.deepCopy(m1)\n"
|
||||||
|
" m1 = mx\n\n"
|
||||||
|
"if isMainModule:\n"
|
||||||
|
" mainProc()\n";
|
||||||
|
nimData.mainFile = "main.nim";
|
||||||
|
nimData.skipLevels = 15;
|
||||||
|
|
||||||
|
QTest::newRow("Nim")
|
||||||
|
<< nimData
|
||||||
|
+ GdbEngine
|
||||||
|
+ Check("name", "\"Hello World\"", "NimStringDesc")
|
||||||
|
+ Check("x", "<6 items>", Pattern("TY.*NI.6..")) // Something like "TY95019 (NI[6])"
|
||||||
|
+ Check("x.2", "[2]", "3", "NI");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
Reference in New Issue
Block a user