From e234bbd88b654965e28d84c5becf07d557726fb4 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 4 Apr 2016 21:51:31 +0200 Subject: [PATCH] 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 --- share/qtcreator/debugger/dumper.py | 3 +- share/qtcreator/debugger/misctypes.py | 19 +++ tests/auto/debugger/tst_dumpers.cpp | 163 ++++++++++++++++++-------- 3 files changed, 138 insertions(+), 47 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index cf08c1305f3..5608113e0af 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -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' diff --git a/share/qtcreator/debugger/misctypes.py b/share/qtcreator/debugger/misctypes.py index e62c1cbc53b..be40d32fe40 100644 --- a/share/qtcreator/debugger/misctypes.py +++ b/share/qtcreator/debugger/misctypes.py @@ -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 diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 3f44fb4c095..ee4e556094a 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -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 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[])