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:
|
||||
# This should not happen. But it does, see QTCREATORBUG-14755.
|
||||
# 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(']')]
|
||||
if not itemCount:
|
||||
itemCount = '100'
|
||||
|
@@ -161,6 +161,25 @@ def qdump__Eigen__Matrix(d, value):
|
||||
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
|
||||
|
@@ -646,33 +646,11 @@ struct NetworkProfile {};
|
||||
struct QmlProfile {};
|
||||
struct QmlPrivateProfile {};
|
||||
|
||||
struct NimProfile {};
|
||||
|
||||
struct BigArrayProfile {};
|
||||
|
||||
struct DataBase
|
||||
{
|
||||
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
|
||||
class Data
|
||||
{
|
||||
public:
|
||||
Data() {}
|
||||
@@ -854,14 +832,37 @@ public:
|
||||
|
||||
const Data &operator+(const ForceC &) const
|
||||
{
|
||||
forceC = true;
|
||||
mainFile = "main.c";
|
||||
return *this;
|
||||
}
|
||||
|
||||
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 includes;
|
||||
mutable QString code;
|
||||
|
||||
mutable QList<Check> checks;
|
||||
};
|
||||
|
||||
@@ -1150,28 +1151,42 @@ void tst_Dumpers::dumper()
|
||||
+ 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));
|
||||
proFile.write("SOURCES = ");
|
||||
proFile.write(mainFile);
|
||||
proFile.write("\nTARGET = doit\n");
|
||||
proFile.write("\nCONFIG -= app_bundle\n");
|
||||
proFile.write("\nCONFIG -= release\n");
|
||||
proFile.write("\nCONFIG += debug\n");
|
||||
if (data.useQt)
|
||||
proFile.write("QT -= widgets gui\n");
|
||||
else
|
||||
proFile.write("CONFIG -= QT\n");
|
||||
if (m_useGLibCxxDebug)
|
||||
proFile.write("DEFINES += _GLIBCXX_DEBUG\n");
|
||||
if (m_debuggerEngine == GdbEngine && m_debuggerVersion < 70500)
|
||||
proFile.write("QMAKE_CXXFLAGS += -gdwarf-3\n");
|
||||
proFile.write(data.profileExtra.toUtf8());
|
||||
if (data.allProfile.isEmpty()) {
|
||||
proFile.write("SOURCES = ");
|
||||
proFile.write(data.mainFile.toUtf8());
|
||||
proFile.write("\nTARGET = doit\n");
|
||||
proFile.write("\nCONFIG -= app_bundle\n");
|
||||
proFile.write("\nCONFIG -= release\n");
|
||||
proFile.write("\nCONFIG += debug\n");
|
||||
if (data.useQt)
|
||||
proFile.write("QT -= widgets gui\n");
|
||||
else
|
||||
proFile.write("CONFIG -= QT\n");
|
||||
if (m_useGLibCxxDebug)
|
||||
proFile.write("DEFINES += _GLIBCXX_DEBUG\n");
|
||||
if (m_debuggerEngine == GdbEngine && m_debuggerVersion < 70500)
|
||||
proFile.write("QMAKE_CXXFLAGS += -gdwarf-3\n");
|
||||
proFile.write(data.profileExtra.toUtf8());
|
||||
} else {
|
||||
proFile.write(data.allProfile.toUtf8());
|
||||
}
|
||||
proFile.close();
|
||||
|
||||
QFile source(t->buildPath + QLatin1Char('/') + QLatin1String(mainFile));
|
||||
QFile source(t->buildPath + QLatin1Char('/') + data.mainFile);
|
||||
QVERIFY(source.open(QIODevice::ReadWrite));
|
||||
QString fullCode = QString() +
|
||||
"\n\n#if defined(_MSC_VER)" + (data.useQt ?
|
||||
@@ -1234,6 +1249,8 @@ void tst_Dumpers::dumper()
|
||||
"\n BREAK;"
|
||||
"\n return 0;"
|
||||
"\n}\n";
|
||||
if (!data.allCode.isEmpty())
|
||||
fullCode = data.allCode;
|
||||
source.write(fullCode.toUtf8());
|
||||
source.close();
|
||||
|
||||
@@ -1251,7 +1268,12 @@ void tst_Dumpers::dumper()
|
||||
output = qmake.readAllStandardOutput();
|
||||
error = qmake.readAllStandardError();
|
||||
//qDebug() << "stdout: " << output;
|
||||
if (!error.isEmpty()) { qDebug() << error; QVERIFY(false); }
|
||||
|
||||
if (data.allProfile.isEmpty()) { // Nim...
|
||||
if (!error.isEmpty()) {
|
||||
qDebug() << error; QVERIFY(false);
|
||||
}
|
||||
}
|
||||
|
||||
QProcess make;
|
||||
make.setWorkingDirectory(t->buildPath);
|
||||
@@ -1267,7 +1289,7 @@ void tst_Dumpers::dumper()
|
||||
qDebug() << "\n------------------ CODE --------------------";
|
||||
qDebug() << fullCode;
|
||||
qDebug() << "\n------------------ CODE --------------------";
|
||||
qDebug() << ".pro: " << qPrintable(proFile.fileName());
|
||||
qDebug() << "Project file: " << qPrintable(proFile.fileName());
|
||||
}
|
||||
|
||||
QByteArray dumperDir = DUMPERDIR;
|
||||
@@ -1321,6 +1343,7 @@ void tst_Dumpers::dumper()
|
||||
"python from gdbbridge import *\n"
|
||||
"python theDumper.setupDumpers()\n"
|
||||
"run " + nograb + "\n"
|
||||
"up " + QString::number(data.skipLevels) + "\n"
|
||||
"python theDumper.fetchVariables({"
|
||||
"'token':2,'fancy':1,'forcens':1,"
|
||||
"'autoderef':1,'dyntype':1,'passexceptions':1,"
|
||||
@@ -6207,6 +6230,54 @@ void tst_Dumpers::dumper_data()
|
||||
+ Check("v14.2", "[2]", "116", "@QChar")
|
||||
+ Check("v15", "\"utf16\"", "@QJSValue (QString)")
|
||||
+ 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[])
|
||||
|
Reference in New Issue
Block a user